diff --git a/README.md b/README.md index 76d01fc..894586f 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ assets/ logo (preloader) + bestemmingsmap voor toekomstige - **Lucht en gras (v0.4.3).** Knop "Lucht" in elke 3D-werkbalk (core/skybox.js, keuze onthouden). Het panorama (assets/skybox.webp) wordt op de grond geprojecteerd (port van three.js GroundedSkybox), met scherp gras - (assets/grass.jpg, Poly Haven grass_medium_01, CC0) in een cirkel van 12 m + (assets/grass.jpg, v0.4.4: kleurgecorrigeerd naar het gemiddelde grasgroen van het panorama onder de camera, belichting gecompenseerd) in een cirkel van 12 m dat daarna overvloeit in het panorama. De zon werpt schaduw op het gras en de camera kan niet onder de grond. Woning: het gras ligt op het maaiveld (woning-instelling, standaard 350 mm onder bovenkant vloer), zodat het diff --git a/assets/README.txt b/assets/README.txt index 36e082e..f6b3c64 100644 --- a/assets/README.txt +++ b/assets/README.txt @@ -1,4 +1,4 @@ Assets voor de 3D-weergave en de PDF: - logo.svg / logo-animated.svg logo (splash, about); PDF-logo staat als data in js/core/logo-data.js - skybox.webp equirectangulair panorama (6000x3000) voor "Lucht" (core/skybox.js) -- grass.jpg naadloze grastextuur (Poly Haven grass_medium_01, diffuse 1k, CC0) +- grass.jpg grastextuur, kleurgecorrigeerd naar het panorama-gras (bron: "grass (kopie).jpg", niet in git) diff --git a/assets/grass.jpg b/assets/grass.jpg index 027f925..460d4ba 100644 Binary files a/assets/grass.jpg and b/assets/grass.jpg differ diff --git a/js/app.js b/js/app.js index 9fd1686..ce8e62a 100644 --- a/js/app.js +++ b/js/app.js @@ -4,7 +4,7 @@ * Alle rechten voorbehouden. Gebruik uitsluitend met schriftelijke toestemming. * Zie LICENTIE.md. */ -const APP_VERSION = '0.4.3'; +const APP_VERSION = '0.4.4'; // 0.0.X per kleine iteratie, 0.X.0 per mijlpaal, X.0.0 bij live-gang. let tabs = []; diff --git a/js/core/skybox.js b/js/core/skybox.js index 7d9d735..e086bed 100644 --- a/js/core/skybox.js +++ b/js/core/skybox.js @@ -26,8 +26,13 @@ window.Skybox = (() => { const RADIUS_M = 60; // straal van de omgevingsbol const GRASS_RADIUS_M = 12; // tot hier is het eigen gras volledig zichtbaar const GRASS_FADE_M = 6; // daarna vloeit het over in het panorama - const GRASS_TILE_M = 2.5; // één grastegel beslaat zoveel meter - const GRASS_SHADE = 0x9a9a9a; // compenseert ambient + zon (anders te licht) + const GRASS_TILE_M = 2.0; // breedte van één grastegel (hoogte volgt de beeldverhouding) + // assets/grass.jpg is kleurgecorrigeerd naar het gemiddelde grasgroen van het + // panorama recht onder de camera (bron: "grass (kopie).jpg"). Het panorama + // is onbelicht; het gras wordt belicht door ambient (0.6) + zon (0.8, vanuit + // SUN_OFFSET). Deze factor maakt belicht gras gelijk aan de textuurkleur. + const SUN_OFFSET = { x: 8, y: 14, z: 6 }; + const GRASS_SHADE = 1 / (0.6 + 0.8 * SUN_OFFSET.y / Math.hypot(SUN_OFFSET.x, SUN_OFFSET.y, SUN_OFFSET.z)); let loading = null; function loadTextures() { @@ -69,8 +74,11 @@ window.Skybox = (() => { const R = GRASS_RADIUS_M + GRASS_FADE_M; const tex = map.clone(); tex.needsUpdate = true; - tex.repeat.set(2 * R / GRASS_TILE_M, 2 * R / GRASS_TILE_M); - const material = new THREE.MeshLambertMaterial({ map: tex, color: GRASS_SHADE, transparent: true, depthWrite: false }); + const aspect = (map.image && map.image.width) ? map.image.height / map.image.width : 1; + tex.repeat.set(2 * R / GRASS_TILE_M, 2 * R / (GRASS_TILE_M * aspect)); + const material = new THREE.MeshLambertMaterial({ + map: tex, color: new THREE.Color(GRASS_SHADE, GRASS_SHADE, GRASS_SHADE), transparent: true, depthWrite: false + }); // Randvervaging op afstand tot het midden (eigen varying: de UV's zijn // al herhaald voor de textuur). material.onBeforeCompile = (shader) => { @@ -125,7 +133,7 @@ window.Skybox = (() => { cam.updateProjectionMatrix(); o.sun.shadow.mapSize.set(2048, 2048); o.sun.shadow.bias = -0.0005; - o.sun.position.set(o.env.group.position.x + 8, 14, o.env.group.position.z + 6); + o.sun.position.set(o.env.group.position.x + SUN_OFFSET.x, o.env.group.position.y + SUN_OFFSET.y, o.env.group.position.z + SUN_OFFSET.z); o.sun.target.position.copy(o.env.group.position); o.sun.target.updateMatrixWorld(); }