v0.4.7: lampen niet meer door muren, buiten overdag gedimd, binnenspots feller
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
5ecf3e0c2a
commit
448c2b1289
@@ -173,6 +173,12 @@ assets/ logo (preloader) + bestemmingsmap voor toekomstige
|
|||||||
unitrand bij een naad); spots te dicht bij een binnenwand vervallen.
|
unitrand bij een naad); spots te dicht bij een binnenwand vervallen.
|
||||||
Woning-instellingen › Verlichting › Binnenspots. In 3D (filter Lampen),
|
Woning-instellingen › Verlichting › Binnenspots. In 3D (filter Lampen),
|
||||||
plattegrond (open cirkeltje), render en totalen.
|
plattegrond (open cirkeltje), render en totalen.
|
||||||
|
- **Lichtbronnen (v0.4.7).** Geen echte schaduw per lamp (één schaduwkaart
|
||||||
|
per lamp overschrijdt de browserlimiet); licht door muren wordt geometrisch
|
||||||
|
voorkomen: buitenlampen en boeideel-spots zijn half hun bundelhoek naar
|
||||||
|
buiten gekanteld (boeideel: normaal van de dakrand, op hoeken diagonaal),
|
||||||
|
binnenspots reiken hard tot net voorbij de vloer. Buitenlampen overdag op
|
||||||
|
35% (LightingModel.DAY_OUTDOOR_FACTOR), 's nachts 100%; binnenspots feller.
|
||||||
- **Mijlpaal v0.4 — gevelopbouw.** Samenvatting van de v0.3.11–0.3.19-iteraties:
|
- **Mijlpaal v0.4 — gevelopbouw.** Samenvatting van de v0.3.11–0.3.19-iteraties:
|
||||||
kruislat-latwerk op vochtdoek (richting gevelbekleding globaal), lampen op de
|
kruislat-latwerk op vochtdoek (richting gevelbekleding globaal), lampen op de
|
||||||
afgewerkte gevel (+52 mm), logo-watermerk op het doek, trasraam (cement-
|
afgewerkte gevel (+52 mm), logo-watermerk op het doek, trasraam (cement-
|
||||||
|
|||||||
@@ -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.6';
|
const APP_VERSION = '0.4.7';
|
||||||
// 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 = [];
|
||||||
|
|||||||
+3
-1
@@ -336,7 +336,9 @@ function mountHouseEditor(container, callbacks) {
|
|||||||
if (parts && parts.lightingGroup) parts.lightingGroup.traverse(o => { if (o.userData.beam) o.visible = !lampsOn; });
|
if (parts && parts.lightingGroup) parts.lightingGroup.traverse(o => { if (o.userData.beam) o.visible = !lampsOn; });
|
||||||
if (lampsOn && parts && lampenVisible) {
|
if (lampsOn && parts && lampenVisible) {
|
||||||
const edge = dakVisible ? parts.roofEdge : null;
|
const edge = dakVisible ? parts.roofEdge : null;
|
||||||
lightsGroup = LightingModel.buildLights3D(parts.lighting.lamps, edge ? edge.spots : [], edge ? edge.top - edge.fasciaHeight : 0, parts.lighting.indoor);
|
lightsGroup = LightingModel.buildLights3D(parts.lighting.lamps, edge ? edge.spots : [], edge ? edge.top - edge.fasciaHeight : 0, parts.lighting.indoor, {
|
||||||
|
outdoorFactor: skyMode === 'night' ? 1 : LightingModel.DAY_OUTDOOR_FACTOR
|
||||||
|
});
|
||||||
scene.add(lightsGroup);
|
scene.add(lightsGroup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,9 +188,20 @@ window.LightingModel = (() => {
|
|||||||
const spots = [];
|
const spots = [];
|
||||||
if (s.mode === 'spots') {
|
if (s.mode === 'spots') {
|
||||||
const rs = RoofModel.normalizeSettings(roofSettings);
|
const rs = RoofModel.normalizeSettings(roofSettings);
|
||||||
edge.segments.filter(sg => sg.fascia).forEach(sg => spotsBetween(sg.spotA, sg.spotB, rs.spotMin, rs.spotMax, spots));
|
edge.segments.filter(sg => sg.fascia).forEach(sg => {
|
||||||
|
const from = spots.length;
|
||||||
|
spotsBetween(sg.spotA, sg.spotB, rs.spotMin, rs.spotMax, spots);
|
||||||
|
for (let k = from; k < spots.length; k++) spots[k].normal = { x: sg.normal.x, z: sg.normal.z };
|
||||||
|
});
|
||||||
}
|
}
|
||||||
edge.spots = spots.filter((p, i) => spots.findIndex(q => Math.hypot(q.x - p.x, q.z - p.z) < 5) === i);
|
// Dubbele spots (hoeken) samenvoegen; de buitenrichting wordt dan de
|
||||||
|
// som van beide gevels (diagonaal naar buiten).
|
||||||
|
edge.spots = [];
|
||||||
|
spots.forEach(p => {
|
||||||
|
const q = edge.spots.find(e => Math.hypot(e.x - p.x, e.z - p.z) < 5);
|
||||||
|
if (!q) edge.spots.push({ x: p.x, z: p.z, normal: p.normal });
|
||||||
|
else if (p.normal && q.normal) q.normal = { x: q.normal.x + p.normal.x, z: q.normal.z + p.normal.z };
|
||||||
|
});
|
||||||
}
|
}
|
||||||
return { lamps };
|
return { lamps };
|
||||||
}
|
}
|
||||||
@@ -212,7 +223,7 @@ window.LightingModel = (() => {
|
|||||||
|
|
||||||
// Binnenspots per unit. units = HouseModel-parts.units (rect, walls, roof.base),
|
// Binnenspots per unit. units = HouseModel-parts.units (rect, walls, roof.base),
|
||||||
// interior = parts.interior (binnenwanden met place). Geeft
|
// interior = parts.interior (binnenwanden met place). Geeft
|
||||||
// [{ unitId, x, z, y }] (mm, y = onderkant plafond).
|
// [{ unitId, x, z, y, floorY }] (mm, y = onderkant plafond, floorY = loopvlak).
|
||||||
function computeIndoor(settings, units, interior) {
|
function computeIndoor(settings, units, interior) {
|
||||||
const s = normalizeSettings(settings);
|
const s = normalizeSettings(settings);
|
||||||
if (!s.indoor) return [];
|
if (!s.indoor) return [];
|
||||||
@@ -229,7 +240,7 @@ window.LightingModel = (() => {
|
|||||||
const a = { x: iw.place.cx - half * c, z: iw.place.cz + half * sn }, b = { x: iw.place.cx + half * c, z: iw.place.cz - half * sn };
|
const a = { x: iw.place.cx - half * c, z: iw.place.cz + half * sn }, b = { x: iw.place.cx + half * c, z: iw.place.cz - half * sn };
|
||||||
return distToSegment({ x, z }, a, b) < iw.place.thickness / 2 + off;
|
return distToSegment({ x, z }, a, b) < iw.place.thickness / 2 + off;
|
||||||
});
|
});
|
||||||
if (!tooClose) out.push({ unitId: u.id, x, z, y: u.roof.base });
|
if (!tooClose) out.push({ unitId: u.id, x, z, y: u.roof.base, floorY: u.layout.floorTop });
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
return out;
|
return out;
|
||||||
@@ -277,31 +288,51 @@ window.LightingModel = (() => {
|
|||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Volle render: elke gevellamp (per lichtrichting) en elke boeideel-spot
|
// Render: elke gevellamp (per lichtrichting), boeideel-spot en binnenspot
|
||||||
// wordt een echte SpotLight. Gevellampen staan net buiten het gevelvlak en
|
// wordt een echte SpotLight. Echte schaduw per lamp is te zwaar (één
|
||||||
// schijnen langs de gevel omhoog/omlaag; spots schijnen recht naar beneden.
|
// schaduwkaart per lamp; de browser kan er maar ~16), dus licht door muren
|
||||||
// spots = [{ x, z }] (mm), spotY = hoogte onderkant boeideel (mm);
|
// wordt geometrisch voorkomen:
|
||||||
// indoor = binnenspots [{ x, z, y }] (mm). Buitenlampen 15% minder fel dan
|
// - buitenlampen en boeideel-spots zijn half hun bundelhoek naar buiten
|
||||||
// eerst (was overdag te heftig).
|
// gekanteld: de binnenrand van de bundel loopt verticaal langs de gevel;
|
||||||
function buildLights3D(lamps, spots, spotY, indoor) {
|
// - binnenspots hebben een harde reikwijdte net voorbij de vloer
|
||||||
|
// (INDOOR_REACH), zodat ze niet tot de grond buiten reiken.
|
||||||
|
// spots = [{ x, z }] (mm, boeideel), spotY = onderkant boeideel (mm),
|
||||||
|
// indoor = [{ x, z, y, floorY }] (mm). o.outdoorFactor schaalt de buiten-
|
||||||
|
// lampen (overdag lager: dan vallen ze nauwelijks op).
|
||||||
|
const OUTDOOR = { lamp: 2.0, spot: 1.6, angle: 0.5 };
|
||||||
|
const INDOOR = { intensity: 4.0, angle: 1.0, reach: 1.12, decay: 0.6 };
|
||||||
|
const DAY_OUTDOOR_FACTOR = 0.35;
|
||||||
|
function buildLights3D(lamps, spots, spotY, indoor, o) {
|
||||||
const toM = 0.001;
|
const toM = 0.001;
|
||||||
|
const fo = (o && o.outdoorFactor !== undefined) ? o.outdoorFactor : 1;
|
||||||
const group = new THREE.Group();
|
const group = new THREE.Group();
|
||||||
const add = (x, y, z, dirY, intensity, angle, distance) => {
|
// Spot op (x, y, z) die naar (x + tx, y + ty, z + tz) schijnt.
|
||||||
const light = new THREE.SpotLight(0xffd9a0, intensity, distance, angle, 0.6, 1.5);
|
const add = (x, y, z, tx, ty, tz, intensity, angle, distance, decay) => {
|
||||||
|
const light = new THREE.SpotLight(0xffd9a0, intensity, distance, angle, 0.6, decay);
|
||||||
light.position.set(x, y, z);
|
light.position.set(x, y, z);
|
||||||
light.target.position.set(x, y + dirY * 2, z);
|
light.target.position.set(x + tx, y + ty, z + tz);
|
||||||
group.add(light);
|
group.add(light);
|
||||||
group.add(light.target);
|
group.add(light.target);
|
||||||
};
|
};
|
||||||
|
const tilt = Math.tan(OUTDOOR.angle); // bundelas half de bundelhoek naar buiten
|
||||||
lamps.forEach(l => {
|
lamps.forEach(l => {
|
||||||
const x = l.x * toM + l.normal.x * 0.12, z = l.z * toM + l.normal.z * 0.12, y = l.y * toM;
|
const x = l.x * toM + l.normal.x * 0.12, z = l.z * toM + l.normal.z * 0.12, y = l.y * toM;
|
||||||
if (l.direction !== 'up') add(x, y - 0.09, z, -1, 2.55, 0.55, 4.5);
|
const nx = l.normal.x * tilt, nz = l.normal.z * tilt;
|
||||||
if (l.direction !== 'down') add(x, y + 0.09, z, 1, 2.55, 0.55, 4.5);
|
if (l.direction !== 'up') add(x, y - 0.09, z, nx, -1, nz, OUTDOOR.lamp * fo, OUTDOOR.angle, 4.5, 1.5);
|
||||||
|
if (l.direction !== 'down') add(x, y + 0.09, z, nx, 1, nz, OUTDOOR.lamp * fo, OUTDOOR.angle, 4.5, 1.5);
|
||||||
|
});
|
||||||
|
// Boeideel-spots: naar buiten gekanteld (normaal van de dakrand; op een
|
||||||
|
// hoek diagonaal).
|
||||||
|
(spots || []).forEach(p => {
|
||||||
|
const n = p.normal || { x: 0, z: 0 }, len = Math.hypot(n.x, n.z) || 1;
|
||||||
|
add(p.x * toM, spotY * toM - 0.02, p.z * toM, n.x / len * tilt, -1, n.z / len * tilt, OUTDOOR.spot * fo, OUTDOOR.angle, 5.5, 1.5);
|
||||||
|
});
|
||||||
|
(indoor || []).forEach(p => {
|
||||||
|
const drop = (p.y - p.floorY) * toM; // plafond -> loopvlak
|
||||||
|
add(p.x * toM, p.y * toM - 0.02, p.z * toM, 0, -1, 0, INDOOR.intensity, INDOOR.angle, drop * INDOOR.reach, INDOOR.decay);
|
||||||
});
|
});
|
||||||
(spots || []).forEach(p => add(p.x * toM, spotY * toM - 0.02, p.z * toM, -1, 2.1, 0.6, 5.5));
|
|
||||||
(indoor || []).forEach(p => add(p.x * toM, p.y * toM - 0.02, p.z * toM, -1, 1.2, 0.7, 4));
|
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { DEFAULT_SETTINGS, MODES, DIRECTIONS, WALL_OVERRIDES, createDefaultUnitLighting, normalizeSettings, compute, computeIndoor, createMaterials, build3D, buildLights3D };
|
return { DEFAULT_SETTINGS, MODES, DIRECTIONS, WALL_OVERRIDES, createDefaultUnitLighting, DAY_OUTDOOR_FACTOR, normalizeSettings, compute, computeIndoor, createMaterials, build3D, buildLights3D };
|
||||||
})();
|
})();
|
||||||
|
|||||||
Reference in New Issue
Block a user