Skip to content

Commit f90d698

Browse files
authored
Water effect: environment Texturing (#19)
* Add texturing Signed-off-by: martinRenou <martin.renou@gmail.com> * Get rid of the hardcoded texture and make texturing optional Signed-off-by: martinRenou <martin.renou@gmail.com> * Use default sand texture Signed-off-by: martinRenou <martin.renou@gmail.com> * Change sand color Signed-off-by: martinRenou <martin.renou@gmail.com>
1 parent 95216c3 commit f90d698

2 files changed

Lines changed: 93 additions & 18 deletions

File tree

src/Plugins/Water/UnderWater.ts

Lines changed: 91 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,17 @@ uniform mat4 lightViewMatrix;
5454
5555
varying vec3 lightPosition;
5656
varying vec3 worldPosition;
57+
varying vec3 textureBlending;
5758
varying float v${underwater};
59+
varying vec3 vNormal;
5860
5961
6062
void main(void){
6163
// Interpolate the underwater value
6264
v${underwater} = ${underwater};
6365
66+
vNormal = normal.xyz;
67+
6468
vec4 modelPosition = modelMatrix * vec4(position, 1.);
6569
worldPosition = modelPosition.xyz;
6670
@@ -69,6 +73,12 @@ void main(void){
6973
vec4 lightRelativePosition = lightProjectionMatrix * lightViewMatrix * modelPosition;
7074
lightPosition = 0.5 + lightRelativePosition.xyz / lightRelativePosition.w * 0.5;
7175
76+
// Texture blending
77+
textureBlending = abs(normal);
78+
textureBlending = normalize(max(textureBlending, 0.00001)); // Force weights to sum to 1.0
79+
float b = textureBlending.x + textureBlending.y + textureBlending.z;
80+
textureBlending /= vec3(b, b, b);
81+
7282
// The position of the vertex
7383
gl_Position = projectionMatrix * viewMatrix * modelPosition;
7484
}
@@ -77,12 +87,24 @@ void main(void){
7787
const getEnvFragment = (underwater: String) => `
7888
uniform vec3 light;
7989
uniform sampler2D caustics;
80-
// TODO Make this a uniform
90+
91+
#ifdef USE_TEXTURING
92+
uniform sampler2D envTexture;
93+
#endif
94+
95+
// TODO Make those uniforms
8196
const vec2 resolution = vec2(1024.);
97+
const float scale = 1. / 0.5;
98+
const vec2 sandTextureResolution = vec2(512, 512);
99+
const vec3 sandColor = vec3(0.951, 1., 0.825);
100+
101+
vec3 texColor;
82102
83103
varying vec3 lightPosition;
84104
varying vec3 worldPosition;
105+
varying vec3 textureBlending;
85106
varying float v${underwater};
107+
varying vec3 vNormal;
86108
87109
const float bias = 0.001;
88110
@@ -101,20 +123,56 @@ float blur(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
101123
return intensity;
102124
}
103125
126+
vec2 random2(vec2 st){
127+
st = vec2(
128+
dot(st, vec2(127.1, 311.7)),
129+
dot(st, vec2(269.5, 183.3))
130+
);
104131
105-
void main() {
106-
// Compute flat shading normal (inefficient, should be computed on CPU once)
107-
vec3 X = dFdx(worldPosition);
108-
vec3 Y = dFdy(worldPosition);
109-
vec3 normal = normalize(cross(X, Y));
132+
return -1.0 + 2.0 * fract(sin(st) * 43758.5453123);
133+
}
110134
111-
float lightIntensity = - dot(light, normalize(normal));
135+
// Gradient Noise
136+
float noise(vec2 st) {
137+
vec2 i = floor(st);
138+
vec2 f = fract(st);
139+
140+
vec2 u = f * f * (3.0 - 2.0 * f);
141+
142+
return mix(
143+
mix(
144+
dot(random2(i + vec2(0.0, 0.0)), f - vec2(0.0, 0.0)),
145+
dot(random2(i + vec2(1.0, 0.0)), f - vec2(1.0, 0.0)),
146+
u.x
147+
),
148+
mix(
149+
dot(random2(i + vec2(0.0, 1.0)), f - vec2(0.0, 1.0)),
150+
dot(random2(i + vec2(1.0, 1.0) ), f - vec2(1.0, 1.0)),
151+
u.x
152+
),
153+
u.y
154+
);
155+
}
112156
113-
// Set the frag color
114-
float computedLightIntensity = 0.5;
157+
void main() {
158+
float lightIntensity = - dot(light, normalize(vNormal));
115159
160+
float computedLightIntensity = 0.5;
116161
computedLightIntensity += 0.2 * lightIntensity;
117162
163+
#ifdef USE_TEXTURING
164+
// Texture tri-planar mapping
165+
vec3 xaxis = texture2D(envTexture, worldPosition.yz * scale).xyz;
166+
vec3 yaxis = texture2D(envTexture, worldPosition.xz * scale).xyz;
167+
vec3 zaxis = texture2D(envTexture, worldPosition.xy * scale).xyz;
168+
#else
169+
// Tri-planar mapping on the generated sand texture
170+
vec3 xaxis = vec3(noise(worldPosition.yz * 100. * scale) * 0.2 + 0.9) * sandColor;
171+
vec3 yaxis = vec3(noise(worldPosition.xz * 100. * scale) * 0.2 + 0.9) * sandColor;
172+
vec3 zaxis = vec3(noise(worldPosition.xy * 100. * scale) * 0.2 + 0.9) * sandColor;
173+
#endif
174+
texColor = xaxis * textureBlending.x + yaxis * textureBlending.y + zaxis * textureBlending.z;
175+
118176
if (v${underwater} > 0.) {
119177
// Retrieve caustics information
120178
vec2 causticsInfo = texture2D(caustics, lightPosition.xy).zw;
@@ -129,9 +187,9 @@ void main() {
129187
computedLightIntensity += causticsIntensity;
130188
}
131189
132-
gl_FragColor = vec4(underwaterColor * computedLightIntensity, 1.);
190+
gl_FragColor = vec4(texColor * underwaterColor * computedLightIntensity, 1.);
133191
} else {
134-
gl_FragColor = vec4(overwaterColor * computedLightIntensity, 1.);
192+
gl_FragColor = vec4(texColor * overwaterColor * computedLightIntensity, 1.);
135193
}
136194
}
137195
`;
@@ -140,7 +198,6 @@ void main() {
140198
/**
141199
* Block that receives the caustics.
142200
**/
143-
// TODO: Take a 1D input, the underwater component that specifies if the vertex is underwater or not
144201
export
145202
class UnderWater extends Effect {
146203

@@ -164,9 +221,13 @@ class UnderWater extends Effect {
164221
uniforms: {
165222
light: { value: null },
166223
caustics: { value: null },
224+
envTexture: { value: null },
167225
lightProjectionMatrix: { value: null },
168226
lightViewMatrix: { value: null }
169227
},
228+
defines: {
229+
USE_TEXTURING: false
230+
},
170231
extensions: {
171232
derivatives: true
172233
}
@@ -181,6 +242,9 @@ class UnderWater extends Effect {
181242

182243
(mesh.geometry as THREE.BufferGeometry).setAttribute(this.inputComponent.shaderName, this.inputComponent.bufferAttribute);
183244

245+
// We need the normals in shaders
246+
mesh.geometry.computeVertexNormals();
247+
184248
const envMesh = new THREE.Mesh(mesh.geometry, this.envMaterial);
185249
envMesh.matrixAutoUpdate = false;
186250
this.envMeshes.push(envMesh);
@@ -210,6 +274,21 @@ class UnderWater extends Effect {
210274
this.envMaterial.uniforms['caustics'].value = causticsTexture;
211275
}
212276

277+
setTexture (texture: THREE.Texture | null) {
278+
if (texture === null) {
279+
this.envMaterial.uniforms['envTexture'].value = null;
280+
this.envMaterial.defines['USE_TEXTURING'] = false;
281+
282+
return;
283+
}
284+
285+
texture.wrapS = THREE.RepeatWrapping;
286+
texture.wrapT = THREE.RepeatWrapping;
287+
288+
this.envMaterial.uniforms['envTexture'].value = texture;
289+
this.envMaterial.defines['USE_TEXTURING'] = true;
290+
}
291+
213292
renderEnvMap (renderer: THREE.WebGLRenderer, lightCamera: THREE.Camera) {
214293
for (const mesh of this.envMappingMeshes) {
215294
renderer.render(mesh, lightCamera);

src/Scene.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,9 @@ class Scene {
2222
const ambientLight = new THREE.AmbientLight(0xffffff, 1);
2323
this.scene.add(ambientLight);
2424

25-
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.1);
26-
directionalLight.position.set(-1, 1.75, 1);
25+
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.3);
26+
directionalLight.position.set(0., 0., 1);
2727
this.scene.add(directionalLight);
28-
29-
const hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.2);
30-
hemiLight.position.set(0, 2, 0);
31-
this.scene.add(hemiLight);
3228
}
3329

3430
/**

0 commit comments

Comments
 (0)