@@ -54,13 +54,17 @@ uniform mat4 lightViewMatrix;
5454
5555varying vec3 lightPosition;
5656varying vec3 worldPosition;
57+ varying vec3 textureBlending;
5758varying float v${ underwater } ;
59+ varying vec3 vNormal;
5860
5961
6062void 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){
7787const getEnvFragment = ( underwater : String ) => `
7888uniform vec3 light;
7989uniform 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
8196const 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
83103varying vec3 lightPosition;
84104varying vec3 worldPosition;
105+ varying vec3 textureBlending;
85106varying float v${ underwater } ;
107+ varying vec3 vNormal;
86108
87109const 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
144201export
145202class 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 ) ;
0 commit comments