diff options
Diffstat (limited to 'serve')
| -rw-r--r-- | serve/index.html | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/serve/index.html b/serve/index.html index b47a7ce..8a97a72 100644 --- a/serve/index.html +++ b/serve/index.html @@ -1256,17 +1256,27 @@ function normalTex(freq, strength) { // нормал-карта из fbm-шу� } g.putImageData(im, 0, 0); const t = new THREE.CanvasTexture(cv); t.encoding = THREE.LinearEncoding; t.needsUpdate = true; return t; } +// пре-генерированная шум-текстура (white-noise + билинейка = value-noise, бесшовно) — вместо sin-хэша +const noiseTex = (function () { + const S = 256, cv = document.createElement('canvas'); cv.width = cv.height = S; + const g = cv.getContext('2d'), im = g.createImageData(S, S); + for (let i = 0; i < S * S; i++) { const v = (Math.random() * 256) | 0; im.data[i * 4] = im.data[i * 4 + 1] = im.data[i * 4 + 2] = v; im.data[i * 4 + 3] = 255; } + g.putImageData(im, 0, 0); + const t = new THREE.CanvasTexture(cv); + t.wrapS = t.wrapT = THREE.RepeatWrapping; t.magFilter = THREE.LinearFilter; t.minFilter = THREE.LinearFilter; t.generateMipmaps = false; t.needsUpdate = true; + return t; +})(); // земля: roughness и нормаль-детали считаются ПРОЦЕДУРНО per-fragment (screen-space, через dFdx/dFdy) // -> чётко на любой дистанции, без растянутой «мыльной» текстуры const terrainMat = new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 1.0, metalness: 0.0 }); terrainMat.onBeforeCompile = (sh) => { + sh.uniforms.uNoise = { value: noiseTex }; sh.vertexShader = sh.vertexShader .replace('#include <common>', '#include <common>\nvarying vec3 vWPosT;') .replace('#include <begin_vertex>', '#include <begin_vertex>\n vWPosT = (modelMatrix * vec4(transformed,1.0)).xyz;'); sh.fragmentShader = sh.fragmentShader - .replace('#include <common>', '#include <common>\nvarying vec3 vWPosT;\n' + - 'float h21T(vec2 p){ return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453); }\n' + - 'float vnT(vec2 p){ vec2 i=floor(p),f=fract(p); f=f*f*(3.0-2.0*f); return mix(mix(h21T(i),h21T(i+vec2(1.0,0.0)),f.x),mix(h21T(i+vec2(0.0,1.0)),h21T(i+vec2(1.0,1.0)),f.x),f.y); }\n' + + .replace('#include <common>', '#include <common>\nvarying vec3 vWPosT;\nuniform sampler2D uNoise;\n' + + 'float vnT(vec2 p){ return texture2D(uNoise, p*0.00390625).r; }\n' + // билинейный value-noise из текстуры, бесшовно 'float fbmT(vec2 p){ float a=0.5,s=0.0; for(int i=0;i<3;i++){ s+=a*vnT(p); p=p*2.03+17.1; a*=0.5; } return s; }\nfloat WY=' + WATER_Y.toFixed(2) + ';\n') .replace('#include <color_fragment>', '#include <color_fragment>\n' + ' float _dst=length(vViewPosition); float _nr=1.0-smoothstep(45.0,200.0,_dst); float _nn=1.0-smoothstep(45.0,170.0,_dst);' + // дистанции — один раз @@ -1291,7 +1301,7 @@ const WATER_Y = MAP.waterY; const waterTime = { value: 0 }; const waterMat = new THREE.MeshStandardMaterial({ color: MAP.water, roughness: 0.14, metalness: 0.0, transparent: true, opacity: 0.72, polygonOffset: true, polygonOffsetFactor: -2, polygonOffsetUnits: -2 }); waterMat.onBeforeCompile = (sh) => { // гёрстнер-волны (vertex) + процедурная roughness/пена (fragment) — БЕЗ запечённых текстур - sh.uniforms.uTime = waterTime; + sh.uniforms.uTime = waterTime; sh.uniforms.uNoise = { value: noiseTex }; const vfn = 'uniform float uTime;\nvarying float vWH; varying vec2 vWXZ;\n' + 'float oceanH(vec2 p){ float h=0.0,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); 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'; @@ -1299,10 +1309,9 @@ waterMat.onBeforeCompile = (sh) => { // гёрстнер-волны (vertex) + .replace('#include <common>', '#include <common>\n' + vfn) .replace('#include <beginnormal_vertex>', '#include <beginnormal_vertex>\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));') .replace('#include <begin_vertex>', '#include <begin_vertex>\n vec3 og=oceanG(position.xy); transformed.x+=og.x; transformed.y+=og.y; transformed.z+=og.z; vWH=og.z; vWXZ=position.xy;'); - const ffn = 'uniform float uTime;\nvarying float vWH; varying vec2 vWXZ;\n' + - 'float wh21(vec2 p){ return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453); }\n' + - 'float wvn(vec2 p){ vec2 i=floor(p),f=fract(p); f=f*f*(3.0-2.0*f); return mix(mix(wh21(i),wh21(i+vec2(1.0,0.0)),f.x),mix(wh21(i+vec2(0.0,1.0)),wh21(i+vec2(1.0,1.0)),f.x),f.y); }\n' + - 'float wfbm(vec2 p){ float a=0.5,s=0.0; for(int i=0;i<4;i++){ s+=a*wvn(p); p=p*2.03+9.1; a*=0.5; } return s; }\n'; + const ffn = 'uniform float uTime;\nuniform sampler2D uNoise;\nvarying float vWH; varying vec2 vWXZ;\n' + + 'float wvn(vec2 p){ return texture2D(uNoise, p*0.00390625).r; }\n' + // value-noise из текстуры + 'float wfbm(vec2 p){ float a=0.5,s=0.0; for(int i=0;i<3;i++){ s+=a*wvn(p); p=p*2.03+9.1; a*=0.5; } return s; }\n'; sh.fragmentShader = sh.fragmentShader .replace('#include <common>', '#include <common>\n' + ffn) .replace('#include <color_fragment>', '#include <color_fragment>\n float wn=wfbm(vWXZ*0.12+uTime*0.03); float foam=smoothstep(2.1,3.6,vWH+wn*1.4); diffuseColor.rgb=mix(diffuseColor.rgb, vec3(0.82,0.9,0.96), foam*0.6);') |
