summaryrefslogtreecommitdiff
path: root/serve
diff options
context:
space:
mode:
Diffstat (limited to 'serve')
-rw-r--r--serve/index.html25
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);')