Merge pull request #410 from pascalorg/feat/paint-slots-phase-4-uv-worldscale
feat(paint-slots): world-scale pool slab floor UVs + metre UV contract
This commit is contained in:
@@ -254,23 +254,12 @@ function generatePoolGeometry(slabNode: SlabNode): THREE.BufferGeometry {
|
|||||||
const positions: number[] = []
|
const positions: number[] = []
|
||||||
const uvs: number[] = []
|
const uvs: number[] = []
|
||||||
const indices: number[] = []
|
const indices: number[] = []
|
||||||
const bounds = new THREE.Box2()
|
|
||||||
|
|
||||||
for (const [x, z] of polygon) {
|
|
||||||
bounds.expandByPoint(new THREE.Vector2(x, z))
|
|
||||||
}
|
|
||||||
for (const hole of holePolygons) {
|
|
||||||
for (const [x, z] of hole) {
|
|
||||||
bounds.expandByPoint(new THREE.Vector2(x, z))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const floorWidth = Math.max(bounds.max.x - bounds.min.x, 0.001)
|
|
||||||
const floorHeight = Math.max(bounds.max.y - bounds.min.y, 0.001)
|
|
||||||
|
|
||||||
const pushFloorVertex = (x: number, y: number, z: number) => {
|
const pushFloorVertex = (x: number, y: number, z: number) => {
|
||||||
positions.push(x, y, z)
|
positions.push(x, y, z)
|
||||||
uvs.push((x - bounds.min.x) / floorWidth, (z - bounds.min.y) / floorHeight)
|
// Floor UVs in metres (shape-space x, -z), matching generatePositiveSlabGeometry's
|
||||||
|
// cap mapping so a finish tiles at the same world scale on every surface.
|
||||||
|
uvs.push(x, -z)
|
||||||
}
|
}
|
||||||
|
|
||||||
const pushWallVertex = (x: number, y: number, z: number, u: number, v: number) => {
|
const pushWallVertex = (x: number, y: number, z: number, u: number, v: number) => {
|
||||||
|
|||||||
@@ -80,3 +80,17 @@ The editor UI chrome is always dark (a fixed `document.body.classList.add('dark'
|
|||||||
## Adding a theme
|
## Adding a theme
|
||||||
|
|
||||||
Append a `SceneTheme` to `SCENE_THEMES` with all required fields. `clayTints` is a `Partial` — any role you omit falls back to the active `colorPreset`. The theme pickers (toolbar + community overlay) render a 2×2 swatch from `clayTints` over `background`, so populate at least `wall`/`roof`/`floor`/`glazing` for a good swatch.
|
Append a `SceneTheme` to `SCENE_THEMES` with all required fields. `clayTints` is a `Partial` — any role you omit falls back to the active `colorPreset`. The theme pickers (toolbar + community overlay) render a 2×2 swatch from `clayTints` over `background`, so populate at least `wall`/`roof`/`floor`/`glazing` for a good swatch.
|
||||||
|
|
||||||
|
## Texture world scale (UVs in metres)
|
||||||
|
|
||||||
|
Every procedural surface generates UVs in metres: 1 UV unit = 1 m.
|
||||||
|
|
||||||
|
This contract is shared by wall `systems/wall/wall-system.tsx` (`ExtrudeGeometry`), slab `systems/slab/slab-system.tsx` (`generatePositiveSlabGeometry`, and `generatePoolGeometry`), ceiling `systems/ceiling/ceiling-system.tsx`, roof `systems/roof/roof-system.tsx`, and chimney/dormer `nodes/src/chimney/geometry.ts`.
|
||||||
|
|
||||||
|
GLB item slots follow the same ~1 UV unit/m authoring convention, enforced by the slot validator's UV-presence check and the phase-6 Blender recipe. This is an authoring requirement, not a render-time correction.
|
||||||
|
|
||||||
|
A catalog material's `repeat` (`mapProperties.repeatX/repeatY` in `packages/core/src/material-library.ts`) is therefore a per-material world-scale setting: tiles per metre.
|
||||||
|
|
||||||
|
`repeat: 1` means 1 tile/m, `0.4` means one tile every 2.5 m, and `1.5` means 1.5 tiles/m.
|
||||||
|
|
||||||
|
Repeat is a property of the material, identical for every surface that uses it, never per-item or per-surface. Custom repeat values are intentional material scale, not per-surface hacks.
|
||||||
|
|||||||
Reference in New Issue
Block a user