Qualitaetssprung: ebene Belaege, echte Bauteile, Sichtschutz
Deploy App / deploy (push) Successful in 49s
Deploy App / deploy (push) Successful in 49s
Nach der Plankontrolle ueberarbeitet: - Belaege sind eben. Je Belag wird aus den Hoehenkoten eine Ebene bestimmt (Gefaelle <= 5 %, am Kotenschwerpunkt aufgehaengt, nur Koten derselben Gelaendezone). Das Raster wird darauf gezwungen und dort nicht geglaettet. Jeder Belag bekommt eine senkrechte Sichtkante zum Gelaende. - Mauern sind Bauteile: Travertin-Schichtmauerwerk mit versetzten Stossfugen und Abdeckplatte, einzelne Winkelelemente mit Fussplatte, Ortbeton in Schaltafelfeldern. - Sichtschutz: die Eibenreihen des Plans werden zu geschnittenen Hecken verkettet, ebenso die Ligusterhecke. Lamellenwand im Planrhythmus. - Der Plan zeichnet die Travertinplatten 40x60 einzeln im Dekorkies - jetzt 30 erhabene Platten an den Planpositionen statt geschlossenem Belag. - Normalmaps aus dem Fugenbild fuer Platten, Pflaster, Holzschalung und Laub. - Nachbarhaus Zollet richtig platziert (stand auf dem Nachbargarten) und wie Haus 9a ausgebildet. Behobene Fehler: boxGeometry erzeugte Seiten und Deckel mit umgekehrtem Wickelsinn - saemtliche Boxen waren innen nach aussen gekehrt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+120
-5
@@ -218,9 +218,11 @@ export function boxGeometry(
|
||||
[cx + u * ca - v * sa, y, cz + u * sa + v * ca];
|
||||
const hw = w / 2, hd = d / 2;
|
||||
const s = 1 / tile;
|
||||
const faces: [Vec2, Vec2, number][] = [
|
||||
[[-hw, -hd], [hw, -hd], 1], [[hw, -hd], [hw, hd], 1],
|
||||
[[hw, hd], [-hw, hd], 1], [[-hw, hd], [-hw, -hd], 1],
|
||||
// Umlauf im Uhrzeigersinn in (u, v). Damit zeigen die Flaechennormalen nach
|
||||
// aussen - andersherum sieht man in die Box hinein.
|
||||
const faces: [Vec2, Vec2][] = [
|
||||
[[-hw, -hd], [-hw, hd]], [[-hw, hd], [hw, hd]],
|
||||
[[hw, hd], [hw, -hd]], [[hw, -hd], [-hw, -hd]],
|
||||
];
|
||||
let uRun = 0;
|
||||
for (const [p0, p1] of faces) {
|
||||
@@ -232,9 +234,13 @@ export function boxGeometry(
|
||||
uv.push(uRun * s, y0 * s, (uRun + len) * s, y1 * s, uRun * s, y1 * s);
|
||||
uRun += len;
|
||||
}
|
||||
// Deckel
|
||||
// Deckel, ebenfalls nach aussen (oben) gewickelt
|
||||
const t0 = P(-hw, -hd, y1), t1 = P(hw, -hd, y1), t2 = P(hw, hd, y1), t3 = P(-hw, hd, y1);
|
||||
pos.push(...t0, ...t1, ...t2, ...t0, ...t2, ...t3);
|
||||
pos.push(...t0, ...t3, ...t2, ...t0, ...t2, ...t1);
|
||||
uv.push(0, 0, 0, d * s, w * s, d * s, 0, 0, w * s, d * s, w * s, 0);
|
||||
// Boden, damit die Box auch von unten geschlossen ist
|
||||
const b0 = P(-hw, -hd, y0), b1 = P(hw, -hd, y0), b2 = P(hw, hd, y0), b3 = P(-hw, hd, y0);
|
||||
pos.push(...b0, ...b1, ...b2, ...b0, ...b2, ...b3);
|
||||
uv.push(0, 0, w * s, 0, w * s, d * s, 0, 0, w * s, d * s, 0, d * s);
|
||||
const g = new BufferGeometry();
|
||||
g.setAttribute('position', new BufferAttribute(new Float32Array(pos), 3));
|
||||
@@ -242,3 +248,112 @@ export function boxGeometry(
|
||||
g.computeVertexNormals();
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ebener Belag: das Polygon liegt exakt in der Ebene a*x + b*z + c.
|
||||
* Gebaute Flaechen sind eben - sie duerfen dem Gelaende nicht folgen.
|
||||
*/
|
||||
export function planarSurfaceGeometry(
|
||||
polygon: Vec2[],
|
||||
plane: [number, number, number],
|
||||
tile: number,
|
||||
lift = 0,
|
||||
): BufferGeometry {
|
||||
const [a, b, c] = plane;
|
||||
const tris = refine(triangulate(polygon), 1.6);
|
||||
const pos = new Float32Array(tris.length * 9);
|
||||
const uv = new Float32Array(tris.length * 6);
|
||||
let p = 0, u = 0;
|
||||
for (const t of tris) {
|
||||
for (const [x, z] of t) {
|
||||
pos[p++] = x;
|
||||
pos[p++] = a * x + b * z + c + lift;
|
||||
pos[p++] = z;
|
||||
uv[u++] = x / tile;
|
||||
uv[u++] = -z / tile;
|
||||
}
|
||||
}
|
||||
const g = new BufferGeometry();
|
||||
g.setAttribute('position', new BufferAttribute(pos, 3));
|
||||
g.setAttribute('uv', new BufferAttribute(uv, 2));
|
||||
g.computeVertexNormals();
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sichtkante eines Belags: senkrechtes Band von der Belagsoberkante hinunter
|
||||
* bis unter das Gelaende. Erst damit wirkt eine Terrasse wie gebaut und nicht
|
||||
* wie aufgemalt.
|
||||
*/
|
||||
export function surfaceEdgeGeometry(
|
||||
polygon: Vec2[],
|
||||
topAt: (x: number, z: number) => number,
|
||||
bottomAt: (x: number, z: number) => number,
|
||||
tile: number,
|
||||
step = 0.4,
|
||||
): BufferGeometry {
|
||||
const pos: number[] = [];
|
||||
const uv: number[] = [];
|
||||
let run = 0;
|
||||
const s = 1 / tile;
|
||||
const n = polygon.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
const [ax, az] = polygon[i];
|
||||
const [bx, bz] = polygon[(i + 1) % n];
|
||||
const len = Math.hypot(bx - ax, bz - az);
|
||||
const parts = Math.max(1, Math.round(len / step));
|
||||
for (let k = 0; k < parts; k++) {
|
||||
const t0 = k / parts, t1 = (k + 1) / parts;
|
||||
const x0 = ax + (bx - ax) * t0, z0 = az + (bz - az) * t0;
|
||||
const x1 = ax + (bx - ax) * t1, z1 = az + (bz - az) * t1;
|
||||
const ty0 = topAt(x0, z0), ty1 = topAt(x1, z1);
|
||||
const by0 = Math.min(bottomAt(x0, z0), ty0 - 0.012);
|
||||
const by1 = Math.min(bottomAt(x1, z1), ty1 - 0.012);
|
||||
const u0 = run, u1 = run + len / parts;
|
||||
// Aussenseite: Polygon laeuft im Gegenuhrzeigersinn, also liegt die
|
||||
// Sichtseite rechts der Laufrichtung.
|
||||
pos.push(x0, ty0, z0, x0, by0, z0, x1, by1, z1);
|
||||
uv.push(u0 * s, ty0 * s, u0 * s, by0 * s, u1 * s, by1 * s);
|
||||
pos.push(x0, ty0, z0, x1, by1, z1, x1, ty1, z1);
|
||||
uv.push(u0 * s, ty0 * s, u1 * s, by1 * s, u1 * s, ty1 * s);
|
||||
run = u1;
|
||||
}
|
||||
}
|
||||
const g = new BufferGeometry();
|
||||
g.setAttribute('position', new BufferAttribute(new Float32Array(pos), 3));
|
||||
g.setAttribute('uv', new BufferAttribute(new Float32Array(uv), 2));
|
||||
g.computeVertexNormals();
|
||||
return g;
|
||||
}
|
||||
|
||||
/**
|
||||
* Metallband: schmales Stahlband entlang eines Polygonrandes, wie es der Plan
|
||||
* zwischen Kies, Rasen und Beeten zeigt.
|
||||
*/
|
||||
export function edgingGeometry(
|
||||
polygon: Vec2[],
|
||||
topAt: (x: number, z: number) => number,
|
||||
thickness = 0.005,
|
||||
proud = 0.022,
|
||||
depth = 0.12,
|
||||
): BufferGeometry {
|
||||
const parts: BufferGeometry[] = [];
|
||||
const n = polygon.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
const [ax, az] = polygon[i];
|
||||
const [bx, bz] = polygon[(i + 1) % n];
|
||||
const len = Math.hypot(bx - ax, bz - az);
|
||||
if (len < 0.12) continue;
|
||||
const steps = Math.max(1, Math.round(len / 1.2));
|
||||
for (let k = 0; k < steps; k++) {
|
||||
const t0 = k / steps, t1 = (k + 1) / steps;
|
||||
const x0 = ax + (bx - ax) * t0, z0 = az + (bz - az) * t0;
|
||||
const x1 = ax + (bx - ax) * t1, z1 = az + (bz - az) * t1;
|
||||
const cx = (x0 + x1) / 2, cz = (z0 + z1) / 2;
|
||||
const y = topAt(cx, cz);
|
||||
const ang = (Math.atan2(z1 - z0, x1 - x0) * 180) / Math.PI;
|
||||
parts.push(boxGeometry(cx, cz, len / steps + 0.004, thickness, y + proud - depth, y + proud, ang, 1));
|
||||
}
|
||||
}
|
||||
return parts.length ? mergeGeometries(parts) : new BufferGeometry();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user