From f0f4eabdda380c912b4e3078ac2eddd7c7643edb Mon Sep 17 00:00:00 2001 From: Jaime Torrealba Date: Mon, 25 Mar 2024 15:52:42 +0000 Subject: [PATCH] feat(app): Add holographic material to cientos --- docs/.vitepress/config.ts | 1 + .../components/HolographicMaterialDemo.vue | 36 +++ docs/guide/materials/holographic-material.md | 55 ++++ .../materials/HolographicMaterialDemo.vue | 51 ++++ playground/src/router/routes/materials.ts | 5 + .../materials/holographicMaterial/index.vue | 69 +++++ .../materials/holographicMaterial/material.ts | 281 ++++++++++++++++++ src/core/materials/index.ts | 3 +- 8 files changed, 500 insertions(+), 1 deletion(-) create mode 100644 docs/.vitepress/theme/components/HolographicMaterialDemo.vue create mode 100644 docs/guide/materials/holographic-material.md create mode 100644 playground/src/pages/materials/HolographicMaterialDemo.vue create mode 100644 src/core/materials/holographicMaterial/index.vue create mode 100644 src/core/materials/holographicMaterial/material.ts diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 24267392..ce8a91e3 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -98,6 +98,7 @@ export default defineConfig({ { text: 'WobbleMaterial', link: '/guide/materials/wobble-material' }, { text: 'MeshGlassMaterial', link: '/guide/materials/glass-material' }, { text: 'CustomShaderMaterial', link: '/guide/materials/custom-shader-material' }, + { text: 'HolographicMaterial', link: '/guide/materials/holographic-material' }, ], }, { diff --git a/docs/.vitepress/theme/components/HolographicMaterialDemo.vue b/docs/.vitepress/theme/components/HolographicMaterialDemo.vue new file mode 100644 index 00000000..5f5503bb --- /dev/null +++ b/docs/.vitepress/theme/components/HolographicMaterialDemo.vue @@ -0,0 +1,36 @@ + + + diff --git a/docs/guide/materials/holographic-material.md b/docs/guide/materials/holographic-material.md new file mode 100644 index 00000000..bc952795 --- /dev/null +++ b/docs/guide/materials/holographic-material.md @@ -0,0 +1,55 @@ +# HolographicMaterial + + + + + +A simple to use holographic material for threejs + +Dive into a world of mesmerizing holographic wonders with the HolographicMaterial for vanilla three.js. This enchanting three.js material brings your virtual reality experiences to life, infusing them with a burst of vibrant colors, dynamic scanlines, and a touch of futuristic brilliance. + +While this material operates independently of any post-processing, it achieves an enhanced visual appeal when coupled with bloom effects. The utilization of bloom proves particularly effective in rendering a captivating glow effect, especially in areas where overexposure is prevalent. + +:::info +This is an integration of the Anderson Mancini [threejs-vanilla-holographic-material](https://github.com/ektogamat/threejs-vanilla-holographic-material). All credits for him. +::: + +## Usage + +```vue{3,10} + + +``` + +### You can also replace the material of an existing mesh like this: + +<<< @/.vitepress/theme/components/GlassMaterialDemo.vue{3,9-12} + +## props + +| Prop | Description | Type | default | +| :--------------------- | :------------------------------------------------------------------ | --------------------------------------------------- | --------- | +| **fresnelAmount** | Controls the value of the Fresnel effect. Ranges from 0.0 to 1.0. | `Number` | 0.45 | +| **fresnelOpacity** | Controls the opacity of the Fresnel effect. Ranges from 0.0 to 1.0. | `Number` | 1.0 | +| **scanlineSize** | Controls the size of the scanlines. Ranges from 1 to 15. | `Number` | 8.0 | +| **hologramBrightness** | Controls the brightness of the hologram. Ranges from 0.0 to 2.0. | `Number` | 1.2 | +| **signalSpeed** | Controls the speed of the signal effect. Ranges from 0.0 to 2.0. | `Number` | 0.45 | +| **hologramColor** | Specifies the color of the hologram. | `String` | "#00d5ff" | +| **enableBlinking** | Enables or disables the blinking effect. | `Boolean` | true | +| **hologramOpacity** | Specifies the opacity of the hologram. | `Number` | 1.0 | +| **enableBlinking** | Enables or disables the blinking effect. | `Boolean` | true | +| **blinkFresnelOnly** | Enables or disables the blinking effect for the Fresnel only. | `Boolean` | true | +| **enableAdditive** | Enables or disables the Additive Blend Mode. | `Boolean` | true | +| **side** | Specifies side for the material, as String. | `THREE.FrontSide, THREE.BackSide, THREE.DoubleSide` | FrontSide | diff --git a/playground/src/pages/materials/HolographicMaterialDemo.vue b/playground/src/pages/materials/HolographicMaterialDemo.vue new file mode 100644 index 00000000..181f36bc --- /dev/null +++ b/playground/src/pages/materials/HolographicMaterialDemo.vue @@ -0,0 +1,51 @@ + + + diff --git a/playground/src/router/routes/materials.ts b/playground/src/router/routes/materials.ts index 693f7406..5a499e7a 100644 --- a/playground/src/router/routes/materials.ts +++ b/playground/src/router/routes/materials.ts @@ -19,4 +19,9 @@ export const materialsRoutes = [ name: 'ReflectionMaterial', component: () => import('../../pages/materials/ReflectionMaterial.vue'), }, + { + path: '/materials/holographic-material', + name: 'HolographicMaterial', + component: () => import('../../pages/materials/HolographicMaterialDemo.vue'), + }, ] diff --git a/src/core/materials/holographicMaterial/index.vue b/src/core/materials/holographicMaterial/index.vue new file mode 100644 index 00000000..a2642ef0 --- /dev/null +++ b/src/core/materials/holographicMaterial/index.vue @@ -0,0 +1,69 @@ + + + diff --git a/src/core/materials/holographicMaterial/material.ts b/src/core/materials/holographicMaterial/material.ts new file mode 100644 index 00000000..089ca799 --- /dev/null +++ b/src/core/materials/holographicMaterial/material.ts @@ -0,0 +1,281 @@ +/** + * Holographic material by Anderson Mancini - Dec 2023. + */ +import { + ShaderMaterial, + Clock, + Uniform, + Color, + NormalBlending, + AdditiveBlending, + FrontSide, + BackSide, + DoubleSide, +} from 'three' +import type { Side, Blending } from 'three' + +// Original author Anderson Mancini - https://github.com/ektogamat/threejs-vanilla-holographic-material + +interface HolographicMaterialParameters { + time?: number + fresnelOpacity?: number + fresnelAmount?: number + scanlineSize?: number + hologramBrightness?: number + signalSpeed?: number + hologramColor?: Color + enableBlinking?: boolean + blinkFresnelOnly?: boolean + hologramOpacity?: number + blendMode?: Blending + side?: Side + depthTest?: boolean +} + +class HolographicMaterial extends ShaderMaterial { + + /** + * Create a HolographicMaterial. + * + * @param {Object} parameters - The parameters to configure the material. + * @param {number} [parameters.time=0.0] - The time uniform representing animation time. + * @param {number} [parameters.fresnelOpacity=1.0] - The opacity for the fresnel effect. + * @param {number} [parameters.fresnelAmount=1.0] - The strength of the fresnel effect. + * @param {number} [parameters.scanlineSize=15.0] - The size of the scanline effect. + * @param {number} [parameters.hologramBrightness=1.0] - The brightness of the hologram. + * @param {number} [parameters.signalSpeed=1.0] - The speed of the signal effect. + * @param {Color} [parameters.hologramColor=new Color('#00d5ff')] - The color of the hologram. + * @param {boolean} [parameters.enableBlinking=true] - Enable/disable blinking effect. + * @param {boolean} [parameters.blinkFresnelOnly=false] - Enable blinking only on the fresnel effect. + * @param {number} [parameters.hologramOpacity=1.0] - The opacity of the hologram. + * @param {number} [parameters.blendMode=NormalBlending] - The blending mode. Use `THREE.NormalBlending` or `THREE.AdditiveBlending`. + * @param {number} [parameters.side=FrontSide] - The rendering side. Use `THREE.FrontSide`, + * `THREE.BackSide`, or `THREE.DoubleSide`. + * @param {Boolean} [parameters.depthTest=true] - Enable or disable depthTest. + */ + + constructor(parameters: HolographicMaterialParameters = {}) { + super() + + this.vertexShader /*GLSL */ + = ` + #define STANDARD + varying vec3 vViewPosition; + #ifdef USE_TRANSMISSION + varying vec3 vWorldPosition; + #endif + + varying vec2 vUv; + varying vec4 vPos; + varying vec3 vNormalW; + varying vec3 vPositionW; + + #include + #include + #include + #include + #include + #include + #include + #include + #include + + void main() { + + #include + #include + #include + + #if defined ( USE_ENVMAP ) || defined ( USE_SKINNING ) + + #include + #include + #include + #include + #include + + #endif + + #include + #include + #include + #include + #include + #include + + #include + #include + #include + + mat4 modelViewProjectionMatrix = projectionMatrix * modelViewMatrix; + + vUv = uv; + vPos = projectionMatrix * modelViewMatrix * vec4( transformed, 1.0 ); + vPositionW = vec3( vec4( transformed, 1.0 ) * modelMatrix); + vNormalW = normalize( vec3( vec4( normal, 0.0 ) * modelMatrix ) ); + + gl_Position = modelViewProjectionMatrix * vec4( transformed, 1.0 ); + + }` + + this.fragmentShader /*GLSL */ + = ` + varying vec2 vUv; + varying vec3 vPositionW; + varying vec4 vPos; + varying vec3 vNormalW; + + uniform float time; + uniform float fresnelOpacity; + uniform float scanlineSize; + uniform float fresnelAmount; + uniform float signalSpeed; + uniform float hologramBrightness; + uniform float hologramOpacity; + uniform bool blinkFresnelOnly; + uniform bool enableBlinking; + uniform vec3 hologramColor; + + float flicker( float amt, float time ) {return clamp( fract( cos( time ) * 43758.5453123 ), amt, 1.0 );} + float random(in float a, in float b) { return fract((cos(dot(vec2(a,b) ,vec2(12.9898,78.233))) * 43758.5453)); } + + void main() { + vec2 vCoords = vPos.xy; + vCoords /= vPos.w; + vCoords = vCoords * 0.5 + 0.5; + vec2 myUV = fract( vCoords ); + + // Defines hologram main color + vec4 hologramColor = vec4(hologramColor, mix(hologramBrightness, vUv.y, 0.5)); + + // Add scanlines + float scanlines = 10.; + scanlines += 20. * sin(time *signalSpeed * 20.8 - myUV.y * 60. * scanlineSize); + scanlines *= smoothstep(1.3 * cos(time *signalSpeed + myUV.y * scanlineSize), 0.78, 0.9); + scanlines *= max(0.25, sin(time *signalSpeed) * 1.0); + + // Scanlines offsets + float r = random(vUv.x, vUv.y); + float g = random(vUv.y * 20.2, vUv.y * .2); + float b = random(vUv.y * .9, vUv.y * .2); + + // Scanline composition + hologramColor += vec4(r*scanlines, b*scanlines, r, 1.0) / 84.; + vec4 scanlineMix = mix(vec4(0.0), hologramColor, hologramColor.a); + + // Calculates fresnel + vec3 viewDirectionW = normalize(cameraPosition - vPositionW); + float fresnelEffect = dot(viewDirectionW, vNormalW) * (1.6 - fresnelOpacity/2.); + fresnelEffect = clamp(fresnelAmount - fresnelEffect, 0., fresnelOpacity); + + // Blinkin effect + //Suggested by Octano - https://x.com/OtanoDesign?s=20 + float blinkValue = enableBlinking ? 0.6 - signalSpeed : 1.0; + float blink = flicker(blinkValue, time * signalSpeed * .02); + + // Final shader composition + vec3 finalColor; + + if(blinkFresnelOnly){ + finalColor = scanlineMix.rgb + fresnelEffect * blink; + }else{ + finalColor = scanlineMix.rgb * blink + fresnelEffect; + } + + gl_FragColor = vec4( finalColor, hologramOpacity); + + }` + + // Set default values or modify existing properties if needed + this.uniforms = { + /** + * The time uniform representing animation time. + * @type {Uniform} + * @default 0.0 + */ + time: new Uniform(0), + + /** + * The opacity for the fresnel effect. + * @type {Uniform} + * @default 1.0 + */ + fresnelOpacity: new Uniform(parameters.fresnelOpacity !== undefined ? parameters.fresnelOpacity : 1.0), + + /** + * The strength of the fresnel effect. + * @type {Uniform} + * @default 1.0 + */ + fresnelAmount: new Uniform(parameters.fresnelAmount !== undefined ? parameters.fresnelAmount : 0.45), + + /** + * The size of the scanline effect. + * @type {Uniform} + * @default 1.0 + */ + scanlineSize: new Uniform(parameters.scanlineSize !== undefined ? parameters.scanlineSize : 8.0), + + /** + * The brightness of the hologram. + * @type {Uniform} + * @default 1.0 + */ + hologramBrightness: new Uniform(parameters.hologramBrightness !== undefined + ? parameters.hologramBrightness + : 1.0), + + /** + * The speed of the signal effect. + * @type {Uniform} + * @default 1.0 + */ + signalSpeed: new Uniform(parameters.signalSpeed !== undefined ? parameters.signalSpeed : 1.0), + + /** + * The color of the hologram. + * @type {Uniform} + * @default new Color(0xFFFFFF) + */ + hologramColor: new Uniform(parameters.hologramColor !== undefined + ? new Color(parameters.hologramColor) + : new Color('#00d5ff')), + + /** + * Enable/disable blinking effect. + * @type {Uniform} + * @default true + */ + enableBlinking: new Uniform(parameters.enableBlinking !== undefined ? parameters.enableBlinking : true), + + /** + * Enable blinking only on the fresnel effect. + * @type {Uniform} + * @default false + */ + blinkFresnelOnly: new Uniform(parameters.blinkFresnelOnly !== undefined ? parameters.blinkFresnelOnly : true), + + /** + * The opacity of the hologram. + * @type {Uniform} + * @default 1.0 + */ + hologramOpacity: new Uniform(parameters.hologramOpacity !== undefined ? parameters.hologramOpacity : 1.0), + } + + this.clock = new Clock() + this.setValues(parameters) + this.depthTest = parameters.depthTest !== undefined ? parameters.depthTest : false + this.blending = parameters.blendMode !== undefined ? parameters.blendMode : AdditiveBlending + this.transparent = true + this.side = parameters.side !== undefined ? parameters.side : FrontSide + + } + + update() { + this.uniforms.time.value = this.clock.getElapsedTime() + } + +} + +export default HolographicMaterial \ No newline at end of file diff --git a/src/core/materials/index.ts b/src/core/materials/index.ts index 6c3678ff..0a07d9c4 100644 --- a/src/core/materials/index.ts +++ b/src/core/materials/index.ts @@ -2,5 +2,6 @@ import MeshWobbleMaterial from './meshWobbleMaterial/index.vue' import MeshGlassMaterial from './meshGlassMaterial/index.vue' import CustomShaderMaterial from './customShaderMaterial/index.vue' import MeshReflectionMaterial from './meshReflectionMaterial/index.vue' +import HolographicMaterial from './holographicMaterial/index.vue' -export { MeshWobbleMaterial, MeshGlassMaterial, CustomShaderMaterial, MeshReflectionMaterial } +export { MeshWobbleMaterial, MeshGlassMaterial, CustomShaderMaterial, MeshReflectionMaterial, HolographicMaterial }