topazcube 0.1.30 → 0.1.33
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.txt +0 -0
- package/README.md +0 -0
- package/dist/Renderer.cjs +18200 -0
- package/dist/Renderer.cjs.map +1 -0
- package/dist/Renderer.js +18183 -0
- package/dist/Renderer.js.map +1 -0
- package/dist/client.cjs +94 -260
- package/dist/client.cjs.map +1 -1
- package/dist/client.js +71 -215
- package/dist/client.js.map +1 -1
- package/dist/server.cjs +165 -432
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +117 -370
- package/dist/server.js.map +1 -1
- package/dist/terminal.cjs +113 -200
- package/dist/terminal.cjs.map +1 -1
- package/dist/terminal.js +50 -51
- package/dist/terminal.js.map +1 -1
- package/dist/utils-CRhi1BDa.cjs +259 -0
- package/dist/utils-CRhi1BDa.cjs.map +1 -0
- package/dist/utils-D7tXt6-2.js +260 -0
- package/dist/utils-D7tXt6-2.js.map +1 -0
- package/package.json +19 -15
- package/src/{client.ts → network/client.js} +173 -403
- package/src/{compress-browser.ts → network/compress-browser.js} +2 -4
- package/src/{compress-node.ts → network/compress-node.js} +8 -14
- package/src/{server.ts → network/server.js} +229 -317
- package/src/{terminal.js → network/terminal.js} +0 -0
- package/src/{topazcube.ts → network/topazcube.js} +2 -2
- package/src/network/utils.js +375 -0
- package/src/renderer/Camera.js +191 -0
- package/src/renderer/DebugUI.js +572 -0
- package/src/renderer/Geometry.js +1049 -0
- package/src/renderer/Material.js +61 -0
- package/src/renderer/Mesh.js +211 -0
- package/src/renderer/Node.js +112 -0
- package/src/renderer/Pipeline.js +643 -0
- package/src/renderer/Renderer.js +1324 -0
- package/src/renderer/Skin.js +792 -0
- package/src/renderer/Texture.js +584 -0
- package/src/renderer/core/AssetManager.js +359 -0
- package/src/renderer/core/CullingSystem.js +307 -0
- package/src/renderer/core/EntityManager.js +541 -0
- package/src/renderer/core/InstanceManager.js +343 -0
- package/src/renderer/core/ParticleEmitter.js +358 -0
- package/src/renderer/core/ParticleSystem.js +564 -0
- package/src/renderer/core/SpriteSystem.js +349 -0
- package/src/renderer/gltf.js +546 -0
- package/src/renderer/math.js +161 -0
- package/src/renderer/rendering/HistoryBufferManager.js +333 -0
- package/src/renderer/rendering/ProbeCapture.js +1495 -0
- package/src/renderer/rendering/ReflectionProbeManager.js +352 -0
- package/src/renderer/rendering/RenderGraph.js +2064 -0
- package/src/renderer/rendering/passes/AOPass.js +308 -0
- package/src/renderer/rendering/passes/AmbientCapturePass.js +593 -0
- package/src/renderer/rendering/passes/BasePass.js +101 -0
- package/src/renderer/rendering/passes/BloomPass.js +417 -0
- package/src/renderer/rendering/passes/FogPass.js +419 -0
- package/src/renderer/rendering/passes/GBufferPass.js +706 -0
- package/src/renderer/rendering/passes/HiZPass.js +714 -0
- package/src/renderer/rendering/passes/LightingPass.js +739 -0
- package/src/renderer/rendering/passes/ParticlePass.js +835 -0
- package/src/renderer/rendering/passes/PlanarReflectionPass.js +456 -0
- package/src/renderer/rendering/passes/PostProcessPass.js +282 -0
- package/src/renderer/rendering/passes/ReflectionPass.js +157 -0
- package/src/renderer/rendering/passes/RenderPostPass.js +364 -0
- package/src/renderer/rendering/passes/SSGIPass.js +265 -0
- package/src/renderer/rendering/passes/SSGITilePass.js +296 -0
- package/src/renderer/rendering/passes/ShadowPass.js +1822 -0
- package/src/renderer/rendering/passes/TransparentPass.js +831 -0
- package/src/renderer/rendering/shaders/ao.wgsl +182 -0
- package/src/renderer/rendering/shaders/bloom.wgsl +97 -0
- package/src/renderer/rendering/shaders/bloom_blur.wgsl +80 -0
- package/src/renderer/rendering/shaders/depth_copy.wgsl +17 -0
- package/src/renderer/rendering/shaders/geometry.wgsl +550 -0
- package/src/renderer/rendering/shaders/hiz_reduce.wgsl +114 -0
- package/src/renderer/rendering/shaders/light_culling.wgsl +204 -0
- package/src/renderer/rendering/shaders/lighting.wgsl +932 -0
- package/src/renderer/rendering/shaders/lighting_common.wgsl +143 -0
- package/src/renderer/rendering/shaders/particle_render.wgsl +525 -0
- package/src/renderer/rendering/shaders/particle_simulate.wgsl +440 -0
- package/src/renderer/rendering/shaders/postproc.wgsl +272 -0
- package/src/renderer/rendering/shaders/render_post.wgsl +289 -0
- package/src/renderer/rendering/shaders/shadow.wgsl +76 -0
- package/src/renderer/rendering/shaders/ssgi.wgsl +266 -0
- package/src/renderer/rendering/shaders/ssgi_accumulate.wgsl +114 -0
- package/src/renderer/rendering/shaders/ssgi_propagate.wgsl +132 -0
- package/src/renderer/utils/BoundingSphere.js +439 -0
- package/src/renderer/utils/Frustum.js +281 -0
- package/dist/client.d.cts +0 -211
- package/dist/client.d.ts +0 -211
- package/dist/server.d.cts +0 -120
- package/dist/server.d.ts +0 -120
- package/dist/terminal.d.cts +0 -64
- package/dist/terminal.d.ts +0 -64
- package/src/utils.ts +0 -403
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
var _UID = 10001
|
|
2
|
+
|
|
3
|
+
class Material {
|
|
4
|
+
|
|
5
|
+
constructor(textures = [], uniforms = {}, name = null, engine = null) {
|
|
6
|
+
this.uid = _UID++
|
|
7
|
+
this.name = name || `Material_${this.uid}`
|
|
8
|
+
this.uniforms = uniforms
|
|
9
|
+
this._textures = textures
|
|
10
|
+
|
|
11
|
+
this.engine = engine
|
|
12
|
+
// If any textures have .engine, use that
|
|
13
|
+
for (const tex of textures) {
|
|
14
|
+
if (tex && tex.engine) {
|
|
15
|
+
this.engine = tex.engine
|
|
16
|
+
break
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Transparency settings
|
|
21
|
+
this.transparent = false // True for alpha blended materials (glass, water)
|
|
22
|
+
this.opacity = 1.0 // Base opacity value (0-1)
|
|
23
|
+
this.opacityTexture = null // Optional opacity texture
|
|
24
|
+
|
|
25
|
+
// Alpha hashing settings (for cutout transparency like leaves)
|
|
26
|
+
this.alphaHash = false
|
|
27
|
+
this.alphaHashScale = 1.0
|
|
28
|
+
|
|
29
|
+
// Alpha source settings
|
|
30
|
+
this.luminanceToAlpha = false // Use base color luminance as alpha (black=transparent)
|
|
31
|
+
|
|
32
|
+
// Force emissive: use base color (albedo) as emission
|
|
33
|
+
this.forceEmissive = false
|
|
34
|
+
|
|
35
|
+
// Specular boost: enables 3 additional specular lights for shiny materials (0-1, default 0 = disabled)
|
|
36
|
+
this.specularBoost = 0
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Get textures array, substituting albedo for emission if forceEmissive is true
|
|
41
|
+
* Texture order: [albedo, normal, ambient, rm, emission]
|
|
42
|
+
*/
|
|
43
|
+
get textures() {
|
|
44
|
+
if (this.forceEmissive && this._textures.length >= 5 && this._textures[0]) {
|
|
45
|
+
// Return copy with albedo texture as emission (index 4)
|
|
46
|
+
const result = [...this._textures]
|
|
47
|
+
result[4] = this._textures[0] // Use albedo as emission
|
|
48
|
+
return result
|
|
49
|
+
}
|
|
50
|
+
return this._textures
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Set textures array directly
|
|
55
|
+
*/
|
|
56
|
+
set textures(value) {
|
|
57
|
+
this._textures = value
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export { Material }
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { mat4, vec3 } from "./math.js"
|
|
2
|
+
|
|
3
|
+
var _UID = 20001
|
|
4
|
+
|
|
5
|
+
class Mesh {
|
|
6
|
+
constructor(geometry, material, name = null) {
|
|
7
|
+
this.engine = geometry.engine || material.engine
|
|
8
|
+
this.uid = _UID++
|
|
9
|
+
this.name = name || `Mesh_${this.uid}`
|
|
10
|
+
this.geometry = geometry
|
|
11
|
+
this.material = material
|
|
12
|
+
|
|
13
|
+
// Cache for rotation to avoid recalculating from matrix
|
|
14
|
+
this._rotation = { yaw: 0, pitch: 0, roll: 0 }
|
|
15
|
+
this._scale = [1, 1, 1]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Add an instance with position and optional bounding sphere radius
|
|
20
|
+
* @param {Array} position - Position [x, y, z] or bounding sphere center
|
|
21
|
+
* @param {number} radius - Bounding sphere radius (default 1)
|
|
22
|
+
* @param {Array} uvTransform - UV transform [offsetX, offsetY, scaleX, scaleY] (default [0,0,1,1])
|
|
23
|
+
* @param {Array} color - RGBA color tint (default [1,1,1,1])
|
|
24
|
+
*/
|
|
25
|
+
addInstance(position, radius = 1, uvTransform = [0, 0, 1, 1], color = [1, 1, 1, 1]) {
|
|
26
|
+
this.geometry.addInstance(position, radius, uvTransform, color)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
updateInstance(index, matrix) {
|
|
30
|
+
this.geometry.updateInstance(index, matrix)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Get position of the first instance (legacy mesh)
|
|
35
|
+
* @returns {[number, number, number]} Position [x, y, z]
|
|
36
|
+
*/
|
|
37
|
+
get position() {
|
|
38
|
+
const data = this.geometry.instanceData
|
|
39
|
+
if (!data) return [0, 0, 0]
|
|
40
|
+
return [data[12], data[13], data[14]]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Set position of the first instance (legacy mesh)
|
|
45
|
+
* @param {[number, number, number]} pos - Position [x, y, z]
|
|
46
|
+
*/
|
|
47
|
+
set position(pos) {
|
|
48
|
+
const data = this.geometry.instanceData
|
|
49
|
+
if (!data) return
|
|
50
|
+
data[12] = pos[0]
|
|
51
|
+
data[13] = pos[1]
|
|
52
|
+
data[14] = pos[2]
|
|
53
|
+
this.geometry._instanceDataDirty = true
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get rotation of the first instance as euler angles
|
|
58
|
+
* @returns {{yaw: number, pitch: number, roll: number}} Rotation in radians
|
|
59
|
+
*/
|
|
60
|
+
get rotation() {
|
|
61
|
+
const data = this.geometry.instanceData
|
|
62
|
+
if (!data) return { yaw: 0, pitch: 0, roll: 0 }
|
|
63
|
+
|
|
64
|
+
// Extract rotation from matrix (assuming no shear)
|
|
65
|
+
// Matrix layout: column-major [m0,m1,m2,m3, m4,m5,m6,m7, m8,m9,m10,m11, m12,m13,m14,m15]
|
|
66
|
+
// Column 0: [m0,m1,m2] = right * scaleX
|
|
67
|
+
// Column 1: [m4,m5,m6] = up * scaleY
|
|
68
|
+
// Column 2: [m8,m9,m10] = forward * scaleZ
|
|
69
|
+
|
|
70
|
+
// Get scale to normalize rotation matrix
|
|
71
|
+
const scaleX = Math.sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2])
|
|
72
|
+
const scaleY = Math.sqrt(data[4]*data[4] + data[5]*data[5] + data[6]*data[6])
|
|
73
|
+
const scaleZ = Math.sqrt(data[8]*data[8] + data[9]*data[9] + data[10]*data[10])
|
|
74
|
+
|
|
75
|
+
// Normalized rotation matrix elements
|
|
76
|
+
const m00 = data[0] / scaleX, m01 = data[4] / scaleY, m02 = data[8] / scaleZ
|
|
77
|
+
const m10 = data[1] / scaleX, m11 = data[5] / scaleY, m12 = data[9] / scaleZ
|
|
78
|
+
const m20 = data[2] / scaleX, m21 = data[6] / scaleY, m22 = data[10] / scaleZ
|
|
79
|
+
|
|
80
|
+
// Extract euler angles (YXZ order: yaw, pitch, roll)
|
|
81
|
+
let pitch, yaw, roll
|
|
82
|
+
|
|
83
|
+
if (Math.abs(m12) < 0.99999) {
|
|
84
|
+
pitch = Math.asin(-m12)
|
|
85
|
+
yaw = Math.atan2(m02, m22)
|
|
86
|
+
roll = Math.atan2(m10, m11)
|
|
87
|
+
} else {
|
|
88
|
+
// Gimbal lock
|
|
89
|
+
pitch = m12 < 0 ? Math.PI / 2 : -Math.PI / 2
|
|
90
|
+
yaw = Math.atan2(-m20, m00)
|
|
91
|
+
roll = 0
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { yaw, pitch, roll }
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Set rotation of the first instance using euler angles
|
|
99
|
+
* Rebuilds the transform matrix preserving position and scale
|
|
100
|
+
* @param {{yaw?: number, pitch?: number, roll?: number}} rot - Rotation in radians
|
|
101
|
+
*/
|
|
102
|
+
set rotation(rot) {
|
|
103
|
+
const data = this.geometry.instanceData
|
|
104
|
+
if (!data) return
|
|
105
|
+
|
|
106
|
+
// Get current position
|
|
107
|
+
const pos = [data[12], data[13], data[14]]
|
|
108
|
+
|
|
109
|
+
// Get current scale
|
|
110
|
+
const scaleX = Math.sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2])
|
|
111
|
+
const scaleY = Math.sqrt(data[4]*data[4] + data[5]*data[5] + data[6]*data[6])
|
|
112
|
+
const scaleZ = Math.sqrt(data[8]*data[8] + data[9]*data[9] + data[10]*data[10])
|
|
113
|
+
|
|
114
|
+
// Update cached rotation
|
|
115
|
+
const yaw = rot.yaw ?? this._rotation.yaw
|
|
116
|
+
const pitch = rot.pitch ?? this._rotation.pitch
|
|
117
|
+
const roll = rot.roll ?? this._rotation.roll
|
|
118
|
+
this._rotation = { yaw, pitch, roll }
|
|
119
|
+
|
|
120
|
+
// Build rotation matrix (YXZ order)
|
|
121
|
+
const cy = Math.cos(yaw), sy = Math.sin(yaw)
|
|
122
|
+
const cp = Math.cos(pitch), sp = Math.sin(pitch)
|
|
123
|
+
const cr = Math.cos(roll), sr = Math.sin(roll)
|
|
124
|
+
|
|
125
|
+
// Combined rotation matrix R = Ry * Rx * Rz
|
|
126
|
+
const m00 = cy * cr + sy * sp * sr
|
|
127
|
+
const m01 = -cy * sr + sy * sp * cr
|
|
128
|
+
const m02 = sy * cp
|
|
129
|
+
const m10 = cp * sr
|
|
130
|
+
const m11 = cp * cr
|
|
131
|
+
const m12 = -sp
|
|
132
|
+
const m20 = -sy * cr + cy * sp * sr
|
|
133
|
+
const m21 = sy * sr + cy * sp * cr
|
|
134
|
+
const m22 = cy * cp
|
|
135
|
+
|
|
136
|
+
// Apply scale and write to instance data
|
|
137
|
+
data[0] = m00 * scaleX; data[1] = m10 * scaleX; data[2] = m20 * scaleX; data[3] = 0
|
|
138
|
+
data[4] = m01 * scaleY; data[5] = m11 * scaleY; data[6] = m21 * scaleY; data[7] = 0
|
|
139
|
+
data[8] = m02 * scaleZ; data[9] = m12 * scaleZ; data[10] = m22 * scaleZ; data[11] = 0
|
|
140
|
+
data[12] = pos[0]; data[13] = pos[1]; data[14] = pos[2]; data[15] = 1
|
|
141
|
+
|
|
142
|
+
this.geometry._instanceDataDirty = true
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get scale of the first instance
|
|
147
|
+
* @returns {[number, number, number]} Scale [x, y, z]
|
|
148
|
+
*/
|
|
149
|
+
get scale() {
|
|
150
|
+
const data = this.geometry.instanceData
|
|
151
|
+
if (!data) return [1, 1, 1]
|
|
152
|
+
|
|
153
|
+
const scaleX = Math.sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2])
|
|
154
|
+
const scaleY = Math.sqrt(data[4]*data[4] + data[5]*data[5] + data[6]*data[6])
|
|
155
|
+
const scaleZ = Math.sqrt(data[8]*data[8] + data[9]*data[9] + data[10]*data[10])
|
|
156
|
+
|
|
157
|
+
return [scaleX, scaleY, scaleZ]
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Set scale of the first instance
|
|
162
|
+
* Rebuilds the transform matrix preserving position and rotation
|
|
163
|
+
* @param {[number, number, number]} s - Scale [x, y, z]
|
|
164
|
+
*/
|
|
165
|
+
set scale(s) {
|
|
166
|
+
const data = this.geometry.instanceData
|
|
167
|
+
if (!data) return
|
|
168
|
+
|
|
169
|
+
// Get current scale to compute ratio
|
|
170
|
+
const oldScaleX = Math.sqrt(data[0]*data[0] + data[1]*data[1] + data[2]*data[2])
|
|
171
|
+
const oldScaleY = Math.sqrt(data[4]*data[4] + data[5]*data[5] + data[6]*data[6])
|
|
172
|
+
const oldScaleZ = Math.sqrt(data[8]*data[8] + data[9]*data[9] + data[10]*data[10])
|
|
173
|
+
|
|
174
|
+
// Scale ratio
|
|
175
|
+
const rx = oldScaleX > 0 ? s[0] / oldScaleX : s[0]
|
|
176
|
+
const ry = oldScaleY > 0 ? s[1] / oldScaleY : s[1]
|
|
177
|
+
const rz = oldScaleZ > 0 ? s[2] / oldScaleZ : s[2]
|
|
178
|
+
|
|
179
|
+
// Apply new scale to rotation columns
|
|
180
|
+
data[0] *= rx; data[1] *= rx; data[2] *= rx
|
|
181
|
+
data[4] *= ry; data[5] *= ry; data[6] *= ry
|
|
182
|
+
data[8] *= rz; data[9] *= rz; data[10] *= rz
|
|
183
|
+
|
|
184
|
+
this.geometry._instanceDataDirty = true
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get the full transform matrix of the first instance
|
|
189
|
+
* @returns {Float32Array} 4x4 transform matrix (16 floats)
|
|
190
|
+
*/
|
|
191
|
+
get matrix() {
|
|
192
|
+
const data = this.geometry.instanceData
|
|
193
|
+
if (!data) return mat4.create()
|
|
194
|
+
return new Float32Array(data.buffer, data.byteOffset, 16)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Set the full transform matrix of the first instance
|
|
199
|
+
* @param {Float32Array|Array} m - 4x4 transform matrix
|
|
200
|
+
*/
|
|
201
|
+
set matrix(m) {
|
|
202
|
+
const data = this.geometry.instanceData
|
|
203
|
+
if (!data) return
|
|
204
|
+
for (let i = 0; i < 16; i++) {
|
|
205
|
+
data[i] = m[i]
|
|
206
|
+
}
|
|
207
|
+
this.geometry._instanceDataDirty = true
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export { Mesh }
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { fromEuler, toEuler, UP, RIGHT, FORWARD, V_T, V_T2 } from "./math.js"
|
|
2
|
+
|
|
3
|
+
class Node {
|
|
4
|
+
|
|
5
|
+
constructor() {
|
|
6
|
+
this.name = null
|
|
7
|
+
this.position = vec3.create()
|
|
8
|
+
this.rotation = quat.create()
|
|
9
|
+
this.scale = vec3.fromValues(1, 1, 1)
|
|
10
|
+
this.children = []
|
|
11
|
+
|
|
12
|
+
// calculated matrices
|
|
13
|
+
this.matrix = mat4.create()
|
|
14
|
+
this.world = mat4.create()
|
|
15
|
+
this.inv = mat4.create()
|
|
16
|
+
this.normal = mat4.create()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
fromEuler(euler) {
|
|
20
|
+
//console.log('before fromEuler', this.rotation)
|
|
21
|
+
fromEuler(euler, this.rotation)
|
|
22
|
+
//console.log('after fromEuler', this.rotation)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get yaw() {
|
|
26
|
+
toEuler(this.rotation, V_T)
|
|
27
|
+
//console.log('get yaw', V_T[0])
|
|
28
|
+
return V_T[1]
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
set yaw(yaw) {
|
|
32
|
+
//console.log('--- set yaw', yaw)
|
|
33
|
+
//console.log('--- set before rotation', this.rotation)
|
|
34
|
+
toEuler(this.rotation, V_T2)
|
|
35
|
+
//console.log('toEuler', V_T2)
|
|
36
|
+
V_T2[1] = yaw
|
|
37
|
+
this.fromEuler(V_T2)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
rotateYaw(yaw) {
|
|
41
|
+
this.yaw += yaw
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get pitch() {
|
|
45
|
+
toEuler(this.rotation, V_T)
|
|
46
|
+
return V_T[0]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
set pitch(pitch) {
|
|
50
|
+
toEuler(this.rotation, V_T2)
|
|
51
|
+
V_T2[0] = pitch
|
|
52
|
+
this.fromEuler(V_T2)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
rotatePitch(pitch) {
|
|
56
|
+
this.pitch += pitch
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
limitPitch() {
|
|
60
|
+
// Convert current pitch to degrees
|
|
61
|
+
let pitchDegrees = this.pitch * (180 / Math.PI);
|
|
62
|
+
|
|
63
|
+
// Clamp pitch between -89.9 and 89.9 degrees
|
|
64
|
+
pitchDegrees = Math.max(-89, Math.min(89, pitchDegrees));
|
|
65
|
+
|
|
66
|
+
// Convert back to radians and set the pitch
|
|
67
|
+
this.pitch = pitchDegrees * (Math.PI / 180);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get roll() {
|
|
71
|
+
toEuler(this.rotation, V_T)
|
|
72
|
+
return V_T[2]
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
set roll(roll) {
|
|
76
|
+
toEuler(this.rotation, V_T2)
|
|
77
|
+
V_T2[2] = roll
|
|
78
|
+
this.fromEuler(V_T2)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
rotateRoll(roll) {
|
|
82
|
+
this.roll += roll
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
updateMatrix(parentMatrix) {
|
|
86
|
+
mat4.fromRotationTranslationScale(this.matrix, this.rotation, this.position, this.scale)
|
|
87
|
+
mat4.identity(this.world)
|
|
88
|
+
mat4.multiply(this.world, this.world, this.matrix)
|
|
89
|
+
if (parentMatrix) {
|
|
90
|
+
mat4.multiply(this.world, this.world, parentMatrix)
|
|
91
|
+
}
|
|
92
|
+
mat4.invert(this.inv, this.world)
|
|
93
|
+
mat4.transpose(this.normal, this.inv)
|
|
94
|
+
if (this.direction) {
|
|
95
|
+
vec3.set(this.direction, 0, 0, -1)
|
|
96
|
+
vec3.transformQuat(this.direction, this.direction, this.rotation)
|
|
97
|
+
}
|
|
98
|
+
if (this.right) {
|
|
99
|
+
vec3.set(this.right, 1, 0, 0)
|
|
100
|
+
vec3.transformQuat(this.right, this.right, this.rotation)
|
|
101
|
+
}
|
|
102
|
+
for (let child of this.children) {
|
|
103
|
+
child.updateMatrix(this.world)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
addChild(child) {
|
|
108
|
+
this.children.push(child)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export { Node, toEuler, fromEuler }
|