solution
Version:
An animation library for different types of liquids.
63 lines (43 loc) • 5.6 kB
JavaScript
import THREE from "three";
const fragment = "#define DISTORTION\r\n\r\nuniform sampler2D tPerturb;\r\nuniform sampler2D tDiffuse;\r\n\r\nuniform float time;\r\nuniform float resetTimer;\r\n\r\nuniform vec2 rollOffSpeed;\r\nuniform vec2 waveStrength;\r\nuniform vec3 tint;\r\n\r\nvarying vec2 vUv;\r\n\r\nconst float FADE = 12.0;\r\n\r\nvoid main() {\r\n\r\n\tfloat n = 0.0;\r\n\tfloat drop = 0.0;\r\n\r\n\tfloat resetTimerFaster = resetTimer * rollOffSpeed.x;\r\n\tfloat resetTimerSlow = resetTimer * rollOffSpeed.y;\r\n\r\n\tvec2 perturbSample;\r\n\r\n\tif(resetTimer > 0.0) {\r\n\r\n\t\tperturbSample = texture2D(tPerturb, vUv).rg;\r\n\r\n\t\tif(resetTimer < T_DISSOLVE) {\r\n\r\n\t\t\tn = perturbSample.r;\r\n\r\n\t\t}\r\n\r\n\t\tif(resetTimer < T_DROPLETS) {\r\n\r\n\t\t\tdrop = perturbSample.g;\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t// if-less alternative.\r\n\t//perturbSample = texture2D(tPerturb, vUv).rg;\r\n\t//n = perturbSample.r;\r\n\t//drop = perturbSample.g;\r\n\t//n *= clamp(ceil(resetTimer / T_DISSOLVE), 0.0, 1.0);\r\n\t//drop *= clamp(ceil(resetTimer / T_DROPLETS), 0.0, 1.0);\r\n\r\n\tfloat drops = clamp(smoothstep(resetTimerFaster, 0.5 + resetTimerFaster, n), 0.0, 1.0);\r\n\tfloat droplet = clamp(smoothstep(0.75 + resetTimerSlow, 1.0 + resetTimerSlow, drop), 0.0, 1.0);\r\n\r\n\tdroplet = pow(clamp(droplet + drops, 0.0, 1.0), 0.1) * 3.0;\r\n\r\n\tvec2 droplets = vec2(dFdx(vUv + droplet).r, dFdy(vUv + droplet).g);\t\t\r\n\r\n\tvec2 wave = vec2(0.0);\r\n\r\n\tif(resetTimer < 1.0) {\r\n\r\n\t\twave.x = sin((vUv.x - vUv.y * 2.0) - time * 1.5) * waveStrength.x;\r\n\t\twave.x += cos((vUv.y * 4.0 - vUv.x * 6.0) + time * 4.2) * waveStrength.y;\r\n\t\twave.x += sin((vUv.x * 9.0 + vUv.y * 8.0) + time * 3.5) * waveStrength.x;\r\n\r\n\t\twave.y = sin((vUv.x * 2.0 + vUv.x * 2.5) + time * 2.5) * waveStrength.x;\r\n\t\twave.y += cos((vUv.y * 3.0 + vUv.x * 6.0) - time * 2.5) * waveStrength.y;\r\n\t\twave.y += sin((vUv.x * 11.0 - vUv.y * 12.0) + time * 4.5) * waveStrength.x;\r\n\r\n\t}\r\n\r\n\t//wave *= clamp(ceil(1.0 - resetTimer), 0.0, 1.0);\r\n\r\n\t// Texture edge bleed removal.\r\n\tvec2 distortFade = vec2(0.0);\r\n\tdistortFade.s = clamp(vUv.s * FADE, 0.0, 1.0);\r\n\tdistortFade.s -= clamp(1.0 - (1.0 - vUv.s) * FADE, 0.0, 1.0);\r\n\tdistortFade.t = clamp(vUv.t * FADE, 0.0, 1.0);\r\n\tdistortFade.t -= clamp(1.0 - (1.0 - vUv.t) * FADE, 0.0, 1.0); \r\n\r\n\tfloat dfade = 1.0 - pow(1.0 - distortFade.s * distortFade.t, 2.0);\r\n\twave = wave * dfade;\r\n\tdroplets = droplets * dfade;\r\n\r\n\tvec2 waveCoordR = vUv - wave * 0.004;\r\n\tvec2 waveCoordG = vUv - wave * 0.006;\t\r\n\tvec2 waveCoordB = vUv - wave * 0.008;\r\n\r\n\tvec2 dropCoordR = vUv - droplets * 1.1;\r\n\tvec2 dropCoordG = vUv - droplets * 1.2;\t\r\n\tvec2 dropCoordB = vUv - droplets * 1.3;\t\r\n\r\n\tvec3 dropletColor = vec3(0.0);\t\r\n\tdropletColor.r = texture2D(tDiffuse, dropCoordR).r;\r\n\tdropletColor.g = texture2D(tDiffuse, dropCoordG).g;\r\n\tdropletColor.b = texture2D(tDiffuse, dropCoordB).b;\r\n\r\n\tvec3 waveColor = vec3(0.0);\r\n\twaveColor.r = texture2D(tDiffuse, waveCoordR).r;\r\n\twaveColor.g = texture2D(tDiffuse, waveCoordG).g;\r\n\twaveColor.b = texture2D(tDiffuse, waveCoordB).b;\r\n\r\n\tfloat dropFade = clamp(resetTimer * 10.0, 0.0, 1.0);\r\n\tfloat dropletMask = smoothstep(0.77 + resetTimerSlow, 0.79 + resetTimerSlow, drop);\r\n\tfloat mask = smoothstep(0.02 + resetTimerFaster, 0.03 + resetTimerFaster, n);\r\n\r\n\tvec4 c = texture2D(tDiffuse, vUv);\r\n\r\n\tvec3 color = mix(waveColor, c.rgb, dropFade);\r\n\tcolor = mix(color, dropletColor * tint, clamp(dropletMask + mask, 0.0, 1.0) * dropFade);\r\n\r\n\tgl_FragColor = vec4(color, c.a);\r\n\r\n}\r\n";
const vertex = "#define DISTORTION\n\nvarying vec2 vUv;\n\nvoid main() {\n\n\tvUv = uv;\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n\n}\n";
/**
* A distortion shader material.
*
* Shader code taken from Martins Upitis' water/underwater blend:
* http://devlog-martinsh.blogspot.de/2013/09/waterunderwater-sky-shader-update-02.html
*
* @class DistortionMaterial
* @constructor
* @extends ShaderMaterial
* @param {Object} [options] - The options.
* @param {Texture} [options.perturbMap] - If none is provided, the shader will generate perlin noise on the fly.
* @param {Vector2} [options.rollOffSpeed] - The water roll off speed. X affects the overall roll off, while Y controls the droplets.
* @param {Vector2} [options.waveStrength] - The distortion wave strength. X = sine, Y = cosine.
* @param {Color} [options.color] - The droplet tint.
*/
export class DistortionMaterial extends THREE.ShaderMaterial {
constructor(options) {
if(options === undefined) { options = {}; }
super({
defines: {
T_DISSOLVE: "4.0",
T_DROPLETS: "60.0"
},
uniforms: {
tPerturb: {type: "t", value: (options.perturbMap !== undefined) ? options.perturbMap : null},
tDiffuse: {type: "t", value: null},
time: {type: "1f", value: Math.random() * 1000.0},
resetTimer: {type: "1f", value: 0.0},
rollOffSpeed: {type: "v2", value: (options.rollOffSpeed !== undefined) ? options.rollOffSpeed : new THREE.Vector2(0.5, 0.02)},
waveStrength: {type: "v2", value: (options.waveStrength !== undefined) ? options.waveStrength : new THREE.Vector2(0.25, 0.5)},
tint: {type: "c", value: (options.color !== undefined) ? options.color : new THREE.Color(1.0, 1.0, 1.0)},
},
fragmentShader: fragment,
vertexShader: vertex,
extensions: {
derivatives: true
}
});
}
}