summaryrefslogtreecommitdiff
path: root/serve
diff options
context:
space:
mode:
Diffstat (limited to 'serve')
-rw-r--r--serve/index.html24
1 files changed, 20 insertions, 4 deletions
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 <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' +
+ '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 <roughnessmap_fragment>', '#include <roughnessmap_fragment>\n roughnessFactor *= 0.5 + 0.65*fbmT(vWPosT.xz*0.32);')
+ .replace('#include <normal_fragment_maps>', '#include <normal_fragment_maps>\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);