From 3326bb2b3af9f3a2f9252564a99ea0cfbc42b574 Mon Sep 17 00:00:00 2001 From: prospanclaudebot Date: Fri, 10 Jul 2026 23:04:45 +0000 Subject: земля: процедурная screen-space roughness + dFdx/dFdy bump (убрал мыльные текстуры) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- serve/index.html | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'serve/index.html') diff --git a/serve/index.html b/serve/index.html index bcc5f17..72bd3e6 100644 --- a/serve/index.html +++ b/serve/index.html @@ -1256,10 +1256,26 @@ 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; } -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 - normalMap: normalTex(0.06, 2.4), normalScale: new THREE.Vector2(0.8, 0.8) // микрорельеф из fbm-шума -> земля не плоская -})); +// земля: roughness и нормаль-детали считаются ПРОЦЕДУРНО per-fragment (screen-space, через dFdx/dFdy) +// -> чётко на любой дистанции, без растянутой «мыльной» текстуры +const terrainMat = new THREE.MeshStandardMaterial({ vertexColors: true, roughness: 1.0, metalness: 0.0 }); +terrainMat.onBeforeCompile = (sh) => { + sh.vertexShader = sh.vertexShader + .replace('#include ', '#include \nvarying vec3 vWPosT;') + .replace('#include ', '#include \n vWPosT = (modelMatrix * vec4(transformed,1.0)).xyz;'); + sh.fragmentShader = sh.fragmentShader + .replace('#include ', '#include \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' + + 'float fbmT(vec2 p){ float a=0.5,s=0.0; for(int i=0;i<4;i++){ s+=a*vnT(p); p=p*2.03+17.1; a*=0.5; } return s; }\n') + .replace('#include ', '#include \n roughnessFactor *= 0.5 + 0.65*fbmT(vWPosT.xz*0.32);') + .replace('#include ', '#include \n' + + ' { float hh=fbmT(vWPosT.xz*0.34); vec2 dH=vec2(dFdx(hh),dFdy(hh))*15.0;' + + ' vec3 Sx=dFdx(-vViewPosition), Sy=dFdy(-vViewPosition);' + + ' vec3 R1=cross(Sy,normal), R2=cross(normal,Sx); float det=dot(Sx,R1);' + + ' vec3 grad=sign(det)*(dH.x*R1+dH.y*R2); normal=normalize(abs(det)*normal-grad); }'); +}; +const terrain = new THREE.Mesh(tgeo, terrainMat); terrain.receiveShadow = true; scene.add(terrain); -- cgit v1.2.3