@marble.fun/track-catalog 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +15 -0
- package/assets.json +346 -0
- package/package.json +32 -0
- package/release.json +135 -0
- package/src/audio/game-audio-preference.ts +9 -0
- package/src/authoritative.ts +6 -0
- package/src/catalog.ts +1 -0
- package/src/index.ts +14 -0
- package/src/legacy-stock-catalog.ts +130 -0
- package/src/pages/lobby/lobby-types.ts +140 -0
- package/src/pages/lobby/marble-factory.ts +931 -0
- package/src/pages/play/race/egypt-elevator-blender.ts +159 -0
- package/src/pages/play/race/egypt-portal-frame.ts +382 -0
- package/src/pages/play/race/finish-detection.ts +1 -0
- package/src/pages/play/race/japanese-sakura-castle-support-blender.ts +510 -0
- package/src/pages/play/race/japanese-sakura-kawara-roof.ts +201 -0
- package/src/pages/play/race/japanese-sakura-portal-frame.ts +325 -0
- package/src/pages/play/race/jungle-portal-frame.ts +308 -0
- package/src/pages/play/race/jungle-temple-lift.ts +366 -0
- package/src/pages/play/race/marble-entity.ts +257 -0
- package/src/pages/play/race/marble-material.ts +20 -0
- package/src/pages/play/race/marble-race-engine.ts +2652 -0
- package/src/pages/play/race/path-pattern-layout.ts +142 -0
- package/src/pages/play/race/peg-obstacle-visual.ts +171 -0
- package/src/pages/play/race/physics-debug.ts +1 -0
- package/src/pages/play/race/physics-dry-run.ts +90 -0
- package/src/pages/play/race/portal-derived-elevator-skins.ts +729 -0
- package/src/pages/play/race/portal-pair-color.ts +20 -0
- package/src/pages/play/race/portal-proportions.ts +25 -0
- package/src/pages/play/race/portal-visual.ts +1108 -0
- package/src/pages/play/race/race-camera-director.ts +586 -0
- package/src/pages/play/race/race-camera-obstruction.ts +37 -0
- package/src/pages/play/race/race-camera-tour-planner.ts +274 -0
- package/src/pages/play/race/race-camera.ts +206 -0
- package/src/pages/play/race/race-completion.ts +5 -0
- package/src/pages/play/race/race-configuration.ts +57 -0
- package/src/pages/play/race/race-marble-focus-renderer.ts +134 -0
- package/src/pages/play/race/race-physics-profile.ts +7 -0
- package/src/pages/play/race/race-physics.ts +16 -0
- package/src/pages/play/race/race-playback.ts +41 -0
- package/src/pages/play/race/race-rolling-audio.ts +616 -0
- package/src/pages/play/race/race-simulation-renderer.ts +221 -0
- package/src/pages/play/race/race-terminal-checker-strip.ts +226 -0
- package/src/pages/play/race/race-transform-interpolation.ts +50 -0
- package/src/pages/play/race/race-types.ts +12 -0
- package/src/pages/play/race/rebound-visual.ts +70 -0
- package/src/pages/play/race/seeded-random.ts +23 -0
- package/src/pages/play/race/space-station-portal-frame.ts +275 -0
- package/src/pages/play/race/track-appearance-canopy.ts +946 -0
- package/src/pages/play/race/track-appearance-floor-runner.ts +206 -0
- package/src/pages/play/race/track-appearance-jungle-flower-hedge.ts +483 -0
- package/src/pages/play/race/track-appearance-rope-wall.ts +443 -0
- package/src/pages/play/race/track-appearance-sakura-bridge-fence.ts +305 -0
- package/src/pages/play/race/track-appearance-sakura-castle-wall.ts +1031 -0
- package/src/pages/play/race/track-appearance-space-station-wall.ts +497 -0
- package/src/pages/play/race/track-appearance-stone-block-shell.ts +517 -0
- package/src/pages/play/race/track-appearance-support.ts +983 -0
- package/src/pages/play/race/track-appearance-vampire-carved-wall.ts +545 -0
- package/src/pages/play/race/track-appearance-wall-terminal.ts +167 -0
- package/src/pages/play/race/track-course.ts +271 -0
- package/src/pages/play/race/track-definition.ts +443 -0
- package/src/pages/play/race/track-fence-architecture.ts +33 -0
- package/src/pages/play/race/track-floor-material-rules.ts +51 -0
- package/src/pages/play/race/track-mechanisms.ts +1350 -0
- package/src/pages/play/race/track-physics-surface.ts +6 -0
- package/src/pages/play/race/track-route-network.ts +9 -0
- package/src/pages/play/race/track-shadow-batching.ts +760 -0
- package/src/pages/play/race/track-surface-basis.ts +1 -0
- package/src/pages/play/race/track-surface-topology.ts +326 -0
- package/src/pages/play/race/track-world.ts +10181 -0
- package/src/pages/play/race/under-track-support-architecture.ts +122 -0
- package/src/pages/play/race/vortex-profile.ts +5 -0
- package/src/pages/play/race/vortex-water-effect.ts +863 -0
- package/src/pages/play/race/wild-west-mine-lift.ts +281 -0
- package/src/pages/play/race/wild-west-vortex-housing.ts +572 -0
- package/src/pages/track-lab/atlas-vortex-layout.ts +1 -0
- package/src/pages/track-lab/cone-field-layout.ts +1 -0
- package/src/pages/track-lab/conveyor-layout.ts +1 -0
- package/src/pages/track-lab/engine/canonical-track-assembly.ts +64 -0
- package/src/pages/track-lab/engine/editor-object-geometry.ts +170 -0
- package/src/pages/track-lab/engine/track-lab-connection-state.ts +123 -0
- package/src/pages/track-lab/engine/track-piece-visual.ts +1420 -0
- package/src/pages/track-lab/flipper-bank-layout.ts +1 -0
- package/src/pages/track-lab/flipper-component.ts +127 -0
- package/src/pages/track-lab/rising-wall-layout.ts +1 -0
- package/src/pages/track-lab/simple-obstacle-layout.ts +1 -0
- package/src/pages/track-lab/track-piece-layout.ts +28 -0
- package/src/pages/track-lab/track-runtime-adapter.ts +1152 -0
- package/src/three/geometry-attribute-aliases.ts +24 -0
- package/src/three/geometry-detail.ts +36 -0
- package/src/three/homepage-marble-geometry.ts +15 -0
- package/src/three/japanese-sakura-appearance.ts +252 -0
- package/src/three/jungle-flower-hedge-appearance.ts +7 -0
- package/src/three/jungle-temple-appearance.ts +5 -0
- package/src/three/low-quality-scene-renderer.ts +132 -0
- package/src/three/marble-sphere-geometry.ts +13 -0
- package/src/three/mobile-rendering-budget.ts +11 -0
- package/src/three/painted-valley-appearance.ts +270 -0
- package/src/three/railroad-appearance.ts +71 -0
- package/src/three/renderer-resize.ts +32 -0
- package/src/three/rope-wall-appearance.ts +91 -0
- package/src/three/rugged-track-appearance.ts +2 -0
- package/src/three/scene-lighting.ts +183 -0
- package/src/three/scene-shader-preparation.ts +64 -0
- package/src/three/scene-theme-controller.ts +461 -0
- package/src/three/shadow-shader-preparation.ts +162 -0
- package/src/three/shared-obstacle-metal.ts +44 -0
- package/src/three/soft-additive-particles.ts +57 -0
- package/src/three/space-station-appearance.ts +213 -0
- package/src/three/static-track-batched-mesh.ts +132 -0
- package/src/three/stone-track-shell-appearance.ts +12 -0
- package/src/three/theme-ambience-controller.ts +226 -0
- package/src/three/theme-asset-cache.ts +120 -0
- package/src/three/theme-audio-preference.ts +43 -0
- package/src/three/theme-catalog.ts +1457 -0
- package/src/three/theme-material-assets.ts +258 -0
- package/src/three/theme-material-ktx2-manifest.ts +190 -0
- package/src/three/theme-material-registry.ts +1952 -0
- package/src/three/theme-world-factory.ts +590 -0
- package/src/three/track-connector-batch.ts +125 -0
- package/src/three/track-material-continuity.ts +442 -0
- package/src/three/track-theme.ts +535 -0
- package/src/three/vampire-castle-appearance.ts +258 -0
- package/src/three/visual-frame-pacing.ts +19 -0
- package/src/three/visual-geometry.ts +120 -0
- package/src/three/visual-quality.ts +83 -0
- package/src/three/water-appearance.ts +29 -0
- package/src/three/wild-west-sand-appearance.ts +2 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { geometryDetailProfile } from '../../../three/geometry-detail'
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
|
|
4
|
+
import { VisualLatheGeometry, VisualExtrudeGeometry, VisualBoxGeometry } from '../../../three/visual-geometry'
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
canonicalWallFrameAt,
|
|
8
|
+
resampleCanonicalWallRun,
|
|
9
|
+
type CanonicalWallRun,
|
|
10
|
+
type RawWallFrame,
|
|
11
|
+
} from './track-surface-topology'
|
|
12
|
+
import { woodenFenceHeight, woodenFencePostCount, WOODEN_FENCE_HEIGHT_RATIO } from './track-fence-architecture'
|
|
13
|
+
|
|
14
|
+
export type SakuraBridgeFencePathFrame = RawWallFrame
|
|
15
|
+
export type SakuraBridgeFencePathRun = CanonicalWallRun
|
|
16
|
+
|
|
17
|
+
export interface SakuraBridgeFenceMaterials {
|
|
18
|
+
timber: THREE.Material
|
|
19
|
+
hardware: THREE.Material
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const RAIL_SAMPLE_SPACING = 1.2 * geometryDetailProfile.ribbonTolerance
|
|
23
|
+
const POST_WIDTH_RATIO = 0.15
|
|
24
|
+
const POST_DEPTH_RATIO = 0.17
|
|
25
|
+
const BALUSTER_WIDTH_RATIO = 0.08
|
|
26
|
+
const BALUSTER_DEPTH_RATIO = 0.065
|
|
27
|
+
const FINIAL_REFERENCE_POST_HEIGHT = 1.28
|
|
28
|
+
const FINIAL_HEIGHT = 0.325
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Adds an open vermilion Japanese bridge fence over the unchanged wall
|
|
32
|
+
* collider: lacquered timber posts and rails with gunmetal giboshi finials.
|
|
33
|
+
*/
|
|
34
|
+
export function addSakuraBridgeFenceVisual(
|
|
35
|
+
root: THREE.Group,
|
|
36
|
+
id: string,
|
|
37
|
+
runs: readonly SakuraBridgeFencePathRun[],
|
|
38
|
+
wallHeight: number,
|
|
39
|
+
materials: SakuraBridgeFenceMaterials,
|
|
40
|
+
): THREE.Group | undefined {
|
|
41
|
+
if (wallHeight <= 0.3) return undefined
|
|
42
|
+
|
|
43
|
+
const group = new THREE.Group()
|
|
44
|
+
group.name = `${id}-sakura-vermilion-bridge-fence`
|
|
45
|
+
group.userData.themeOnly = 'japanese-sakura-lake'
|
|
46
|
+
group.userData.decorative = true
|
|
47
|
+
group.userData.visualOnly = true
|
|
48
|
+
group.userData.appearance = 'japanese-sakura-vermilion-bridge-fence'
|
|
49
|
+
group.userData.constructionContract = 'japanese-sakura-vermilion-bridge-fence-v5'
|
|
50
|
+
group.userData.wallHeightRatio = WOODEN_FENCE_HEIGHT_RATIO
|
|
51
|
+
group.userData.balustersPerPanel = 3
|
|
52
|
+
group.userData.balusterWidthRatio = BALUSTER_WIDTH_RATIO
|
|
53
|
+
group.userData.balusterDepthRatio = BALUSTER_DEPTH_RATIO
|
|
54
|
+
|
|
55
|
+
const postMatrices: THREE.Matrix4[] = []
|
|
56
|
+
const railMatrices: THREE.Matrix4[] = []
|
|
57
|
+
const balusterMatrices: THREE.Matrix4[] = []
|
|
58
|
+
const knobMatrices: THREE.Matrix4[] = []
|
|
59
|
+
const ownedPostPositions: THREE.Vector3[] = []
|
|
60
|
+
let suppressedConnectedPostCount = 0
|
|
61
|
+
let runCount = 0
|
|
62
|
+
|
|
63
|
+
for (const run of runs) {
|
|
64
|
+
if (run.frames.length < 2) continue
|
|
65
|
+
const canonicalRun = run
|
|
66
|
+
const frames = resampleCanonicalWallRun(canonicalRun, RAIL_SAMPLE_SPACING).frames
|
|
67
|
+
const totalLength = canonicalRun.length
|
|
68
|
+
if (totalLength <= 0.001) continue
|
|
69
|
+
runCount += 1
|
|
70
|
+
|
|
71
|
+
const overallFenceHeight = woodenFenceHeight(wallHeight)
|
|
72
|
+
// The finial is part of the silhouette, so reserve its scaled height
|
|
73
|
+
// inside the shared fence-height envelope rather than adding it on top.
|
|
74
|
+
const postHeight = overallFenceHeight / (1 + FINIAL_HEIGHT / FINIAL_REFERENCE_POST_HEIGHT)
|
|
75
|
+
const postCount = woodenFencePostCount(totalLength, overallFenceHeight)
|
|
76
|
+
for (let postIndex = 0; postIndex < postCount; postIndex += 1) {
|
|
77
|
+
const distance = (postIndex / (postCount - 1)) * totalLength
|
|
78
|
+
const frame = canonicalWallFrameAt(canonicalRun, distance)
|
|
79
|
+
// A connected run never owns its start post. At an ordinary connector
|
|
80
|
+
// the incoming neighbour owns it; at a T-junction the straight receiver
|
|
81
|
+
// owns the single corner post while the circular branch rails terminate
|
|
82
|
+
// against it. This prevents doubled posts and paired finials.
|
|
83
|
+
if (postIndex === 0 && run.startOwnership === 'connected') {
|
|
84
|
+
suppressedConnectedPostCount += 1
|
|
85
|
+
continue
|
|
86
|
+
}
|
|
87
|
+
if (ownedPostPositions.some(position => position.distanceToSquared(frame.base) <= 0.025 * 0.025)) {
|
|
88
|
+
suppressedConnectedPostCount += 1
|
|
89
|
+
continue
|
|
90
|
+
}
|
|
91
|
+
ownedPostPositions.push(frame.base.clone())
|
|
92
|
+
const worldUp = new THREE.Vector3(0, 1, 0)
|
|
93
|
+
const rotation = verticalFrameQuaternion(frame)
|
|
94
|
+
postMatrices.push(
|
|
95
|
+
new THREE.Matrix4().compose(
|
|
96
|
+
frame.base.clone().addScaledVector(worldUp, postHeight / 2 - 0.03),
|
|
97
|
+
rotation,
|
|
98
|
+
new THREE.Vector3(postHeight * POST_WIDTH_RATIO, postHeight, postHeight * POST_DEPTH_RATIO),
|
|
99
|
+
),
|
|
100
|
+
)
|
|
101
|
+
knobMatrices.push(
|
|
102
|
+
new THREE.Matrix4().compose(
|
|
103
|
+
frame.base.clone().addScaledVector(worldUp, postHeight - 0.03),
|
|
104
|
+
rotation,
|
|
105
|
+
new THREE.Vector3(1, 1, 1).multiplyScalar(postHeight / FINIAL_REFERENCE_POST_HEIGHT),
|
|
106
|
+
),
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (let panelIndex = 0; panelIndex < postCount - 1; panelIndex += 1) {
|
|
111
|
+
const panelStart = (panelIndex / (postCount - 1)) * totalLength
|
|
112
|
+
const panelEnd = ((panelIndex + 1) / (postCount - 1)) * totalLength
|
|
113
|
+
const balusterCount = 3
|
|
114
|
+
for (let balusterIndex = 0; balusterIndex < balusterCount; balusterIndex += 1) {
|
|
115
|
+
const distance = THREE.MathUtils.lerp(panelStart, panelEnd, (balusterIndex + 1) / 4)
|
|
116
|
+
const frame = canonicalWallFrameAt(canonicalRun, distance)
|
|
117
|
+
const bottomRailTop = postHeight * (0.16 + 0.13 / 2)
|
|
118
|
+
const middleRailBottom = postHeight * (0.55 - 0.13 / 2)
|
|
119
|
+
const balusterHeight = Math.max(0.16, middleRailBottom - bottomRailTop)
|
|
120
|
+
balusterMatrices.push(
|
|
121
|
+
new THREE.Matrix4().compose(
|
|
122
|
+
frame.base.clone().add(new THREE.Vector3(0, (bottomRailTop + middleRailBottom) / 2 - 0.03, 0)),
|
|
123
|
+
verticalFrameQuaternion(frame),
|
|
124
|
+
new THREE.Vector3(
|
|
125
|
+
postHeight * BALUSTER_WIDTH_RATIO,
|
|
126
|
+
balusterHeight,
|
|
127
|
+
postHeight * BALUSTER_DEPTH_RATIO,
|
|
128
|
+
),
|
|
129
|
+
),
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
for (let index = 0; index < frames.length - 1; index += 1) {
|
|
135
|
+
const start = frames[index]!
|
|
136
|
+
const end = frames[index + 1]!
|
|
137
|
+
const outward = start.outward.clone().add(end.outward).normalize()
|
|
138
|
+
for (const [heightFraction, heightRatio, depthRatio] of [
|
|
139
|
+
[0.16, 0.13, 0.11],
|
|
140
|
+
[0.55, 0.13, 0.11],
|
|
141
|
+
[0.84, 0.12, 0.11],
|
|
142
|
+
] as const) {
|
|
143
|
+
const startPoint = start.base.clone().add(new THREE.Vector3(0, postHeight * heightFraction - 0.03, 0))
|
|
144
|
+
const endPoint = end.base.clone().add(new THREE.Vector3(0, postHeight * heightFraction - 0.03, 0))
|
|
145
|
+
appendRailMatrix(
|
|
146
|
+
railMatrices,
|
|
147
|
+
startPoint,
|
|
148
|
+
endPoint,
|
|
149
|
+
outward,
|
|
150
|
+
postHeight * heightRatio,
|
|
151
|
+
postHeight * depthRatio,
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (runCount === 0) return undefined
|
|
158
|
+
if (postMatrices.length > 0) {
|
|
159
|
+
const geometry = useAuthoredUv(new VisualBoxGeometry(1, 1, 1, 3, 0.12))
|
|
160
|
+
geometry.name = 'sakura-bridge-chunky-post-geometry'
|
|
161
|
+
group.add(instancedBatch(`${id}-sakura-bridge-posts`, geometry, materials.timber, postMatrices))
|
|
162
|
+
}
|
|
163
|
+
if (railMatrices.length > 0) {
|
|
164
|
+
const geometry = useAuthoredUv(createProfiledRailGeometry())
|
|
165
|
+
geometry.name = 'sakura-bridge-profiled-longitudinal-rail-geometry'
|
|
166
|
+
group.add(instancedBatch(`${id}-sakura-bridge-rails`, geometry, materials.timber, railMatrices))
|
|
167
|
+
}
|
|
168
|
+
if (balusterMatrices.length > 0) {
|
|
169
|
+
const geometry = useAuthoredUv(new VisualBoxGeometry(1, 1, 1, 3, 0.12))
|
|
170
|
+
geometry.name = 'sakura-bridge-lower-panel-baluster-geometry'
|
|
171
|
+
group.add(instancedBatch(`${id}-sakura-bridge-balusters`, geometry, materials.timber, balusterMatrices))
|
|
172
|
+
}
|
|
173
|
+
if (knobMatrices.length > 0) {
|
|
174
|
+
group.add(instancedBatch(`${id}-sakura-bridge-gunmetal-knobs`, createGiboshiGeometry(), materials.hardware, knobMatrices))
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
group.userData.runCount = runCount
|
|
178
|
+
group.userData.postCount = postMatrices.length
|
|
179
|
+
group.userData.railCount = railMatrices.length
|
|
180
|
+
group.userData.balusterCount = balusterMatrices.length
|
|
181
|
+
group.userData.knobCount = knobMatrices.length
|
|
182
|
+
group.userData.suppressedConnectedPostCount = suppressedConnectedPostCount
|
|
183
|
+
group.userData.connectedPostOwnership = 'incoming-or-t-receiver'
|
|
184
|
+
root.add(group)
|
|
185
|
+
return group
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function appendRailMatrix(
|
|
189
|
+
target: THREE.Matrix4[],
|
|
190
|
+
start: THREE.Vector3,
|
|
191
|
+
end: THREE.Vector3,
|
|
192
|
+
outward: THREE.Vector3,
|
|
193
|
+
height: number,
|
|
194
|
+
depth: number,
|
|
195
|
+
): void {
|
|
196
|
+
const direction = end.clone().sub(start)
|
|
197
|
+
const length = direction.length()
|
|
198
|
+
if (length <= 0.001) return
|
|
199
|
+
const xAxis = direction.normalize()
|
|
200
|
+
const zAxis = outward.clone().addScaledVector(xAxis, -outward.dot(xAxis))
|
|
201
|
+
if (zAxis.lengthSq() < 0.000_001) return
|
|
202
|
+
zAxis.normalize()
|
|
203
|
+
const yAxis = new THREE.Vector3().crossVectors(zAxis, xAxis).normalize()
|
|
204
|
+
const rotation = new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(xAxis, yAxis, zAxis))
|
|
205
|
+
target.push(
|
|
206
|
+
new THREE.Matrix4().compose(
|
|
207
|
+
start.clone().lerp(end, 0.5),
|
|
208
|
+
rotation,
|
|
209
|
+
new THREE.Vector3(length + 0.035, height, depth),
|
|
210
|
+
),
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function verticalFrameQuaternion(frame: SakuraBridgeFencePathFrame): THREE.Quaternion {
|
|
215
|
+
const yAxis = new THREE.Vector3(0, 1, 0)
|
|
216
|
+
const xAxis = frame.tangent.clone().addScaledVector(yAxis, -frame.tangent.dot(yAxis))
|
|
217
|
+
if (xAxis.lengthSq() < 0.000_001) xAxis.set(1, 0, 0)
|
|
218
|
+
xAxis.normalize()
|
|
219
|
+
const zAxis = new THREE.Vector3().crossVectors(xAxis, yAxis).normalize()
|
|
220
|
+
xAxis.crossVectors(yAxis, zAxis).normalize()
|
|
221
|
+
return new THREE.Quaternion().setFromRotationMatrix(new THREE.Matrix4().makeBasis(xAxis, yAxis, zAxis))
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function createGiboshiGeometry(): THREE.LatheGeometry {
|
|
225
|
+
const profile = [
|
|
226
|
+
new THREE.Vector2(0, 0),
|
|
227
|
+
new THREE.Vector2(0.11, 0),
|
|
228
|
+
new THREE.Vector2(0.125, 0.012),
|
|
229
|
+
new THREE.Vector2(0.125, 0.03),
|
|
230
|
+
new THREE.Vector2(0.108, 0.042),
|
|
231
|
+
new THREE.Vector2(0.124, 0.052),
|
|
232
|
+
new THREE.Vector2(0.124, 0.07),
|
|
233
|
+
new THREE.Vector2(0.1, 0.083),
|
|
234
|
+
new THREE.Vector2(0.094, 0.098),
|
|
235
|
+
new THREE.Vector2(0.122, 0.132),
|
|
236
|
+
new THREE.Vector2(0.137, 0.17),
|
|
237
|
+
new THREE.Vector2(0.126, 0.195),
|
|
238
|
+
new THREE.Vector2(0.105, 0.222),
|
|
239
|
+
new THREE.Vector2(0.075, 0.255),
|
|
240
|
+
new THREE.Vector2(0.045, 0.282),
|
|
241
|
+
new THREE.Vector2(0.018, 0.307),
|
|
242
|
+
new THREE.Vector2(0.005, 0.319),
|
|
243
|
+
new THREE.Vector2(0, 0.325),
|
|
244
|
+
]
|
|
245
|
+
const geometry = new VisualLatheGeometry([0, 1, 3, 8, 10, 12, 15, 17].map(index => profile[index]!), 32)
|
|
246
|
+
geometry.name = 'sakura-bridge-gunmetal-giboshi-geometry-v3'
|
|
247
|
+
geometry.userData.profile = 'compact-two-ring-long-taper-giboshi'
|
|
248
|
+
return geometry
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function createProfiledRailGeometry(): THREE.ExtrudeGeometry {
|
|
252
|
+
const profile = new THREE.Shape()
|
|
253
|
+
profile.moveTo(-0.5, -0.32)
|
|
254
|
+
profile.quadraticCurveTo(-0.5, -0.5, -0.32, -0.5)
|
|
255
|
+
profile.lineTo(0.16, -0.5)
|
|
256
|
+
profile.quadraticCurveTo(0.43, -0.5, 0.53, -0.29)
|
|
257
|
+
profile.quadraticCurveTo(0.64, 0, 0.53, 0.29)
|
|
258
|
+
profile.quadraticCurveTo(0.43, 0.5, 0.16, 0.5)
|
|
259
|
+
profile.lineTo(-0.32, 0.5)
|
|
260
|
+
profile.quadraticCurveTo(-0.5, 0.5, -0.5, 0.32)
|
|
261
|
+
profile.closePath()
|
|
262
|
+
const geometry = new VisualExtrudeGeometry(profile, {
|
|
263
|
+
depth: 1,
|
|
264
|
+
steps: 1,
|
|
265
|
+
curveSegments: 5,
|
|
266
|
+
bevelEnabled: false,
|
|
267
|
+
})
|
|
268
|
+
geometry.rotateY(-Math.PI / 2)
|
|
269
|
+
geometry.translate(0.5, 0, 0)
|
|
270
|
+
geometry.computeVertexNormals()
|
|
271
|
+
geometry.userData.profile = 'flat-rear-crowned-fascia-bullnose'
|
|
272
|
+
geometry.userData.grainDirection = 'longitudinal'
|
|
273
|
+
return geometry
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function useAuthoredUv<T extends THREE.BufferGeometry>(geometry: T): T {
|
|
277
|
+
const uv = geometry.getAttribute('uv')
|
|
278
|
+
const authored = new Float32Array(uv.count * 4)
|
|
279
|
+
for (let index = 0; index < uv.count; index += 1) authored[index * 4 + 2] = 1
|
|
280
|
+
geometry.setAttribute('themeNetUv', new THREE.BufferAttribute(authored, 4))
|
|
281
|
+
geometry.setAttribute('uv1', uv.clone())
|
|
282
|
+
geometry.userData.textureMapping = 'authored-aligned-pbr'
|
|
283
|
+
return geometry
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
function instancedBatch(
|
|
288
|
+
name: string,
|
|
289
|
+
geometry: THREE.BufferGeometry,
|
|
290
|
+
material: THREE.Material,
|
|
291
|
+
matrices: readonly THREE.Matrix4[],
|
|
292
|
+
): THREE.InstancedMesh {
|
|
293
|
+
const mesh = new THREE.InstancedMesh(geometry, material, matrices.length)
|
|
294
|
+
mesh.name = name
|
|
295
|
+
mesh.userData.themeOnly = 'japanese-sakura-lake'
|
|
296
|
+
mesh.userData.decorative = true
|
|
297
|
+
mesh.userData.visualOnly = true
|
|
298
|
+
mesh.castShadow = true
|
|
299
|
+
mesh.receiveShadow = true
|
|
300
|
+
matrices.forEach((matrix, index) => mesh.setMatrixAt(index, matrix))
|
|
301
|
+
mesh.instanceMatrix.needsUpdate = true
|
|
302
|
+
mesh.computeBoundingBox()
|
|
303
|
+
mesh.computeBoundingSphere()
|
|
304
|
+
return mesh
|
|
305
|
+
}
|