Last active
December 3, 2023 18:03
-
-
Save ektogamat/b149d9154f86c128c9fea52c974dda1a to your computer and use it in GitHub Desktop.
HolographicMaterial for Vanilla Three.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Holographic material by Anderson Mancini - Dec 2023. | |
*/ | |
import { ShaderMaterial, Clock, Uniform, Color, NormalBlending, AdditiveBlending, FrontSide, BackSide, DoubleSide } from 'three'; | |
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 = {}) { | |
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 <common> | |
#include <uv_pars_vertex> | |
#include <envmap_pars_vertex> | |
#include <color_pars_vertex> | |
#include <fog_pars_vertex> | |
#include <morphtarget_pars_vertex> | |
#include <skinning_pars_vertex> | |
#include <logdepthbuf_pars_vertex> | |
#include <clipping_planes_pars_vertex> | |
void main() { | |
#include <uv_vertex> | |
#include <color_vertex> | |
#include <morphcolor_vertex> | |
#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING ) | |
#include <beginnormal_vertex> | |
#include <morphnormal_vertex> | |
#include <skinbase_vertex> | |
#include <skinnormal_vertex> | |
#include <defaultnormal_vertex> | |
#endif | |
#include <begin_vertex> | |
#include <morphtarget_vertex> | |
#include <skinning_vertex> | |
#include <project_vertex> | |
#include <logdepthbuf_vertex> | |
#include <clipping_planes_vertex> | |
#include <worldpos_vertex> | |
#include <envmap_vertex> | |
#include <fog_vertex> | |
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<number>} | |
* @default 0.0 | |
*/ | |
time: new Uniform(0), | |
/** | |
* The opacity for the fresnel effect. | |
* @type {Uniform<number>} | |
* @default 1.0 | |
*/ | |
fresnelOpacity: new Uniform(parameters.fresnelOpacity !== undefined ? parameters.fresnelOpacity : 1.0), | |
/** | |
* The strength of the fresnel effect. | |
* @type {Uniform<number>} | |
* @default 1.0 | |
*/ | |
fresnelAmount: new Uniform(parameters.fresnelAmount !== undefined ? parameters.fresnelAmount : 0.45), | |
/** | |
* The size of the scanline effect. | |
* @type {Uniform<number>} | |
* @default 1.0 | |
*/ | |
scanlineSize: new Uniform(parameters.scanlineSize !== undefined ? parameters.scanlineSize : 8.0), | |
/** | |
* The brightness of the hologram. | |
* @type {Uniform<number>} | |
* @default 1.0 | |
*/ | |
hologramBrightness: new Uniform(parameters.hologramBrightness !== undefined ? parameters.hologramBrightness : 1.0), | |
/** | |
* The speed of the signal effect. | |
* @type {Uniform<number>} | |
* @default 1.0 | |
*/ | |
signalSpeed: new Uniform(parameters.signalSpeed !== undefined ? parameters.signalSpeed : 1.0), | |
/** | |
* The color of the hologram. | |
* @type {Uniform<Color>} | |
* @default new Color(0xFFFFFF) | |
*/ | |
hologramColor: new Uniform(parameters.hologramColor !== undefined ? new Color(parameters.hologramColor) : new Color("#00d5ff")), | |
/** | |
* Enable/disable blinking effect. | |
* @type {Uniform<boolean>} | |
* @default true | |
*/ | |
enableBlinking: new Uniform(parameters.enableBlinking !== undefined ? parameters.enableBlinking : true), | |
/** | |
* Enable blinking only on the fresnel effect. | |
* @type {Uniform<boolean>} | |
* @default false | |
*/ | |
blinkFresnelOnly: new Uniform(parameters.blinkFresnelOnly !== undefined ? parameters.blinkFresnelOnly : true), | |
/** | |
* The opacity of the hologram. | |
* @type {Uniform<number>} | |
* @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 ; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment