Skip to content

Commit 47168bf

Browse files
committed
[Release] Prepare release for 0.10.10
1 parent 790f688 commit 47168bf

File tree

145 files changed

+11962
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+11962
-2
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# Changelog
2+
## v0.10.10 - 2026-03-01
3+
### 🐞 Fixes
4+
- [Patch] Added SceneRootTransform system and tests (be46bad…)
5+
- [Patch] Implemented Octree-GPU ray picking (5b6e7c3…)
6+
- [Patch] Add ground picking system and update spatial input docs (44b1886…)
27
## v0.10.9 - 2026-02-27
38
### 🐞 Fixes
49
- [Patch] Added occlusion culling (ccbd522…)
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
id: materials
3+
title: Materials
4+
sidebar_position: 14
5+
---
6+
7+
# Using Materials in Untold Engine
8+
9+
The engine uses a PBR (Physically Based Rendering) material model. Each entity's mesh can contain one or more submeshes, and each submesh holds its own `Material`. You can read and write individual material properties at runtime using the functions below.
10+
11+
All material functions accept optional `meshIndex` and `submeshIndex` parameters (both default to `0`) so you can target a specific submesh when an entity contains more than one.
12+
13+
> **Note:** Every update function automatically refreshes static batching for the affected entity, so you do not need to do this manually.
14+
15+
---
16+
17+
## Base Color
18+
19+
The base color is stored as a `simd_float4` (RGBA). The `.w` component doubles as the opacity channel.
20+
21+
### Get Base Color
22+
23+
```swift
24+
let color = getMaterialBaseColor(entityId: entity)
25+
// color.x = red, color.y = green, color.z = blue, color.w = alpha
26+
```
27+
28+
### Set Base Color via SwiftUI Color
29+
30+
```swift
31+
updateMaterialColor(entityId: entity, color: .red)
32+
```
33+
34+
This converts the SwiftUI `Color` to RGBA internally. If the alpha is below `1.0`, the material automatically switches to `.blend` alpha mode.
35+
36+
---
37+
38+
## Roughness
39+
40+
Controls how rough or smooth a surface appears. A value of `0.0` is perfectly smooth (mirror-like reflections) and `1.0` is fully rough (diffuse).
41+
42+
### Get Roughness
43+
44+
```swift
45+
let roughness = getMaterialRoughness(entityId: entity)
46+
```
47+
48+
### Set Roughness
49+
50+
```swift
51+
updateMaterialRoughness(entityId: entity, roughness: 0.3)
52+
```
53+
54+
> When a roughness **texture** is present, the scalar value acts as a modulator (multiplied with the texture sample in the shader). If you remove the texture, the scalar value is used directly.
55+
56+
---
57+
58+
## Metallic
59+
60+
Controls how metallic a surface appears. `0.0` is fully dielectric (plastic, wood, etc.) and `1.0` is fully metallic.
61+
62+
### Get Metallic
63+
64+
```swift
65+
let metallic = getMaterialMetallic(entityId: entity)
66+
```
67+
68+
### Set Metallic
69+
70+
```swift
71+
updateMaterialMetallic(entityId: entity, metallic: 1.0)
72+
```
73+
74+
> Like roughness, the scalar value modulates the metallic texture when one is present.
75+
76+
---
77+
78+
## Emissive
79+
80+
Controls self-illumination. The value is a `simd_float3` (RGB) representing the emitted light color and intensity. A value of `.zero` means no emission.
81+
82+
### Get Emissive
83+
84+
```swift
85+
let emissive = getMaterialEmmissive(entityId: entity)
86+
```
87+
88+
### Set Emissive
89+
90+
```swift
91+
updateMaterialEmmisive(entityId: entity, emmissive: simd_float3(1.0, 0.5, 0.0))
92+
```
93+
94+
> **Spelling note:** The API currently uses `getMaterialEmmissive` / `updateMaterialEmmisive` (with double-m). Use these exact names when calling the functions.
95+
96+
---
97+
98+
## Alpha Mode
99+
100+
Determines how the renderer handles transparency for this material.
101+
102+
### Available Modes (`MaterialAlphaMode`)
103+
104+
- **`.opaque`** — Fully opaque. Alpha channel is ignored.
105+
- **`.mask`** — Binary transparency. Pixels with alpha below the cutoff are discarded; the rest are fully opaque. Useful for foliage, fences, etc.
106+
- **`.blend`** — Smooth alpha blending. Pixels are composited based on their alpha value.
107+
108+
### Get Alpha Mode
109+
110+
```swift
111+
let mode = getMaterialAlphaMode(entityId: entity) // returns MaterialAlphaMode
112+
```
113+
114+
### Set Alpha Mode
115+
116+
```swift
117+
updateMaterialAlphaMode(entityId: entity, mode: .blend)
118+
```
119+
120+
---
121+
122+
## Alpha Cutoff
123+
124+
Used only when the alpha mode is `.mask`. Pixels with alpha below this threshold are discarded. The value is clamped to `0.0 ... 1.0`. Default is `0.5`.
125+
126+
### Get Alpha Cutoff
127+
128+
```swift
129+
let cutoff = getMaterialAlphaCutoff(entityId: entity)
130+
```
131+
132+
### Set Alpha Cutoff
133+
134+
```swift
135+
updateMaterialAlphaCutoff(entityId: entity, cutoff: 0.3)
136+
```
137+
138+
---
139+
140+
## Opacity
141+
142+
A convenience layer over the base color's alpha channel (`.w`). The value is clamped to `0.0 ... 1.0`. Setting opacity below `1.0` automatically switches the alpha mode to `.blend`.
143+
144+
### Get Opacity
145+
146+
```swift
147+
let opacity = getMaterialOpacity(entityId: entity)
148+
```
149+
150+
### Set Opacity (all submeshes)
151+
152+
```swift
153+
updateMaterialOpacity(entityId: entity, opacity: 0.5)
154+
```
155+
156+
By default this applies to **every submesh** on the entity. To target a single submesh instead:
157+
158+
```swift
159+
updateMaterialOpacity(entityId: entity, opacity: 0.5, applyToAllSubmeshes: false)
160+
```
161+
162+
Or specify exact indices:
163+
164+
```swift
165+
updateMaterialOpacity(entityId: entity, opacity: 0.5, meshIndex: 0, submeshIndex: 1)
166+
```
167+
168+
---
169+
170+
## Quick Reference
171+
172+
- `getMaterialBaseColor(entityId:meshIndex:submeshIndex:)``simd_float4`
173+
- `updateMaterialColor(entityId:color:meshIndex:submeshIndex:)` — sets base color from SwiftUI `Color`
174+
- `getMaterialRoughness(entityId:meshIndex:submeshIndex:)``Float`
175+
- `updateMaterialRoughness(entityId:roughness:meshIndex:submeshIndex:)`
176+
- `getMaterialMetallic(entityId:meshIndex:submeshIndex:)``Float`
177+
- `updateMaterialMetallic(entityId:metallic:meshIndex:submeshIndex:)`
178+
- `getMaterialEmmissive(entityId:meshIndex:submeshIndex:)``simd_float3`
179+
- `updateMaterialEmmisive(entityId:emmissive:meshIndex:submeshIndex:)`
180+
- `getMaterialAlphaMode(entityId:meshIndex:submeshIndex:)``MaterialAlphaMode`
181+
- `updateMaterialAlphaMode(entityId:mode:meshIndex:submeshIndex:)`
182+
- `getMaterialAlphaCutoff(entityId:meshIndex:submeshIndex:)``Float`
183+
- `updateMaterialAlphaCutoff(entityId:cutoff:meshIndex:submeshIndex:)`
184+
- `getMaterialOpacity(entityId:meshIndex:submeshIndex:)``Float`
185+
- `updateMaterialOpacity(entityId:opacity:applyToAllSubmeshes:)`
186+
- `updateMaterialOpacity(entityId:opacity:meshIndex:submeshIndex:)`

docs/04-Engine Development/03-Engine Systems/UsingSpatialInput.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,40 @@ delta jitter can become visible.
235235

236236
------------------------------------------------------------------------
237237

238+
## Anchored Scene Drag Helper
239+
240+
For translating the **entire scene root** (rather than a single entity), use the anchored scene drag lifecycle:
241+
242+
``` swift
243+
func handleInput() {
244+
let state = InputSystem.shared.xrSpatialInputState
245+
246+
SpatialManipulationSystem.shared.processAnchoredSceneDragLifecycle(from: state)
247+
}
248+
```
249+
250+
This helper:
251+
252+
- Captures initial hand + scene root world positions on drag start
253+
- Applies absolute displacement from gesture start via `translateSceneTo`, keeping static batches intact
254+
- Cleans up session state on end/cancel
255+
256+
You can adjust movement speed with the `sensitivity` parameter (defaults to `1.0`):
257+
258+
``` swift
259+
SpatialManipulationSystem.shared.processAnchoredSceneDragLifecycle(from: state, sensitivity: 0.5)
260+
```
261+
262+
To manually end the drag (e.g. on a mode change), call:
263+
264+
``` swift
265+
SpatialManipulationSystem.shared.endAnchoredSceneDrag()
266+
```
267+
268+
Use this when panning an entire scene — for example, sliding a map, architectural model, or level layout in world space.
269+
270+
------------------------------------------------------------------------
271+
238272
## Two-Hand Zoom Signal (Coming soon)
239273

240274
Two hands pinching and moving closer/farther.
@@ -353,6 +387,13 @@ Use these helpers from `SpatialManipulationSystem.shared`:
353387
- `applyPinchDragIfNeeded(from:entityId:sensitivity:)`\
354388
Lower-level translation helper if you want full control.
355389

390+
- `processAnchoredSceneDragLifecycle(from:sensitivity:)`\
391+
Anchored drag for the entire scene root. Applies absolute
392+
displacement via `translateSceneTo`.
393+
394+
- `endAnchoredSceneDrag()`\
395+
Manually ends an in-progress anchored scene drag session.
396+
356397
- `applyTwoHandZoomIfNeeded(from:sensitivity:)`\
357398
Provides zoom delta signal. You must define what zoom means in your
358399
app.

docs/04-Engine Development/03-Engine Systems/UsingTransformSystem.md

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,32 @@ rotateTo(entityId: entity, rotation: simd_float4x4( /* matrix values */ ))
110110

111111
---
112112

113+
### Step 3: Translate the Entire Scene
114+
115+
These functions move the **scene root** without modifying individual entity transforms. Because per-entity transforms stay untouched, static batches remain intact and no rebatching is needed.
116+
117+
#### Move Scene to an Absolute Position
118+
119+
```swift
120+
translateSceneTo(position: simd_float3(10.0, 0.0, 5.0))
121+
```
122+
123+
#### Move Scene by a Relative Offset
124+
125+
```swift
126+
translateSceneBy(delta: simd_float3(1.0, 0.0, 0.0))
127+
```
128+
129+
Use these when you need to pan or reposition the entire world — for example, sliding a map or architectural model during a spatial drag gesture.
130+
131+
---
132+
113133
## Tips and Best Practices
114134
- Use Local Transformations for Hierarchies:
115135
- For example, a car’s wheels (children) should use local transforms relative to the car body (parent).
116136
- Combine Translations and Rotations:
117-
- Use translateTo or rotateTo to set an entity’s absolute position or rotation.
118-
- Use translateBy or rotateBy for incremental adjustments.
137+
- Use translateTo to set an entity's absolute position or rotation.
138+
- Use translateBy for incremental adjustments.
139+
- Use Scene-Level Translation for Batch-Safe Movement:
140+
- Use `translateSceneTo` / `translateSceneBy` instead of moving every entity individually.
141+
- This avoids breaking static batches and is ideal for spatial drag gestures on the whole scene.

0 commit comments

Comments
 (0)