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
@@ -4,7 +4,7 @@
|
||||
* Alle rechten voorbehouden. Gebruik uitsluitend met schriftelijke toestemming.
|
||||
* 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.
|
||||
|
||||
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 (lampsOn && parts && lampenVisible) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,9 +188,20 @@ window.LightingModel = (() => {
|
||||
const spots = [];
|
||||
if (s.mode === 'spots') {
|
||||
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 };
|
||||
}
|
||||
@@ -212,7 +223,7 @@ window.LightingModel = (() => {
|
||||
|
||||
// Binnenspots per unit. units = HouseModel-parts.units (rect, walls, roof.base),
|
||||
// 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) {
|
||||
const s = normalizeSettings(settings);
|
||||
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 };
|
||||
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;
|
||||
@@ -277,31 +288,51 @@ window.LightingModel = (() => {
|
||||
return group;
|
||||
}
|
||||
|
||||
// Volle render: elke gevellamp (per lichtrichting) en elke boeideel-spot
|
||||
// wordt een echte SpotLight. Gevellampen staan net buiten het gevelvlak en
|
||||
// schijnen langs de gevel omhoog/omlaag; spots schijnen recht naar beneden.
|
||||
// spots = [{ x, z }] (mm), spotY = hoogte onderkant boeideel (mm);
|
||||
// indoor = binnenspots [{ x, z, y }] (mm). Buitenlampen 15% minder fel dan
|
||||
// eerst (was overdag te heftig).
|
||||
function buildLights3D(lamps, spots, spotY, indoor) {
|
||||
// Render: elke gevellamp (per lichtrichting), boeideel-spot en binnenspot
|
||||
// wordt een echte SpotLight. Echte schaduw per lamp is te zwaar (één
|
||||
// schaduwkaart per lamp; de browser kan er maar ~16), dus licht door muren
|
||||
// wordt geometrisch voorkomen:
|
||||
// - buitenlampen en boeideel-spots zijn half hun bundelhoek naar buiten
|
||||
// gekanteld: de binnenrand van de bundel loopt verticaal langs de gevel;
|
||||
// - 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 fo = (o && o.outdoorFactor !== undefined) ? o.outdoorFactor : 1;
|
||||
const group = new THREE.Group();
|
||||
const add = (x, y, z, dirY, intensity, angle, distance) => {
|
||||
const light = new THREE.SpotLight(0xffd9a0, intensity, distance, angle, 0.6, 1.5);
|
||||
// Spot op (x, y, z) die naar (x + tx, y + ty, z + tz) schijnt.
|
||||
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.target.position.set(x, y + dirY * 2, z);
|
||||
light.target.position.set(x + tx, y + ty, z + tz);
|
||||
group.add(light);
|
||||
group.add(light.target);
|
||||
};
|
||||
const tilt = Math.tan(OUTDOOR.angle); // bundelas half de bundelhoek naar buiten
|
||||
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;
|
||||
if (l.direction !== 'up') add(x, y - 0.09, z, -1, 2.55, 0.55, 4.5);
|
||||
if (l.direction !== 'down') 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 !== '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 { 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