ris-framework 0.2.0-dev.14 → 0.2.0-dev.16

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.
Files changed (160) hide show
  1. package/CHANGELOG.md +39 -2
  2. package/README.md +8 -6
  3. package/dist/api/IFramework.d.ts +1 -1
  4. package/dist/api/IFramework.d.ts.map +1 -1
  5. package/dist/api/_export.d.ts +3 -0
  6. package/dist/api/_export.d.ts.map +1 -1
  7. package/dist/api/camera/CameraTransformUtilities.d.ts +65 -0
  8. package/dist/api/camera/CameraTransformUtilities.d.ts.map +1 -0
  9. package/dist/api/camera/ICamera.d.ts +36 -2
  10. package/dist/api/camera/ICamera.d.ts.map +1 -1
  11. package/dist/api/camera/OrbitCamera.d.ts +22 -14
  12. package/dist/api/camera/OrbitCamera.d.ts.map +1 -1
  13. package/dist/api/camera/OrthographicCamera.d.ts +33 -11
  14. package/dist/api/camera/OrthographicCamera.d.ts.map +1 -1
  15. package/dist/api/camera/PerspectiveCamera.d.ts +32 -18
  16. package/dist/api/camera/PerspectiveCamera.d.ts.map +1 -1
  17. package/dist/api/content/ContentManager.d.ts.map +1 -1
  18. package/dist/api/lights/AmbientLight.d.ts +7 -2
  19. package/dist/api/lights/AmbientLight.d.ts.map +1 -1
  20. package/dist/api/lights/DirectionalLight.d.ts +18 -4
  21. package/dist/api/lights/DirectionalLight.d.ts.map +1 -1
  22. package/dist/api/lights/ILight.d.ts +18 -0
  23. package/dist/api/lights/ILight.d.ts.map +1 -0
  24. package/dist/api/lights/PointLight.d.ts +17 -4
  25. package/dist/api/lights/PointLight.d.ts.map +1 -1
  26. package/dist/api/lights/_export.d.ts +1 -0
  27. package/dist/api/lights/_export.d.ts.map +1 -1
  28. package/dist/api/material/ForwardBlinnPhongMaterial.d.ts +2 -2
  29. package/dist/api/material/ForwardBlinnPhongMaterial.d.ts.map +1 -1
  30. package/dist/api/material/IMaterial.d.ts +7 -0
  31. package/dist/api/material/IMaterial.d.ts.map +1 -1
  32. package/dist/api/material/IMaterialFactory.d.ts +3 -2
  33. package/dist/api/material/IMaterialFactory.d.ts.map +1 -1
  34. package/dist/api/material/IUnlitMaterialDescriptor.d.ts +16 -0
  35. package/dist/api/material/IUnlitMaterialDescriptor.d.ts.map +1 -0
  36. package/dist/api/material/MaterialFactory.d.ts +3 -2
  37. package/dist/api/material/MaterialFactory.d.ts.map +1 -1
  38. package/dist/api/material/SpriteMaterial.d.ts +3 -0
  39. package/dist/api/material/SpriteMaterial.d.ts.map +1 -1
  40. package/dist/api/material/UnlitMaterial.d.ts +5 -12
  41. package/dist/api/material/UnlitMaterial.d.ts.map +1 -1
  42. package/dist/api/material/_export.d.ts +1 -1
  43. package/dist/api/material/_export.d.ts.map +1 -1
  44. package/dist/api/meshes/IRenderableMesh.d.ts +3 -14
  45. package/dist/api/meshes/IRenderableMesh.d.ts.map +1 -1
  46. package/dist/api/meshes/RenderableMesh.d.ts +5 -20
  47. package/dist/api/meshes/RenderableMesh.d.ts.map +1 -1
  48. package/dist/api/rendering/IGraphicsDevice.d.ts +2 -2
  49. package/dist/api/rendering/IGraphicsDevice.d.ts.map +1 -1
  50. package/dist/api/rendering/IRenderer.d.ts +6 -4
  51. package/dist/api/rendering/IRenderer.d.ts.map +1 -1
  52. package/dist/api/rendering/_export-rendering.d.ts +1 -0
  53. package/dist/api/rendering/_export-rendering.d.ts.map +1 -1
  54. package/dist/api/rendering/primitive/IPrimitiveStateDescriptor.d.ts +24 -0
  55. package/dist/api/rendering/primitive/IPrimitiveStateDescriptor.d.ts.map +1 -0
  56. package/dist/api/rendering/primitive/_export.d.ts +1 -1
  57. package/dist/api/rendering/primitive/_export.d.ts.map +1 -1
  58. package/dist/api/rendering/render-pipelines/IMainRenderTargetRenderPipeline.d.ts +5 -0
  59. package/dist/api/rendering/render-pipelines/IMainRenderTargetRenderPipeline.d.ts.map +1 -1
  60. package/dist/api/rendering/texture/ITextureDescriptor.d.ts +5 -1
  61. package/dist/api/rendering/texture/ITextureDescriptor.d.ts.map +1 -1
  62. package/dist/api/rendering/texture/ITextureFactory.d.ts +3 -1
  63. package/dist/api/rendering/texture/ITextureFactory.d.ts.map +1 -1
  64. package/dist/api/rendering/texture/TextureUtilities.d.ts +7 -0
  65. package/dist/api/rendering/texture/TextureUtilities.d.ts.map +1 -1
  66. package/dist/api/scene/ISceneObject.d.ts +12 -0
  67. package/dist/api/scene/ISceneObject.d.ts.map +1 -0
  68. package/dist/api/scene/Scene.d.ts +17 -6
  69. package/dist/api/scene/Scene.d.ts.map +1 -1
  70. package/dist/api/scene/node/Node.d.ts +26 -0
  71. package/dist/api/scene/node/Node.d.ts.map +1 -0
  72. package/dist/api/scene/node/TransformNode.d.ts +46 -0
  73. package/dist/api/scene/node/TransformNode.d.ts.map +1 -0
  74. package/dist/core/material/UnlitMaterialDescriptorUtilities.d.ts +17 -0
  75. package/dist/core/material/UnlitMaterialDescriptorUtilities.d.ts.map +1 -0
  76. package/dist/core/rendering/AGraphicsDevice.d.ts +2 -2
  77. package/dist/core/rendering/AGraphicsDevice.d.ts.map +1 -1
  78. package/dist/core/rendering/ARenderer.d.ts +5 -2
  79. package/dist/core/rendering/ARenderer.d.ts.map +1 -1
  80. package/dist/core/rendering/primitive/PrimitiveStateDescriptorUtilities.d.ts +15 -0
  81. package/dist/core/rendering/primitive/PrimitiveStateDescriptorUtilities.d.ts.map +1 -0
  82. package/dist/core/rendering/texture/TextureDescriptorUtilities.d.ts +2 -2
  83. package/dist/core/rendering/texture/TextureDescriptorUtilities.d.ts.map +1 -1
  84. package/dist/index.js +704 -272
  85. package/dist/webgl/WebGlGraphicsDevice.d.ts +2 -2
  86. package/dist/webgl/WebGlGraphicsDevice.d.ts.map +1 -1
  87. package/dist/webgl/lights/WebGlLightsBuffer.d.ts.map +1 -1
  88. package/dist/webgl/primitive/WebGlPrimitiveState.d.ts +3 -3
  89. package/dist/webgl/primitive/WebGlPrimitiveState.d.ts.map +1 -1
  90. package/dist/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.d.ts +8 -0
  91. package/dist/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.d.ts.map +1 -1
  92. package/dist/webgl/texture/WebGlTextureFactory.d.ts +1 -1
  93. package/dist/webgl/texture/WebGlTextureFactory.d.ts.map +1 -1
  94. package/dist/webgl/utilities/WebGlTextureUtilities.d.ts.map +1 -1
  95. package/dist/webgpu/WebGpuGraphicsDevice.d.ts +2 -2
  96. package/dist/webgpu/WebGpuGraphicsDevice.d.ts.map +1 -1
  97. package/dist/webgpu/primitive/WebGpuPrimitiveState.d.ts +2 -2
  98. package/dist/webgpu/primitive/WebGpuPrimitiveState.d.ts.map +1 -1
  99. package/dist/webgpu/render-pipelines/WebGpuMainRenderTargetRenderPipeline.d.ts +5 -0
  100. package/dist/webgpu/render-pipelines/WebGpuMainRenderTargetRenderPipeline.d.ts.map +1 -1
  101. package/dist/webgpu/texture/WebGpuTextureFactory.d.ts.map +1 -1
  102. package/package.json +2 -2
  103. package/src/Framework.ts +1 -1
  104. package/src/api/IFramework.ts +1 -1
  105. package/src/api/_export.ts +3 -0
  106. package/src/api/camera/CameraTransformUtilities.ts +182 -0
  107. package/src/api/camera/ICamera.ts +42 -2
  108. package/src/api/camera/OrbitCamera.ts +71 -38
  109. package/src/api/camera/OrthographicCamera.ts +71 -28
  110. package/src/api/camera/PerspectiveCamera.ts +69 -33
  111. package/src/api/content/ContentManager.ts +9 -5
  112. package/src/api/lights/AmbientLight.ts +8 -2
  113. package/src/api/lights/DirectionalLight.ts +30 -5
  114. package/src/api/lights/ILight.ts +22 -0
  115. package/src/api/lights/PointLight.ts +26 -5
  116. package/src/api/lights/_export.ts +1 -0
  117. package/src/api/material/ForwardBlinnPhongMaterial.ts +2 -2
  118. package/src/api/material/IMaterial.ts +8 -0
  119. package/src/api/material/IMaterialFactory.ts +3 -2
  120. package/src/api/material/IUnlitMaterialDescriptor.ts +18 -0
  121. package/src/api/material/MaterialFactory.ts +4 -3
  122. package/src/api/material/SpriteMaterial.ts +4 -0
  123. package/src/api/material/UnlitMaterial.ts +11 -18
  124. package/src/api/material/_export.ts +1 -1
  125. package/src/api/meshes/IRenderableMesh.ts +3 -18
  126. package/src/api/meshes/RenderableMesh.ts +15 -45
  127. package/src/api/rendering/IGraphicsDevice.ts +2 -2
  128. package/src/api/rendering/IRenderer.ts +6 -4
  129. package/src/api/rendering/_export-rendering.ts +2 -1
  130. package/src/api/rendering/primitive/IPrimitiveStateDescriptor.ts +27 -0
  131. package/src/api/rendering/primitive/_export.ts +1 -1
  132. package/src/api/rendering/render-pipelines/IMainRenderTargetRenderPipeline.ts +6 -0
  133. package/src/api/rendering/texture/ITextureDescriptor.ts +6 -1
  134. package/src/api/rendering/texture/ITextureFactory.ts +3 -1
  135. package/src/api/rendering/texture/TextureUtilities.ts +16 -0
  136. package/src/api/scene/ISceneObject.ts +13 -0
  137. package/src/api/scene/Scene.ts +52 -11
  138. package/src/api/scene/node/Node.ts +54 -0
  139. package/src/api/scene/node/TransformNode.ts +88 -0
  140. package/src/core/material/UnlitMaterialDescriptorUtilities.ts +21 -0
  141. package/src/core/rendering/AGraphicsDevice.ts +2 -2
  142. package/src/core/rendering/ARenderer.ts +23 -5
  143. package/src/core/rendering/primitive/PrimitiveStateDescriptorUtilities.ts +22 -0
  144. package/src/core/rendering/texture/TextureDescriptorUtilities.ts +3 -2
  145. package/src/webgl/WebGlGraphicsDevice.ts +2 -3
  146. package/src/webgl/lights/WebGlLightsBuffer.ts +21 -8
  147. package/src/webgl/primitive/WebGlPrimitiveState.ts +8 -6
  148. package/src/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.ts +14 -0
  149. package/src/webgl/texture/WebGlTextureFactory.ts +27 -16
  150. package/src/webgl/utilities/WebGlTextureUtilities.ts +10 -4
  151. package/src/webgpu/WebGpuGraphicsDevice.ts +3 -3
  152. package/src/webgpu/primitive/WebGpuPrimitiveState.ts +7 -5
  153. package/src/webgpu/render-pipelines/WebGpuMainRenderTargetRenderPipeline.ts +6 -0
  154. package/src/webgpu/texture/WebGpuTextureFactory.ts +1 -1
  155. package/dist/api/material/ICameraMaterial.d.ts +0 -18
  156. package/dist/api/material/ICameraMaterial.d.ts.map +0 -1
  157. package/dist/api/rendering/primitive/PrimitiveStateDescriptor.d.ts +0 -24
  158. package/dist/api/rendering/primitive/PrimitiveStateDescriptor.d.ts.map +0 -1
  159. package/src/api/material/ICameraMaterial.ts +0 -22
  160. package/src/api/rendering/primitive/PrimitiveStateDescriptor.ts +0 -27
@@ -10,6 +10,8 @@ import {MouseButton} from "../input/mouse/MouseButton.ts";
10
10
  import {TouchCollection} from "../input/touch/TouchCollection.ts";
11
11
  import {TouchLocation} from "../input/touch/TouchLocation.ts";
12
12
  import {InputDeviceType} from "../input/InputDeviceType.ts";
13
+ import {CameraTransformUtilities} from "./CameraTransformUtilities.ts";
14
+ import type {TransformNode} from "../scene/node/TransformNode.ts";
13
15
 
14
16
  /**
15
17
  * Camerae that support orbit movement.
@@ -31,6 +33,7 @@ export class OrbitCamera implements ICamera {
31
33
  private readonly _inputManager: IInputManager
32
34
 
33
35
  /** The rotation around the vertical axis. */
36
+ private readonly _target = vec3.create();
34
37
  private _yaw = 0;
35
38
 
36
39
  /** The tilt of the camera.*/
@@ -47,8 +50,8 @@ export class OrbitCamera implements ICamera {
47
50
  public supportedInputTypes: InputDeviceType = InputDeviceType.MOUSE | InputDeviceType.TOUCHPAD) {
48
51
  this._coreCamera = coreCamera;
49
52
  this._inputManager = inputManager;
50
- this.eye = vec3.fromValues(0, 0, -3);
51
- this.target = vec3.fromValues(0, 0, 0);
53
+ vec3.set(this._coreCamera.transform.position, 0, 0, 3);
54
+ this._syncFromTransform();
52
55
  void this.POSITIVE_179_DEG;
53
56
  void this.findTarget;
54
57
  }
@@ -66,7 +69,6 @@ export class OrbitCamera implements ICamera {
66
69
  public pinchSpeed: number = 1;
67
70
 
68
71
  /** The up vector. */
69
- public up = vec3.fromValues(0, 1, 0);
70
72
 
71
73
  /** The clamp values of pitch axis */
72
74
  public pitchClamp = vec2.fromValues(-this.POSITIVE_89_DEG, this.POSITIVE_89_DEG);
@@ -119,37 +121,65 @@ export class OrbitCamera implements ICamera {
119
121
  /** Orbit controls can be used if this button is pressed. */
120
122
  public orbitButton = MouseButton.LEFT;
121
123
 
122
- /**
123
- * The eye position of the camera.
124
- */
125
- public get eye(): vec3 {
126
- return this._coreCamera.eye;
124
+ /** The orbit camera's transform: the core camera's transform. Its position is the eye; the rotation is set each update to look at {@link target}. */
125
+ public get transform(): TransformNode {
126
+ return this._coreCamera.transform;
127
127
  }
128
128
 
129
129
  /**
130
- * The eye position of the camera.
130
+ * Sets the point the camera orbits around and looks at (the core camera's target). By default, the origin.
131
+ * @param target The world point.
131
132
  */
132
- public set eye(value: vec3) {
133
- this._coreCamera.eye = value;
134
- this._setPitchAndYawFromDirection(this._coreCamera.direction);
133
+ public setTarget(target: vec3): void {
134
+ vec3.copy(this._target, target);
135
+ this._syncFromTransform();
135
136
  }
136
137
 
137
- /**
138
- * The eye position of the camera.
139
- */
140
- public get target(): vec3 {
141
- return this._coreCamera.target;
138
+ /** @inheritDoc */
139
+ public getTarget(out: vec3 = vec3.create()): vec3 {
140
+ return vec3.copy(out, this._target);
142
141
  }
143
142
 
144
143
  /**
145
- * The eye position of the camera.
144
+ * Moves the camera to a world position and re-derives the orbit (pitch, yaw, distance) around the target.
145
+ * @param eye The world position.
146
146
  */
147
- public set target(value: vec3) {
148
- this._coreCamera.target = value;
149
- this._setPitchAndYawFromDirection(this._coreCamera.direction);
147
+ public setEye(eye: vec3): void {
148
+ CameraTransformUtilities.setWorldPosition(this._coreCamera.transform, eye);
149
+ this._syncFromTransform();
150
+ }
151
+
152
+ /** @inheritDoc */
153
+ public getEye(out?: vec3): vec3 {
154
+ return this._coreCamera.getEye(out);
155
+ }
156
+
157
+ /** Sets the up vector the core camera aims with (the orbit angles stay around world +Y, so this rolls the view). */
158
+ public setUp(up: vec3): void {
159
+ this._coreCamera.setUp(up);
160
+ this._coreCamera.setTarget(this._target);
161
+ }
162
+
163
+ /** @inheritDoc */
164
+ public getUp(out?: vec3): vec3 {
165
+ return this._coreCamera.getUp(out);
166
+ }
167
+
168
+ /** The eye: `transform.position` (world space). */
169
+ private get _eye(): vec3 {
170
+ return this._coreCamera.transform.position;
171
+ }
172
+
173
+ /** Re-derives pitch and yaw from the eye and target, and aims the core camera at the target. */
174
+ private _syncFromTransform(): void {
175
+ vec3.sub(this._tempDirection, this._target, this._eye);
176
+ if (vec3.sqrLen(this._tempDirection) === 0) {
177
+ return;
178
+ }
179
+ this._setPitchAndYawFromDirection(this._tempDirection);
180
+ this._coreCamera.setTarget(this._target);
150
181
  }
151
182
 
152
- /** Gets the core camera.*/
153
183
  public get coreCamera(): ICamera | undefined {
154
184
  return this._coreCamera;
155
185
  }
@@ -184,7 +214,8 @@ export class OrbitCamera implements ICamera {
184
214
  vec3.normalize(lookDirection, lookDirection);
185
215
  const y = MathHelper.clamp(lookDirection[1], -1, 1);
186
216
  this._pitch = -this._pitchClamp(Math.asin(y));
187
- this._yaw = -Math.atan2(lookDirection[0], lookDirection[2]);
217
+ // World direction; the orbit angles keep their original z-flipped convention.
218
+ this._yaw = -Math.atan2(lookDirection[0], 0 - lookDirection[2]);
188
219
  }
189
220
 
190
221
  private _calculateOrbitMovement() {
@@ -192,7 +223,7 @@ export class OrbitCamera implements ICamera {
192
223
  this._pitch = this._pitchClamp(this._pitch);
193
224
 
194
225
  // Convert spherical coordinates to Cartesian
195
- vec3.sub(this._tempVec3, this._coreCamera.target, this._coreCamera.eye);
226
+ vec3.sub(this._tempVec3, this._target, this._eye);
196
227
  const radius = vec3.len(this._tempVec3);
197
228
 
198
229
  const sinPitch = Math.sin(this._pitch);
@@ -204,8 +235,9 @@ export class OrbitCamera implements ICamera {
204
235
 
205
236
  this._tempVec3[0] = x;
206
237
  this._tempVec3[1] = y;
207
- this._tempVec3[2] = -z;
208
- vec3.add(this._coreCamera.eye, this._coreCamera.target, this._tempVec3);
238
+ this._tempVec3[2] = z;
239
+ vec3.add(this._eye, this._target, this._tempVec3);
240
+ this._coreCamera.setTarget(this._target);
209
241
  }
210
242
 
211
243
  /**
@@ -267,11 +299,11 @@ export class OrbitCamera implements ICamera {
267
299
  }
268
300
 
269
301
  // Find the current distance.
270
- vec3.copy(this._tempDirection, this.direction);
302
+ vec3.sub(this._tempDirection, this._target, this._eye);
271
303
 
272
304
  // Find the next eye position.
273
305
  vec3.normalize(this._tempDirection, this._tempDirection);
274
- vec3.copy(this._tempNextEye, this.eye);
306
+ vec3.copy(this._tempNextEye, this._eye);
275
307
 
276
308
  if (diff < 0) {
277
309
  vec3.scale(this._tempVec3, this._tempDirection, this.pinchSpeed * deltaTime);
@@ -282,8 +314,8 @@ export class OrbitCamera implements ICamera {
282
314
  }
283
315
 
284
316
  // Find the new potential length.
285
- vec3.sub(this._tempNextDirection, this.target, this._tempNextEye);
286
- const nextLength = this._tempNextDirection.length;
317
+ vec3.sub(this._tempNextDirection, this._target, this._tempNextEye);
318
+ const nextLength = vec3.len(this._tempNextDirection);
287
319
  vec3.normalize(this._tempNextDirection, this._tempNextDirection);
288
320
 
289
321
  // Difference between next direction and direction.
@@ -298,8 +330,8 @@ export class OrbitCamera implements ICamera {
298
330
  return;
299
331
  }
300
332
 
301
- vec3.copy(this._coreCamera.eye, this._tempNextEye);
302
- this._setPitchAndYawFromDirection(this._coreCamera.direction);
333
+ vec3.copy(this._eye, this._tempNextEye);
334
+ this._syncFromTransform();
303
335
  }
304
336
 
305
337
  /** Handles forward/backward movement */
@@ -312,7 +344,7 @@ export class OrbitCamera implements ICamera {
312
344
  }
313
345
 
314
346
  // Find the current distance.
315
- vec3.copy(this._tempDirection, this.direction);
347
+ vec3.sub(this._tempDirection, this._target, this._eye);
316
348
  const distance = vec3.len(this._tempDirection);
317
349
 
318
350
  // Map it to [1,0.1f] space.
@@ -331,7 +363,7 @@ export class OrbitCamera implements ICamera {
331
363
 
332
364
  // Find the next eye position.
333
365
  vec3.normalize(this._tempDirection, this._tempDirection);
334
- vec3.copy(this._tempNextEye, this.eye);
366
+ vec3.copy(this._tempNextEye, this._eye);
335
367
 
336
368
  if (mouseScrollPos > 0) {
337
369
  vec3.scale(this._tempVec3, this._tempDirection, trueScrollSpeed * deltaTime);
@@ -342,8 +374,8 @@ export class OrbitCamera implements ICamera {
342
374
  }
343
375
 
344
376
  // Find the new potential length.
345
- vec3.sub(this._tempNextDirection, this.target, this._tempNextEye);
346
- const nextLength = this._tempNextDirection.length;
377
+ vec3.sub(this._tempNextDirection, this._target, this._tempNextEye);
378
+ const nextLength = vec3.len(this._tempNextDirection);
347
379
  vec3.normalize(this._tempNextDirection, this._tempNextDirection);
348
380
 
349
381
  // Difference between next direction and direction.
@@ -358,8 +390,8 @@ export class OrbitCamera implements ICamera {
358
390
  return;
359
391
  }
360
392
 
361
- vec3.copy(this._coreCamera.eye, this._tempNextEye);
362
- this._setPitchAndYawFromDirection(this._coreCamera.direction);
393
+ vec3.copy(this._eye, this._tempNextEye);
394
+ this._syncFromTransform();
363
395
  }
364
396
 
365
397
  /** @inheritDoc */
@@ -392,6 +424,7 @@ export class OrbitCamera implements ICamera {
392
424
  }
393
425
  }
394
426
 
427
+ this._coreCamera.setTarget(this._target);
395
428
  this._coreCamera.update(time);
396
429
  }
397
430
 
@@ -4,21 +4,21 @@ import {vec3, mat4} from "gl-matrix";
4
4
  import type { IUniformBuffer } from "../rendering/buffers/IUniformBuffer.ts";
5
5
  import {BufferUsage} from "../rendering/buffers/BufferUsage.ts";
6
6
  import {GameTime} from "../time/GameTime.ts";
7
+ import {TransformNode} from "../scene/node/TransformNode.ts";
8
+ import {CameraAim, CameraTransformUtilities} from "./CameraTransformUtilities.ts";
7
9
 
8
10
  /**
9
11
  * The Orthographic Camera.
10
12
  */
11
13
  export class OrthographicCamera implements IOrthographicCamera {
12
14
 
13
- static UP_VECTOR = vec3.fromValues(0, 1, 0);
14
-
15
15
  private readonly _framework: IFramework;
16
16
 
17
17
  /** @ts-ignore */
18
18
  private readonly _zSpaceLength: number;
19
19
 
20
- private _eye: vec3;
21
- private _target: vec3;
20
+ private readonly _lastWorld = mat4.fromValues(NaN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
21
+ private readonly _direction = vec3.create();
22
22
 
23
23
  private _left: number;
24
24
  private _right: number;
@@ -33,9 +33,58 @@ export class OrthographicCamera implements IOrthographicCamera {
33
33
  protected _viewMatrix = mat4.create();
34
34
  protected _projectionViewMatrix = mat4.create();
35
35
 
36
- public readonly position = vec3.create();
37
- public readonly target = vec3.create();
38
- public readonly direction = vec3.create();
36
+ /**
37
+ * The camera transform: the single source of the view. The camera looks down its local -Z axis;
38
+ * the view matrix is `inverse(T * R)` of `transform.modelMatrix` (scale is ignored).
39
+ * By default, at (0, 0, 1) looking down -Z at the origin.
40
+ */
41
+ public transform = new TransformNode();
42
+
43
+ /** The unit direction the camera looks in, from the transform. */
44
+ public get direction(): vec3 {
45
+ return CameraTransformUtilities.forwardFromWorld(this._direction, this.transform.modelMatrix);
46
+ }
47
+
48
+ private readonly _aim = new CameraAim(() => this.transform);
49
+
50
+ /**
51
+ * Rotates the transform once so the camera looks at a world point, using the current up ({@link getUp}).
52
+ * Forgets the target stored by {@link setTarget}, so a later {@link setEye} does not re-aim.
53
+ * @param target The point to look at.
54
+ */
55
+ public lookAt(target: vec3): void {
56
+ this._aim.lookAt(target);
57
+ }
58
+
59
+ /** @inheritDoc */
60
+ public setEye(eye: vec3): void {
61
+ this._aim.setEye(eye);
62
+ }
63
+
64
+ /** @inheritDoc */
65
+ public getEye(out?: vec3): vec3 {
66
+ return this._aim.getEye(out);
67
+ }
68
+
69
+ /** @inheritDoc */
70
+ public setTarget(target: vec3): void {
71
+ this._aim.setTarget(target);
72
+ }
73
+
74
+ /** @inheritDoc */
75
+ public getTarget(out?: vec3): vec3 {
76
+ return this._aim.getTarget(out);
77
+ }
78
+
79
+ /** @inheritDoc */
80
+ public setUp(up: vec3): void {
81
+ this._aim.setUp(up);
82
+ }
83
+
84
+ /** @inheritDoc */
85
+ public getUp(out?: vec3): vec3 {
86
+ return this._aim.getUp(out);
87
+ }
39
88
 
40
89
  private _projectionBuffer: IUniformBuffer = null!;
41
90
  private _viewBuffer: IUniformBuffer = null!;
@@ -72,8 +121,7 @@ export class OrthographicCamera implements IOrthographicCamera {
72
121
  this._near = near;
73
122
  this._far = far;
74
123
 
75
- this._eye = vec3.fromValues(0, 0, 1);
76
- this._target = vec3.fromValues(0, 0, 0);
124
+ vec3.set(this.transform.position, 0, 0, 1);
77
125
 
78
126
  this._zSpaceLength = 2; // For WebGL2 it is 2, WebGPU it is 1.
79
127
 
@@ -164,19 +212,6 @@ export class OrthographicCamera implements IOrthographicCamera {
164
212
  this._isDirty = true;
165
213
  }
166
214
 
167
- /** @inheritDoc */
168
- public get eye(): vec3 {
169
- return this._eye;
170
- }
171
-
172
- /** @inheritDoc */
173
- public set eye(value: vec3) {
174
- if (this._eye === value)
175
- return;
176
- this._eye = value;
177
- this._isDirty = true;
178
- }
179
-
180
215
  /** @inheritDoc */
181
216
  public get projectionMatrix(): mat4 {
182
217
  return this._projectionMatrix;
@@ -212,19 +247,27 @@ export class OrthographicCamera implements IOrthographicCamera {
212
247
  return this._positionBuffer;
213
248
  }
214
249
 
215
- /** Writes the world-space eye into the std140 position data (no z flip: the look-at uses the eye as is). */
250
+ /** Writes the transform's world position into the std140 position data. */
216
251
  private _updatePositionData(): number[] {
217
- this._positionData[0] = this._eye[0];
218
- this._positionData[1] = this._eye[1];
219
- this._positionData[2] = this._eye[2];
252
+ const m = this.transform.modelMatrix;
253
+ this._positionData[0] = m[12];
254
+ this._positionData[1] = m[13];
255
+ this._positionData[2] = m[14];
220
256
  return this._positionData;
221
257
  }
222
258
 
259
+ /** True when the transform's world matrix changed since the view was last built. */
260
+ private _transformChanged(): boolean {
261
+ return !mat4.exactEquals(this._lastWorld, this.transform.modelMatrix);
262
+ }
263
+
223
264
  /**
224
265
  * Updates the camera matrices.
225
266
  */
226
267
  protected _updateMatrices() {
227
- mat4.lookAt(this._viewMatrix, this._eye, this._target, OrthographicCamera.UP_VECTOR);
268
+ const world = this.transform.modelMatrix;
269
+ mat4.copy(this._lastWorld, world);
270
+ CameraTransformUtilities.viewFromWorld(this._viewMatrix, world);
228
271
  mat4.orthoNO(this._projectionMatrix, this._left, this._right, this._bottom, this._top, this._near, this._far);
229
272
  mat4.multiply(this._projectionViewMatrix, this._projectionMatrix, this._viewMatrix);
230
273
  }
@@ -261,7 +304,7 @@ export class OrthographicCamera implements IOrthographicCamera {
261
304
  /** @inheritDoc */
262
305
  public update(_: GameTime): void {
263
306
 
264
- if (!this._isDirty)
307
+ if (!this._isDirty && !this._transformChanged())
265
308
  return;
266
309
 
267
310
  this.updateBuffers();
@@ -6,6 +6,8 @@ import {BufferUsage} from "../rendering/buffers/BufferUsage.ts";
6
6
  import type { IUniformBuffer } from "../rendering/buffers/IUniformBuffer.ts";
7
7
  import {GameTime} from "../time/GameTime.ts";
8
8
  import type {Scene} from "../scene/Scene.ts";
9
+ import {TransformNode} from "../scene/node/TransformNode.ts";
10
+ import {CameraAim, CameraTransformUtilities} from "./CameraTransformUtilities.ts";
9
11
 
10
12
  /**
11
13
  * The descriptor for a perspective camera. Every field is optional.
@@ -24,13 +26,16 @@ export interface PerspectiveCameraDescriptor {
24
26
  /** The far plane. By default, 100. */
25
27
  far?: number;
26
28
 
27
- /** The eye position. Copied. By default, (0, 0, 3). */
29
+ /** The world position (see {@link ICamera.setEye}). By default, (0, 0, -3). */
30
+ position?: vec3;
31
+
32
+ /** Alias of {@link position}; `position` wins when both are given. */
28
33
  eye?: vec3;
29
34
 
30
- /** The point the camera looks at. Copied. By default, the origin. */
35
+ /** The point the camera looks at (see {@link ICamera.setTarget}). By default, the origin. */
31
36
  target?: vec3;
32
37
 
33
- /** The up vector. Copied. By default, (0, 1, 0). */
38
+ /** The up vector used to aim (see {@link ICamera.setUp}). By default, (0, 1, 0). */
34
39
  up?: vec3;
35
40
  }
36
41
 
@@ -40,7 +45,8 @@ export interface PerspectiveCameraDescriptor {
40
45
  export class PerspectiveCamera implements ICamera {
41
46
 
42
47
  protected readonly _framework: IFramework;
43
- private readonly _tempVec3 = vec3.create();
48
+ private readonly _lastWorld = mat4.fromValues(NaN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
49
+ private readonly _positionData = [0, 0, 0, 0];
44
50
 
45
51
  private _projectionMatrix = mat4.create();
46
52
  private _viewMatrix = mat4.create();
@@ -69,15 +75,11 @@ export class PerspectiveCamera implements ICamera {
69
75
  this.aspectRatio = descriptor?.aspectRatio ?? 1;
70
76
  this.nearPlane = descriptor?.near ?? 0.01;
71
77
  this.farPlane = descriptor?.far ?? 100;
72
- if (descriptor?.eye) {
73
- vec3.copy(this.eye, descriptor.eye);
74
- }
75
- if (descriptor?.target) {
76
- vec3.copy(this.target, descriptor.target);
77
- }
78
+ vec3.copy(this.transform.position, descriptor?.position ?? descriptor?.eye ?? [0, 0, -3]);
78
79
  if (descriptor?.up) {
79
- vec3.copy(this.up, descriptor.up);
80
+ this.setUp(descriptor.up);
80
81
  }
82
+ this.setTarget(descriptor?.target ?? [0, 0, 0]);
81
83
  if (scene) {
82
84
  scene.add(this);
83
85
  }
@@ -148,24 +150,56 @@ export class PerspectiveCamera implements ICamera {
148
150
  }
149
151
 
150
152
  /**
151
- * The eye position of the camera.
153
+ * The camera transform: the single source of the view. The camera looks down its local -Z axis;
154
+ * the view matrix is `inverse(T * R)` of `transform.modelMatrix` (scale is ignored).
155
+ * By default, at (0, 0, -3) looking at the origin.
152
156
  */
153
- public eye = vec3.fromValues(0,0,3);
157
+ public transform = new TransformNode();
154
158
 
155
- /**
156
- * The target position of the camera.
157
- */
158
- public target = vec3.create();
159
+ /** The unit direction the camera looks in, from the transform. */
160
+ public get direction(): vec3 {
161
+ return CameraTransformUtilities.forwardFromWorld(this._direction, this.transform.modelMatrix);
162
+ }
163
+
164
+ private readonly _aim = new CameraAim(() => this.transform);
159
165
 
160
166
  /**
161
- * The up vector of the camera.
167
+ * Rotates the transform once so the camera looks at a world point, using the current up ({@link getUp}).
168
+ * Forgets the target stored by {@link setTarget}, so a later {@link setEye} does not re-aim.
169
+ * @param target The point to look at.
162
170
  */
163
- public up = vec3.fromValues(0,1,0);
171
+ public lookAt(target: vec3): void {
172
+ this._aim.lookAt(target);
173
+ }
164
174
 
165
- /** The direction of a camera. */
166
- public get direction(): vec3 {
167
- vec3.sub(this._direction, this.target, this.eye);
168
- return this._direction;
175
+ /** @inheritDoc */
176
+ public setEye(eye: vec3): void {
177
+ this._aim.setEye(eye);
178
+ }
179
+
180
+ /** @inheritDoc */
181
+ public getEye(out?: vec3): vec3 {
182
+ return this._aim.getEye(out);
183
+ }
184
+
185
+ /** @inheritDoc */
186
+ public setTarget(target: vec3): void {
187
+ this._aim.setTarget(target);
188
+ }
189
+
190
+ /** @inheritDoc */
191
+ public getTarget(out?: vec3): vec3 {
192
+ return this._aim.getTarget(out);
193
+ }
194
+
195
+ /** @inheritDoc */
196
+ public setUp(up: vec3): void {
197
+ this._aim.setUp(up);
198
+ }
199
+
200
+ /** @inheritDoc */
201
+ public getUp(out?: vec3): vec3 {
202
+ return this._aim.getUp(out);
169
203
  }
170
204
 
171
205
  /**
@@ -202,12 +236,13 @@ export class PerspectiveCamera implements ICamera {
202
236
  this._viewBuffer = this._framework.bufferFactory.createUniformBuffer(this.viewMatrix, bufferUsage);
203
237
  }
204
238
 
205
- /**
206
- * The eye in world space, as used by the view matrix: z is flipped for the right-handed look-at.
207
- * This is what {@link positionBuffer} holds, std140 `vec3` (padded to 16 bytes).
208
- */
239
+ /** The world position, std140 `vec3` (padded to 16 bytes). This is what {@link positionBuffer} holds. */
209
240
  private _worldEye(): number[] {
210
- return [this.eye[0], this.eye[1], -this.eye[2], 0];
241
+ const m = this.transform.modelMatrix;
242
+ this._positionData[0] = m[12];
243
+ this._positionData[1] = m[13];
244
+ this._positionData[2] = m[14];
245
+ return this._positionData;
211
246
  }
212
247
 
213
248
  /**
@@ -218,11 +253,12 @@ export class PerspectiveCamera implements ICamera {
218
253
  // Right-handed
219
254
  mat4.perspectiveNO(this._projectionMatrix, this.fieldOfView, this.aspectRatio, this.nearPlane, this.farPlane);
220
255
 
221
- // mat4 does not have right-handed look at, therefore swap z for right-handed matrix.
222
- this._tempVec3[0] = this.eye[0];
223
- this._tempVec3[1] = this.eye[1];
224
- this._tempVec3[2] = -this.eye[2];
225
- mat4.lookAt(this.viewMatrix, this._tempVec3, this.target, this.up);
256
+ // The view only changes when the transform's world matrix changed.
257
+ const world = this.transform.modelMatrix;
258
+ if (!mat4.exactEquals(this._lastWorld, world)) {
259
+ mat4.copy(this._lastWorld, world);
260
+ CameraTransformUtilities.viewFromWorld(this.viewMatrix, world);
261
+ }
226
262
  mat4.multiply(this.projectionViewMatrix, this.projectionMatrix, this.viewMatrix);
227
263
  }
228
264
 
@@ -1,3 +1,4 @@
1
+ import {ColorSpace} from "../rendering/enums.ts";
1
2
  import {
2
3
  type IShaderModule,
3
4
  type IContentManager,
@@ -94,7 +95,10 @@ export class ContentManager implements IContentManager {
94
95
  return tex;
95
96
  }
96
97
 
97
- let format = this._framework.renderer.preferredTextureFormat;
98
+ // The descriptor's color space overrides the renderer's; an explicit format overrides both.
99
+ let format = desc.preferredColorSpace
100
+ ? (desc.preferredColorSpace == ColorSpace.SRGB ? TextureFormat.RGBA_8_UNORM_SRGB : TextureFormat.RGBA_8_UNORM)
101
+ : this._framework.renderer.preferredTextureFormat;
98
102
 
99
103
  if (desc.textureFormat != TextureFormat.UNDEFINED) {
100
104
  format = desc.textureFormat;
@@ -103,13 +107,12 @@ export class ContentManager implements IContentManager {
103
107
  const imageLoader = this._framework.imageLoader;
104
108
  const data = await imageLoader.loadAsync(path, contentConfig?.keepDataCached);
105
109
 
106
- // TODO: pass texture descriptor
107
110
  return this._framework.textureFactory.create(
108
111
  data.baseWidth, data.baseHeight,
109
112
  data.getData(0) as Uint8Array,
110
113
  data.channels,
111
- path,
112
- TextureUsage.TEXTURE_BINDING | TextureUsage.COPY_SRC,
114
+ desc.label ?? path,
115
+ textureDescriptor?.textureUsage ?? (TextureUsage.TEXTURE_BINDING | TextureUsage.COPY_SRC),
113
116
  format,
114
117
  desc.generateMipmaps
115
118
  );
@@ -118,7 +121,8 @@ export class ContentManager implements IContentManager {
118
121
  /** @inheritDoc */
119
122
  public loadTexture2DFromPixels(width: number, height: number, pixels: ArrayBuffer): ITexture2D {
120
123
  const view = new Uint8Array(pixels);
121
- return this._framework.textureFactory.create(width, height, view);
124
+ // Raw pixels keep the old linear default.
125
+ return this._framework.textureFactory.create(width, height, view, 4, undefined, undefined, TextureFormat.RGBA_8_UNORM);
122
126
  }
123
127
 
124
128
  /** @inheritDoc */
@@ -1,6 +1,8 @@
1
1
  import {Color} from "../data/Color.ts";
2
2
  import {createLightId} from "./LightId.ts";
3
3
  import type {Scene} from "../scene/Scene.ts";
4
+ import type {ILight} from "./ILight.ts";
5
+ import {TransformNode} from "../scene/node/TransformNode.ts";
4
6
 
5
7
  /** The descriptor for an ambient light. All fields are optional. */
6
8
  export interface AmbientLightDescriptor {
@@ -18,11 +20,12 @@ export interface AmbientLightDescriptor {
18
20
  }
19
21
 
20
22
  /**
21
- * The ambient light. Plain data: it has no GPU resources.
23
+ * The ambient light. Plain data: it has no GPU resources. It has a {@link transform} (so it can live in `scene.nodes`),
24
+ * but the transform has no effect on the lighting.
22
25
  * Put it into a {@link LightsBuffer} to use it in shaders.
23
26
  * @public
24
27
  */
25
- export class AmbientLight {
28
+ export class AmbientLight implements ILight {
26
29
 
27
30
  /**
28
31
  * The constructor.
@@ -39,6 +42,9 @@ export class AmbientLight {
39
42
  scene?.add(this);
40
43
  }
41
44
 
45
+ /** The transform. It has no effect on an ambient light. */
46
+ public transform: TransformNode = new TransformNode();
47
+
42
48
  /** The unique id of this light. */
43
49
  public readonly id: number;
44
50