v0.4.4: gras kleurgecorrigeerd naar panorama-grasgroen, belichting gecompenseerd

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Machiel
2026-09-30 12:13:41 +02:00
co-authored by Claude Opus 5.5
parent f8da490640
commit 9ed9cee2e0
5 changed files with 16 additions and 8 deletions
+1 -1
View File
@@ -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, - **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 keuze onthouden). Het panorama (assets/skybox.webp) wordt op de grond
geprojecteerd (port van three.js GroundedSkybox), met scherp gras 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 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 de camera kan niet onder de grond. Woning: het gras ligt op het maaiveld
(woning-instelling, standaard 350 mm onder bovenkant vloer), zodat het (woning-instelling, standaard 350 mm onder bovenkant vloer), zodat het
+1 -1
View File
@@ -1,4 +1,4 @@
Assets voor de 3D-weergave en de PDF: 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 - 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) - 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)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 386 KiB

After

Width:  |  Height:  |  Size: 8.8 MiB

+1 -1
View File
@@ -4,7 +4,7 @@
* Alle rechten voorbehouden. Gebruik uitsluitend met schriftelijke toestemming. * Alle rechten voorbehouden. Gebruik uitsluitend met schriftelijke toestemming.
* Zie LICENTIE.md. * 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. // 0.0.X per kleine iteratie, 0.X.0 per mijlpaal, X.0.0 bij live-gang.
let tabs = []; let tabs = [];
+13 -5
View File
@@ -26,8 +26,13 @@ window.Skybox = (() => {
const RADIUS_M = 60; // straal van de omgevingsbol const RADIUS_M = 60; // straal van de omgevingsbol
const GRASS_RADIUS_M = 12; // tot hier is het eigen gras volledig zichtbaar 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_FADE_M = 6; // daarna vloeit het over in het panorama
const GRASS_TILE_M = 2.5; // één grastegel beslaat zoveel meter const GRASS_TILE_M = 2.0; // breedte van één grastegel (hoogte volgt de beeldverhouding)
const GRASS_SHADE = 0x9a9a9a; // compenseert ambient + zon (anders te licht) // 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; let loading = null;
function loadTextures() { function loadTextures() {
@@ -69,8 +74,11 @@ window.Skybox = (() => {
const R = GRASS_RADIUS_M + GRASS_FADE_M; const R = GRASS_RADIUS_M + GRASS_FADE_M;
const tex = map.clone(); const tex = map.clone();
tex.needsUpdate = true; tex.needsUpdate = true;
tex.repeat.set(2 * R / GRASS_TILE_M, 2 * R / GRASS_TILE_M); const aspect = (map.image && map.image.width) ? map.image.height / map.image.width : 1;
const material = new THREE.MeshLambertMaterial({ map: tex, color: GRASS_SHADE, transparent: true, depthWrite: false }); 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 // Randvervaging op afstand tot het midden (eigen varying: de UV's zijn
// al herhaald voor de textuur). // al herhaald voor de textuur).
material.onBeforeCompile = (shader) => { material.onBeforeCompile = (shader) => {
@@ -125,7 +133,7 @@ window.Skybox = (() => {
cam.updateProjectionMatrix(); cam.updateProjectionMatrix();
o.sun.shadow.mapSize.set(2048, 2048); o.sun.shadow.mapSize.set(2048, 2048);
o.sun.shadow.bias = -0.0005; 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.position.copy(o.env.group.position);
o.sun.target.updateMatrixWorld(); o.sun.target.updateMatrixWorld();
} }