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,
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
+1 -1
View File
@@ -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)
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.
* 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 = [];
+13 -5
View File
@@ -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();
}