From a9b41742dabf427b3e8d5d4cba0803c9dbe77f20 Mon Sep 17 00:00:00 2001 From: prospanclaudebot Date: Fri, 10 Jul 2026 22:57:38 +0000 Subject: textures: гёрстнер-океан (вода) + fbm normal map (земля) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- serve/index.html | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/serve/index.html b/serve/index.html index f8ce0f2..bcc5f17 100644 --- a/serve/index.html +++ b/serve/index.html @@ -1243,8 +1243,22 @@ function roughTex(freq, rmin, rmax) { } g.putImageData(im, 0, 0); const t = new THREE.CanvasTexture(cv); t.encoding = THREE.LinearEncoding; t.needsUpdate = true; return t; } +function normalTex(freq, strength) { // нормал-карта из fbm-шума -> микрорельеф земли в затенении + const Sz = 512, cv = document.createElement('canvas'); cv.width = cv.height = Sz; + const g = cv.getContext('2d'), im = g.createImageData(Sz, Sz); + const H = (i, j) => { const wx = (i / Sz - 0.5) * TERR * 2, wz = (j / Sz - 0.5) * TERR * 2; return fbm(wx * freq + 11.1, wz * freq + 5.5) + 0.5 * fbm(wx * freq * 3.1 + 2.0, wz * freq * 3.1); }; + for (let j = 0; j < Sz; j++) for (let i = 0; i < Sz; i++) { + const hL = H((i - 1 + Sz) % Sz, j), hR = H((i + 1) % Sz, j), hD = H(i, (j - 1 + Sz) % Sz), hU = H(i, (j + 1) % Sz); + let nx = (hL - hR) * strength, ny = (hD - hU) * strength, nz = 1.0; + const L = Math.hypot(nx, ny, nz) || 1; nx /= L; ny /= L; nz /= L; + const k = (j * Sz + i) * 4; + im.data[k] = Math.round((nx * 0.5 + 0.5) * 255); im.data[k + 1] = Math.round((ny * 0.5 + 0.5) * 255); im.data[k + 2] = Math.round((nz * 0.5 + 0.5) * 255); im.data[k + 3] = 255; + } + g.putImageData(im, 0, 0); const t = new THREE.CanvasTexture(cv); t.encoding = THREE.LinearEncoding; t.needsUpdate = true; return t; +} const terrain = new THREE.Mesh(tgeo, new THREE.MeshStandardMaterial({ - vertexColors: true, roughness: 1.0, metalness: 0.0, roughnessMap: roughTex(0.02, 0.42, 0.96) // land: rough, but varied + vertexColors: true, roughness: 1.0, metalness: 0.0, roughnessMap: roughTex(0.02, 0.42, 0.96), // land: rough, but varied + normalMap: normalTex(0.06, 2.4), normalScale: new THREE.Vector2(0.8, 0.8) // микрорельеф из fbm-шума -> земля не плоская })); terrain.receiveShadow = true; scene.add(terrain); @@ -1256,13 +1270,15 @@ const waterMat = new THREE.MeshStandardMaterial({ color: MAP.water, roughness: 1 waterMat.onBeforeCompile = (sh) => { // fractal-sine waves: displaces the surface + ripples the normal (so LTC/reflections shimmer) sh.uniforms.uTime = waterTime; const wfn = 'uniform float uTime;\n' + - 'float wv(vec2 p){ float w=0.0,a=1.0,f=0.045; vec2 d=vec2(1.0,0.35);' + - ' for(int i=0;i<4;i++){ w+=a*sin(dot(normalize(d),p)*f+uTime*(0.9+float(i)*0.35)); a*=0.5; f*=1.92; d=vec2(d.x*0.6-d.y*0.8,d.x*0.8+d.y*0.6); } return w; }\n'; + 'float oceanH(vec2 p){ float h=0.0,A=1.25,L=95.0; vec2 d=vec2(1.0,0.28);' + + ' for(int i=0;i<6;i++){ vec2 dd=normalize(d); float k=6.2831853/L; float c=sqrt(9.8/k); h+=A*sin(dot(dd,p)*k+uTime*c*0.14); A*=0.62; L*=0.62; d=vec2(d.x*0.6-d.y*0.8,d.x*0.8+d.y*0.6); } return h; }\n' + + 'vec3 oceanG(vec2 p){ vec3 o=vec3(0.0); float A=1.7,L=95.0; vec2 d=vec2(1.0,0.28);' + + ' for(int i=0;i<6;i++){ vec2 dd=normalize(d); float k=6.2831853/L; float c=sqrt(9.8/k); float f=dot(dd,p)*k+uTime*c*0.14; float Q=0.6/(k*A*6.0); o.x+=Q*A*dd.x*cos(f); o.y+=Q*A*dd.y*cos(f); o.z+=A*sin(f); A*=0.62; L*=0.62; d=vec2(d.x*0.6-d.y*0.8,d.x*0.8+d.y*0.6); } return o; }\n'; sh.vertexShader = wfn + sh.vertexShader; sh.vertexShader = sh.vertexShader.replace('#include ', - '#include \n float e=1.5; float wx=wv(position.xy+vec2(e,0.0))-wv(position.xy-vec2(e,0.0)); float wy=wv(position.xy+vec2(0.0,e))-wv(position.xy-vec2(0.0,e)); objectNormal=normalize(vec3(-wx,-wy,2.0*e));'); + '#include \n float e=1.6; float wx=oceanH(position.xy+vec2(e,0.0))-oceanH(position.xy-vec2(e,0.0)); float wy=oceanH(position.xy+vec2(0.0,e))-oceanH(position.xy-vec2(0.0,e)); objectNormal=normalize(vec3(-wx,-wy,2.0*e));'); sh.vertexShader = sh.vertexShader.replace('#include ', - '#include \n transformed.z += wv(position.xy)*0.8;'); + '#include \n vec3 og=oceanG(position.xy); transformed.x+=og.x; transformed.y+=og.y; transformed.z+=og.z;'); }; const water = new THREE.Mesh(new THREE.PlaneGeometry(TERR * 2, TERR * 2, 110, 110), waterMat); water.rotation.x = -Math.PI / 2; water.position.y = WATER_Y; scene.add(water); -- cgit v1.2.3