ris-framework 0.1.0 → 0.2.0-dev.11

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 (217) hide show
  1. package/CHANGELOG.md +49 -1
  2. package/README.md +15 -4
  3. package/dist/Framework.d.ts +9 -3
  4. package/dist/Framework.d.ts.map +1 -1
  5. package/dist/api/IFramework.d.ts +7 -6
  6. package/dist/api/IFramework.d.ts.map +1 -1
  7. package/dist/api/_export.d.ts +2 -0
  8. package/dist/api/_export.d.ts.map +1 -1
  9. package/dist/api/camera/CameraFactory.d.ts +3 -2
  10. package/dist/api/camera/CameraFactory.d.ts.map +1 -1
  11. package/dist/api/camera/ICamera.d.ts +5 -0
  12. package/dist/api/camera/ICamera.d.ts.map +1 -1
  13. package/dist/api/camera/ICameraFactory.d.ts +5 -6
  14. package/dist/api/camera/ICameraFactory.d.ts.map +1 -1
  15. package/dist/api/camera/OrthographicCamera.d.ts +7 -0
  16. package/dist/api/camera/OrthographicCamera.d.ts.map +1 -1
  17. package/dist/api/camera/PerspectiveCamera.d.ts +30 -6
  18. package/dist/api/camera/PerspectiveCamera.d.ts.map +1 -1
  19. package/dist/api/content/ContentManager.d.ts +67 -2
  20. package/dist/api/content/ContentManager.d.ts.map +1 -1
  21. package/dist/api/content/IContentManager.d.ts +32 -1
  22. package/dist/api/content/IContentManager.d.ts.map +1 -1
  23. package/dist/api/content/ShaderModuleContent.d.ts.map +1 -1
  24. package/dist/api/data/Color.d.ts +5 -0
  25. package/dist/api/data/Color.d.ts.map +1 -1
  26. package/dist/api/geometry/BaseGeometry.d.ts +9 -0
  27. package/dist/api/geometry/BaseGeometry.d.ts.map +1 -1
  28. package/dist/api/geometry/GeometryBuilder.d.ts +3 -1
  29. package/dist/api/geometry/GeometryBuilder.d.ts.map +1 -1
  30. package/dist/api/geometry/IGeometryBuilder.d.ts +24 -0
  31. package/dist/api/geometry/IGeometryBuilder.d.ts.map +1 -1
  32. package/dist/api/geometry/_export-geometry.d.ts +1 -0
  33. package/dist/api/geometry/_export-geometry.d.ts.map +1 -1
  34. package/dist/api/input/InputManager.d.ts +4 -0
  35. package/dist/api/input/InputManager.d.ts.map +1 -1
  36. package/dist/api/lights/AmbientLight.d.ts +35 -0
  37. package/dist/api/lights/AmbientLight.d.ts.map +1 -0
  38. package/dist/api/lights/DirectionalLight.d.ts +40 -0
  39. package/dist/api/lights/DirectionalLight.d.ts.map +1 -0
  40. package/dist/api/lights/LightFactory.d.ts +18 -0
  41. package/dist/api/lights/LightFactory.d.ts.map +1 -0
  42. package/dist/api/lights/LightId.d.ts +6 -0
  43. package/dist/api/lights/LightId.d.ts.map +1 -0
  44. package/dist/api/lights/LightsBuffer.d.ts +70 -0
  45. package/dist/api/lights/LightsBuffer.d.ts.map +1 -0
  46. package/dist/api/lights/PointLight.d.ts +59 -0
  47. package/dist/api/lights/PointLight.d.ts.map +1 -0
  48. package/dist/api/lights/_export.d.ts +6 -0
  49. package/dist/api/lights/_export.d.ts.map +1 -0
  50. package/dist/api/loaders/ObjGeometryMapper.d.ts +19 -0
  51. package/dist/api/loaders/ObjGeometryMapper.d.ts.map +1 -0
  52. package/dist/api/loaders/_export.d.ts +1 -0
  53. package/dist/api/loaders/_export.d.ts.map +1 -1
  54. package/dist/api/loaders/obj/ObjLoader.d.ts +29 -0
  55. package/dist/api/loaders/obj/ObjLoader.d.ts.map +1 -0
  56. package/dist/api/loaders/obj/ObjTypes.d.ts +103 -0
  57. package/dist/api/loaders/obj/ObjTypes.d.ts.map +1 -0
  58. package/dist/api/loaders/obj/index.d.ts +3 -0
  59. package/dist/api/loaders/obj/index.d.ts.map +1 -0
  60. package/dist/api/material/ForwardBlinnPhongMaterial.d.ts +127 -0
  61. package/dist/api/material/ForwardBlinnPhongMaterial.d.ts.map +1 -0
  62. package/dist/api/material/IMaterial.d.ts +15 -6
  63. package/dist/api/material/IMaterial.d.ts.map +1 -1
  64. package/dist/api/material/IMaterialFactory.d.ts +17 -2
  65. package/dist/api/material/IMaterialFactory.d.ts.map +1 -1
  66. package/dist/api/material/InspectTextureMipsMaterial.d.ts +16 -7
  67. package/dist/api/material/InspectTextureMipsMaterial.d.ts.map +1 -1
  68. package/dist/api/material/MaterialFactory.d.ts +6 -0
  69. package/dist/api/material/MaterialFactory.d.ts.map +1 -1
  70. package/dist/api/material/SpriteMaterial.d.ts +51 -0
  71. package/dist/api/material/SpriteMaterial.d.ts.map +1 -0
  72. package/dist/api/material/UnlitMaterial.d.ts +28 -10
  73. package/dist/api/material/UnlitMaterial.d.ts.map +1 -1
  74. package/dist/api/material/_export.d.ts +2 -0
  75. package/dist/api/material/_export.d.ts.map +1 -1
  76. package/dist/api/meshes/IMesh.d.ts +35 -5
  77. package/dist/api/meshes/IMesh.d.ts.map +1 -1
  78. package/dist/api/meshes/IMeshFactory.d.ts +25 -4
  79. package/dist/api/meshes/IMeshFactory.d.ts.map +1 -1
  80. package/dist/api/meshes/Mesh.d.ts +58 -6
  81. package/dist/api/meshes/Mesh.d.ts.map +1 -1
  82. package/dist/api/meshes/MeshFactory.d.ts +7 -3
  83. package/dist/api/meshes/MeshFactory.d.ts.map +1 -1
  84. package/dist/api/meshes/QuadMesh.d.ts +5 -1
  85. package/dist/api/meshes/QuadMesh.d.ts.map +1 -1
  86. package/dist/api/meshes/SubMesh.d.ts +47 -0
  87. package/dist/api/meshes/SubMesh.d.ts.map +1 -0
  88. package/dist/api/meshes/_export.d.ts +1 -0
  89. package/dist/api/meshes/_export.d.ts.map +1 -1
  90. package/dist/api/rendering/render-pipelines/IForwardBlinnPhongRenderPipeline.d.ts +56 -0
  91. package/dist/api/rendering/render-pipelines/IForwardBlinnPhongRenderPipeline.d.ts.map +1 -0
  92. package/dist/api/rendering/render-pipelines/IRenderPipeline.d.ts +3 -0
  93. package/dist/api/rendering/render-pipelines/IRenderPipeline.d.ts.map +1 -1
  94. package/dist/api/rendering/render-pipelines/IRenderPipelineFactory.d.ts +29 -0
  95. package/dist/api/rendering/render-pipelines/IRenderPipelineFactory.d.ts.map +1 -1
  96. package/dist/api/rendering/render-pipelines/_export-render-pipelines.d.ts +1 -0
  97. package/dist/api/rendering/render-pipelines/_export-render-pipelines.d.ts.map +1 -1
  98. package/dist/api/scene/Scene.d.ts +104 -0
  99. package/dist/api/scene/Scene.d.ts.map +1 -0
  100. package/dist/api/shader/IShaderModuleLoader.d.ts +4 -1
  101. package/dist/api/shader/IShaderModuleLoader.d.ts.map +1 -1
  102. package/dist/api/shader/{shader-loader.d.ts → ShaderLoader.d.ts} +1 -1
  103. package/dist/api/shader/ShaderLoader.d.ts.map +1 -0
  104. package/dist/api/sprites/SpriteBatchDrawable.d.ts +1 -1
  105. package/dist/api/sprites/SpriteBatchDrawable.d.ts.map +1 -1
  106. package/dist/api/sprites/SpriteBatchMesh.d.ts +14 -1
  107. package/dist/api/sprites/SpriteBatchMesh.d.ts.map +1 -1
  108. package/dist/api/utilities/GeometryUtilities.d.ts.map +1 -1
  109. package/dist/api/window/WindowManager.d.ts +4 -0
  110. package/dist/api/window/WindowManager.d.ts.map +1 -1
  111. package/dist/core/rendering/vertex-buffer-layout.d.ts +1 -0
  112. package/dist/core/rendering/vertex-buffer-layout.d.ts.map +1 -1
  113. package/dist/index.js +2252 -260
  114. package/dist/webgl/WebGlGraphicsDevice.d.ts.map +1 -1
  115. package/dist/webgl/lights/WebGlAmbientLightFactory.d.ts +17 -0
  116. package/dist/webgl/lights/WebGlAmbientLightFactory.d.ts.map +1 -0
  117. package/dist/webgl/lights/WebGlLightsBuffer.d.ts +55 -0
  118. package/dist/webgl/lights/WebGlLightsBuffer.d.ts.map +1 -0
  119. package/dist/webgl/render-pipelines/AWebGlRenderPipeline.d.ts +3 -1
  120. package/dist/webgl/render-pipelines/AWebGlRenderPipeline.d.ts.map +1 -1
  121. package/dist/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.d.ts +3 -0
  122. package/dist/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.d.ts.map +1 -1
  123. package/dist/webgl/render-pipelines/WebGlRenderPipelineFactory.d.ts +3 -1
  124. package/dist/webgl/render-pipelines/WebGlRenderPipelineFactory.d.ts.map +1 -1
  125. package/dist/webgl/render-pipelines/inspect/WebGlInspectTextureMipsRenderPipeline.d.ts +3 -1
  126. package/dist/webgl/render-pipelines/inspect/WebGlInspectTextureMipsRenderPipeline.d.ts.map +1 -1
  127. package/dist/webgl/render-pipelines/material/WebGlBlinnPhongRenderPipeline.d.ts +88 -0
  128. package/dist/webgl/render-pipelines/material/WebGlBlinnPhongRenderPipeline.d.ts.map +1 -0
  129. package/dist/webgl/render-pipelines/material/WebGlUnlitRenderPipeline.d.ts +3 -1
  130. package/dist/webgl/render-pipelines/material/WebGlUnlitRenderPipeline.d.ts.map +1 -1
  131. package/dist/webgl/render-pipelines/sprite/WebGlSpriteRenderPipeline.d.ts +3 -1
  132. package/dist/webgl/render-pipelines/sprite/WebGlSpriteRenderPipeline.d.ts.map +1 -1
  133. package/dist/webgl/shader/WebGlShaderModule.d.ts +4 -1
  134. package/dist/webgl/shader/WebGlShaderModule.d.ts.map +1 -1
  135. package/dist/webgl/shader/WebGlShaderModuleLoader.d.ts +16 -5
  136. package/dist/webgl/shader/WebGlShaderModuleLoader.d.ts.map +1 -1
  137. package/dist/webgl/texture/WebGlTexture2D.d.ts +8 -1
  138. package/dist/webgl/texture/WebGlTexture2D.d.ts.map +1 -1
  139. package/dist/webgl/utilities/webgl-filter-anisotropic-utilities.d.ts +0 -1
  140. package/dist/webgl/utilities/webgl-filter-anisotropic-utilities.d.ts.map +1 -1
  141. package/package.json +4 -4
  142. package/shaders/glsl/forward_blinn_phong_material_fs.glsl +110 -0
  143. package/shaders/glsl/forward_blinn_phong_material_vs.glsl +32 -0
  144. package/shaders/glsl/sprite_fs.glsl +1 -1
  145. package/shaders/glsl/unlit_material_fs.glsl +1 -1
  146. package/src/Framework.ts +37 -13
  147. package/src/api/IFramework.ts +8 -6
  148. package/src/api/_export.ts +2 -0
  149. package/src/api/camera/CameraFactory.ts +6 -6
  150. package/src/api/camera/ICamera.ts +6 -0
  151. package/src/api/camera/ICameraFactory.ts +5 -10
  152. package/src/api/camera/OrthographicCamera.ts +23 -1
  153. package/src/api/camera/PerspectiveCamera.ts +60 -15
  154. package/src/api/content/ContentManager.ts +201 -5
  155. package/src/api/content/IContentManager.ts +33 -1
  156. package/src/api/content/ShaderModuleContent.ts +9 -0
  157. package/src/api/data/Color.ts +7 -1
  158. package/src/api/geometry/BaseGeometry.ts +23 -0
  159. package/src/api/geometry/GeometryBuilder.ts +14 -2
  160. package/src/api/geometry/IGeometryBuilder.ts +31 -1
  161. package/src/api/geometry/_export-geometry.ts +2 -1
  162. package/src/api/input/InputManager.ts +14 -5
  163. package/src/api/lights/AmbientLight.ts +53 -0
  164. package/src/api/lights/DirectionalLight.ts +60 -0
  165. package/src/api/lights/LightFactory.ts +21 -0
  166. package/src/api/lights/LightId.ts +9 -0
  167. package/src/api/lights/LightsBuffer.ts +87 -0
  168. package/src/api/lights/PointLight.ts +91 -0
  169. package/src/api/lights/_export.ts +5 -0
  170. package/src/api/loaders/ObjGeometryMapper.ts +28 -0
  171. package/src/api/loaders/_export.ts +2 -1
  172. package/src/api/loaders/obj/ObjLoader.ts +270 -0
  173. package/src/api/loaders/obj/ObjTypes.ts +124 -0
  174. package/src/api/loaders/obj/index.ts +5 -0
  175. package/src/api/material/ForwardBlinnPhongMaterial.ts +302 -0
  176. package/src/api/material/IMaterial.ts +16 -6
  177. package/src/api/material/IMaterialFactory.ts +19 -2
  178. package/src/api/material/InspectTextureMipsMaterial.ts +63 -24
  179. package/src/api/material/MaterialFactory.ts +12 -0
  180. package/src/api/material/SpriteMaterial.ts +83 -0
  181. package/src/api/material/UnlitMaterial.ts +101 -29
  182. package/src/api/material/_export.ts +3 -1
  183. package/src/api/meshes/IMesh.ts +45 -6
  184. package/src/api/meshes/IMeshFactory.ts +27 -4
  185. package/src/api/meshes/Mesh.ts +163 -41
  186. package/src/api/meshes/MeshFactory.ts +30 -6
  187. package/src/api/meshes/QuadMesh.ts +6 -2
  188. package/src/api/meshes/SubMesh.ts +71 -0
  189. package/src/api/meshes/_export.ts +1 -0
  190. package/src/api/rendering/render-pipelines/IForwardBlinnPhongRenderPipeline.ts +66 -0
  191. package/src/api/rendering/render-pipelines/IRenderPipeline.ts +4 -0
  192. package/src/api/rendering/render-pipelines/IRenderPipelineFactory.ts +39 -0
  193. package/src/api/rendering/render-pipelines/_export-render-pipelines.ts +2 -1
  194. package/src/api/scene/Scene.ts +264 -0
  195. package/src/api/shader/IShaderModuleLoader.ts +2 -1
  196. package/src/api/sprites/SpriteBatchDrawable.ts +12 -16
  197. package/src/api/sprites/SpriteBatchMesh.ts +23 -4
  198. package/src/api/utilities/GeometryUtilities.ts +2 -0
  199. package/src/api/window/WindowManager.ts +22 -2
  200. package/src/core/rendering/vertex-buffer-layout.ts +32 -1
  201. package/src/main.ts +0 -1
  202. package/src/webgl/WebGlGraphicsDevice.ts +0 -1
  203. package/src/webgl/lights/WebGlAmbientLightFactory.ts +35 -0
  204. package/src/webgl/lights/WebGlLightsBuffer.ts +215 -0
  205. package/src/webgl/render-pipelines/AWebGlRenderPipeline.ts +7 -1
  206. package/src/webgl/render-pipelines/WebGlMainRenderTargetRenderPipeline.ts +3 -0
  207. package/src/webgl/render-pipelines/WebGlRenderPipelineFactory.ts +24 -2
  208. package/src/webgl/render-pipelines/inspect/WebGlInspectTextureMipsRenderPipeline.ts +16 -6
  209. package/src/webgl/render-pipelines/material/WebGlBlinnPhongRenderPipeline.ts +300 -0
  210. package/src/webgl/render-pipelines/material/WebGlUnlitRenderPipeline.ts +16 -6
  211. package/src/webgl/render-pipelines/sprite/WebGlSpriteRenderPipeline.ts +11 -7
  212. package/src/webgl/shader/WebGlShaderModule.ts +11 -4
  213. package/src/webgl/shader/WebGlShaderModuleLoader.ts +29 -10
  214. package/src/webgl/texture/WebGlTexture2D.ts +19 -5
  215. package/src/webgl/utilities/webgl-filter-anisotropic-utilities.ts +9 -6
  216. package/dist/api/shader/shader-loader.d.ts.map +0 -1
  217. /package/src/api/shader/{shader-loader.ts → ShaderLoader.ts} +0 -0
@@ -7,7 +7,7 @@ in vec2 v_texCoords;
7
7
  layout(location = 0) out vec4 o_outputColor;
8
8
 
9
9
  layout(std140) uniform MaterialBuffer
10
- {
10
+ {
11
11
  vec4 diffuseColor;
12
12
  };
13
13
 
package/src/Framework.ts CHANGED
@@ -1,7 +1,7 @@
1
- import {container, type DependencyContainer} from "tsyringe";
1
+ import {WebGlAmbientLightFactory} from "./webgl/lights/WebGlAmbientLightFactory.ts";
2
2
  import {WindowManager} from "./api/window/WindowManager.ts";
3
3
  import {FrameworkConfiguration} from "./api/FrameworkConfiguration.ts";
4
- import {type IRendererConfiguration, RenderConfigurationSymbol} from "./api/rendering/renderer-interface.ts";
4
+ import {type IRendererConfiguration} from "./api/rendering/renderer-interface.ts";
5
5
  import {GeometryBuilder} from "./api/geometry/GeometryBuilder.ts";
6
6
  import {ContentManager} from "./api/content/ContentManager.ts";
7
7
  import {WebGlRenderer} from "./webgl/WebGlRenderer.ts";
@@ -26,6 +26,7 @@ import {
26
26
  type IInputManager,
27
27
  ImageLoader,
28
28
  type IMaterialFactory,
29
+ type AmbientLightFactory,
29
30
  type IMeshFactory,
30
31
  type ISpriteBatch,
31
32
  type ITextureFactory,
@@ -35,6 +36,8 @@ import {
35
36
  RenderingBackend,
36
37
  TimeManager
37
38
  } from "./api/index.ts";
39
+ import {WebGlTexture2D} from "./webgl/texture/WebGlTexture2D.ts";
40
+ import type {IDisposable} from "./api/core/IDisposable.ts";
38
41
  import {WebGlShaderModuleLoader} from "./webgl/shader/WebGlShaderModuleLoader.ts";
39
42
  import {TextureSamplerFilteringPreset} from "./core/rendering/enums.ts";
40
43
  import {SpriteBatch} from "./api/sprites/SpriteBatch.ts";
@@ -53,12 +56,12 @@ export class Framework implements IFramework {
53
56
  private readonly _onUpdateListeners: ((gameTime: GameTime) => void)[] = [];
54
57
  private readonly _onRenderListeners: (() => void)[] = [];
55
58
 
56
- private readonly _container: DependencyContainer;
57
59
  private readonly _textureFactory: ITextureFactory;
58
60
  private readonly _buffersFactory: IBufferFactory;
59
61
  private readonly _contentManager: IContentManager;
60
62
  private readonly _geometryBuilder: IGeometryBuilder;
61
63
  private readonly _meshFactory: IMeshFactory;
64
+ private _disposed = false;
62
65
 
63
66
  /**
64
67
  * The constructor for the Framework class.
@@ -73,17 +76,15 @@ export class Framework implements IFramework {
73
76
  }
74
77
  options.backBufferSize = options.backBufferSize ?? vec2.fromValues(800, 600);
75
78
 
76
- this._container = container.createChildContainer();
77
79
  this.windowManager = new WindowManager(options.canvas ?? null);
78
80
 
79
- // Setup container.
81
+ // Services are created here and get their dependencies through their constructors.
80
82
  const rendererConfig: IRendererConfiguration = {
81
83
  backBufferSize: options.backBufferSize,
82
84
  textureFiltering: options.textureFiltering ?? TextureSamplerFilteringPreset.BILINEAR,
83
85
  alpha: options.alpha ?? false,
84
86
  powerPreference: options.powerPreference ?? PowerPreferenceType.DEFAULT
85
87
  };
86
- this._container.registerInstance(RenderConfigurationSymbol, rendererConfig);
87
88
  this.renderer = new WebGlRenderer(this, rendererConfig);
88
89
  this.renderingBackend = RenderingBackend.WEB_GL;
89
90
  this._textureFactory = new WebGlTextureFactory(this);
@@ -92,6 +93,7 @@ export class Framework implements IFramework {
92
93
  this._contentManager = new ContentManager(this, new WebGlShaderModuleLoader(this));
93
94
  this._meshFactory = new MeshFactory(this);
94
95
  this.materialFactory = new MaterialFactory(this);
96
+ this.lightsFactory = new WebGlAmbientLightFactory(this);
95
97
 
96
98
  this._buffersFactory = new WebGlBuffersFactory(this);
97
99
  this.spriteBatch = new SpriteBatch(this);
@@ -216,6 +218,9 @@ export class Framework implements IFramework {
216
218
  /** @inheritDoc */
217
219
  public readonly materialFactory: IMaterialFactory;
218
220
 
221
+ /** @inheritDoc */
222
+ public readonly lightsFactory: AmbientLightFactory;
223
+
219
224
  /** @inheritDoc */
220
225
  public readonly timeManager: ITimeManager;
221
226
 
@@ -235,12 +240,13 @@ export class Framework implements IFramework {
235
240
 
236
241
  this.timeManager.prepareStart();
237
242
 
238
- // Load content events.
239
- for(const listener of this._onLoadContentListeners){
243
+ // Initialize callbacks.
244
+ for(const listener of this._onInitializeListeners){
240
245
  listener();
241
246
  }
242
247
 
243
- for(const listener of this._onInitializeListeners){
248
+ // Load content events.
249
+ for(const listener of this._onLoadContentListeners){
244
250
  listener();
245
251
  }
246
252
 
@@ -271,10 +277,28 @@ export class Framework implements IFramework {
271
277
  this.windowManager.runEventLoop();
272
278
  }
273
279
 
274
- /** @inheritDoc */
275
- public dispose() {
276
- // this.windowManager.dispose();
280
+ /**
281
+ * Stops the event loop and disposes the framework's services and GL resources,
282
+ * including per-framework caches such as the default texture and the shader modules.
283
+ * A new `Framework` afterwards creates fresh resources on its own context. Calling it twice does nothing.
284
+ */
285
+ public dispose(): void {
286
+ if (this._disposed) {
287
+ return;
288
+ }
289
+ this._disposed = true;
290
+
291
+ this.windowManager.dispose();
292
+ (this.input as Partial<IDisposable>).dispose?.();
293
+
294
+ this._onLoadContentListeners.length = 0;
295
+ this._onInitializeListeners.length = 0;
296
+ this._onUpdateListeners.length = 0;
297
+ this._onRenderListeners.length = 0;
277
298
 
278
- // TODO: dispose of other resources
299
+ WebGlTexture2D.disposeDefault(this);
300
+ (this._contentManager as Partial<IDisposable>).dispose?.();
301
+ // Only exists after initialize(); it owns the default sampler and blend state.
302
+ (this.renderer.graphicsDevice as IGraphicsDevice | undefined)?.dispose();
279
303
  }
280
304
  }
@@ -11,6 +11,7 @@ import type { IContentManager } from "./content/IContentManager.ts";
11
11
  import type { IImageLoader } from "./loaders/IImageLoader.ts";
12
12
  import type { IMeshFactory } from "./meshes/IMeshFactory.ts";
13
13
  import type { IMaterialFactory } from "./material/IMaterialFactory.ts";
14
+ import type { AmbientLightFactory } from "./lights/LightFactory.ts";
14
15
  import type { ITimeManager } from "./time/ITimeManager.ts";
15
16
  import type { IInputManager } from "./input/IInputManager.ts";
16
17
  import type { IWindowManager } from "./window/IWindowManager.ts";
@@ -91,6 +92,11 @@ export interface IFramework extends IDisposable {
91
92
  */
92
93
  readonly materialFactory: IMaterialFactory;
93
94
 
95
+ /**
96
+ * The ambient light factory.
97
+ */
98
+ readonly lightsFactory: AmbientLightFactory;
99
+
94
100
  /**
95
101
  * The time manager.
96
102
  */
@@ -117,14 +123,10 @@ export interface IFramework extends IDisposable {
117
123
  */
118
124
  removeOnLoadContentListener(event: () => void): void;
119
125
 
120
- /**
121
- * Called when the framework is initialized.
122
- */
126
+ /** Called when the framework is initialized.*/
123
127
  addOnInitializedListener(event: () => void): void;
124
128
 
125
- /**
126
- * Called when the framework is initialized.
127
- */
129
+ /** Called when the framework is initialized.*/
128
130
  removeOnInitializedListener(event: () => void): void;
129
131
 
130
132
  /**
@@ -22,5 +22,7 @@ export * from "./rendering/sampler/_export.ts"
22
22
  export * from "./utilities/_export.ts"
23
23
  export * from "./meshes/_export.ts";
24
24
  export * from "./material/_export.ts";
25
+ export * from "./lights/_export.ts";
26
+ export * from "./scene/Scene.ts";
25
27
  export * from "./input/_export.ts";
26
28
  export * from "./image/_export.ts";
@@ -1,11 +1,11 @@
1
1
  import {vec2} from "gl-matrix";
2
2
  import type { ICameraFactory } from "./ICameraFactory.ts";
3
+ import type { Scene } from "../scene/Scene.ts";
3
4
  import type { IFramework } from "../IFramework.ts";
4
5
  import type { IOrthographicCamera } from "./IOrthographicCamera.ts";
5
6
  import {OrthographicCamera} from "./OrthographicCamera.ts";
6
7
  import {OrbitCamera} from "./OrbitCamera.ts";
7
- import {PerspectiveCamera} from "./PerspectiveCamera.ts";
8
- import {MathHelper} from "../utilities/MathHelper.ts";
8
+ import {PerspectiveCamera, type PerspectiveCameraDescriptor} from "./PerspectiveCamera.ts";
9
9
 
10
10
  /** The Camera Factory */
11
11
  export class CameraFactory implements ICameraFactory {
@@ -41,15 +41,15 @@ export class CameraFactory implements ICameraFactory {
41
41
 
42
42
  /** @inheritDoc */
43
43
  public createOrbitCamera(fov = 60, aspectRatio = 1, near = 0.01, far = 100): OrbitCamera {
44
- return new OrbitCamera(this.createPerspectiveCamera(fov, aspectRatio, near, far), this._framework.input);
44
+ return new OrbitCamera(this.createPerspectiveCamera({fov, aspectRatio, near, far}), this._framework.input);
45
45
 
46
46
  }
47
47
 
48
48
  /** @inheritDoc */
49
- public createPerspectiveCamera(fov= 60, aspectRatio = 1, near= 0.01, far = 100): PerspectiveCamera {
50
- fov = MathHelper.toRadians(fov);
51
- const camera = new PerspectiveCamera(this._framework, fov, aspectRatio, near, far);
49
+ public createPerspectiveCamera(descriptor?: PerspectiveCameraDescriptor, scene? : Scene): PerspectiveCamera {
50
+ const camera = new PerspectiveCamera(this._framework, descriptor, scene);
52
51
  camera.initialize();
52
+
53
53
  return camera;
54
54
  }
55
55
 
@@ -36,6 +36,12 @@ export interface ICamera extends IDisposable {
36
36
  */
37
37
  readonly viewBuffer: IUniformBuffer;
38
38
 
39
+ /**
40
+ * The world-space eye position buffer, std140 `vec3` (`[x, y, z, 0]`).
41
+ * Used by lit materials for specular highlights.
42
+ */
43
+ readonly positionBuffer: IUniformBuffer;
44
+
39
45
  /**
40
46
  * Update the GPU buffers.
41
47
  * This needs to be called when camera properties are changed.
@@ -1,7 +1,8 @@
1
1
  import type { IOrthographicCamera } from "./IOrthographicCamera.ts";
2
2
  import {vec2} from "gl-matrix";
3
3
  import {OrbitCamera} from "./OrbitCamera.ts";
4
- import {PerspectiveCamera} from "./PerspectiveCamera.ts";
4
+ import {PerspectiveCamera, type PerspectiveCameraDescriptor} from "./PerspectiveCamera.ts";
5
+ import type {Scene} from "../scene/Scene.ts";
5
6
 
6
7
  /**
7
8
  * The camera factory.
@@ -10,17 +11,11 @@ export interface ICameraFactory {
10
11
 
11
12
  /**
12
13
  * Creates a new perspective camera.
13
- * @param fov The field of view. By default, 60 degrees.
14
- * @param aspectRatio The aspect ratio. By default, 1.
15
- * @param near The near plane. By default, 0.01.
16
- * @param far The far plane. By default, 100.
14
+ * @param descriptor The optional descriptor; omitted fields use the defaults documented on {@link PerspectiveCameraDescriptor}.
15
+ * @param scene The optional scene; the camera becomes its `scene.camera`.
17
16
  * @return The perspective camera.
18
17
  */
19
- createPerspectiveCamera(
20
- fov?: number,
21
- aspectRatio?: number,
22
- near?: number,
23
- far?: number): PerspectiveCamera;
18
+ createPerspectiveCamera(descriptor?: PerspectiveCameraDescriptor, scene?: Scene): PerspectiveCamera;
24
19
 
25
20
  /**
26
21
  * Creates a new orthographic camera which is suitable for 2D games, or for UI rendering.
@@ -40,6 +40,9 @@ export class OrthographicCamera implements IOrthographicCamera {
40
40
  private _projectionBuffer: IUniformBuffer = null!;
41
41
  private _viewBuffer: IUniformBuffer = null!;
42
42
  private _projectionViewBuffer: IUniformBuffer = null!;
43
+ private _positionBuffer: IUniformBuffer = null!;
44
+ /** std140 vec3 world-space eye, padded to 4 floats. */
45
+ private readonly _positionData = [0, 0, 0, 0];
43
46
 
44
47
  /**
45
48
  *
@@ -69,7 +72,7 @@ export class OrthographicCamera implements IOrthographicCamera {
69
72
  this._near = near;
70
73
  this._far = far;
71
74
 
72
- this._eye = vec3.fromValues(0, 0, -1);
75
+ this._eye = vec3.fromValues(0, 0, 1);
73
76
  this._target = vec3.fromValues(0, 0, 0);
74
77
 
75
78
  this._zSpaceLength = 2; // For WebGL2 it is 2, WebGPU it is 1.
@@ -204,6 +207,19 @@ export class OrthographicCamera implements IOrthographicCamera {
204
207
  return this._viewBuffer;
205
208
  }
206
209
 
210
+ /** @inheritDoc */
211
+ public get positionBuffer(): IUniformBuffer {
212
+ return this._positionBuffer;
213
+ }
214
+
215
+ /** Writes the world-space eye into the std140 position data (no z flip: the look-at uses the eye as is). */
216
+ private _updatePositionData(): number[] {
217
+ this._positionData[0] = this._eye[0];
218
+ this._positionData[1] = this._eye[1];
219
+ this._positionData[2] = this._eye[2];
220
+ return this._positionData;
221
+ }
222
+
207
223
  /**
208
224
  * Updates the camera matrices.
209
225
  */
@@ -227,6 +243,10 @@ export class OrthographicCamera implements IOrthographicCamera {
227
243
  this._projectionViewBuffer = this._framework.bufferFactory.createUniformBuffer(
228
244
  this._projectionViewMatrix, BufferUsage.UNIFORM, "OrthographicCamera.projectionViewBuffer"
229
245
  );
246
+
247
+ this._positionBuffer = this._framework.bufferFactory.createUniformBuffer(
248
+ this._updatePositionData(), BufferUsage.UNIFORM, "OrthographicCamera.positionBuffer"
249
+ );
230
250
  }
231
251
 
232
252
  /** @inheritDoc */
@@ -235,6 +255,7 @@ export class OrthographicCamera implements IOrthographicCamera {
235
255
  this.projectionBuffer.update(this.projectionMatrix);
236
256
  this.viewBuffer.update(this.viewMatrix);
237
257
  this.projectionViewBuffer.update(this.projectionViewMatrix);
258
+ this.positionBuffer.update(this._updatePositionData());
238
259
  }
239
260
 
240
261
  /** @inheritDoc */
@@ -253,5 +274,6 @@ export class OrthographicCamera implements IOrthographicCamera {
253
274
  this.projectionBuffer.dispose();
254
275
  this.projectionViewBuffer.dispose();
255
276
  this.viewBuffer.dispose();
277
+ this.positionBuffer.dispose();
256
278
  }
257
279
  }
@@ -5,6 +5,34 @@ import {MathHelper} from "../utilities/MathHelper.ts";
5
5
  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
+ import type {Scene} from "../scene/Scene.ts";
9
+
10
+ /**
11
+ * The descriptor for a perspective camera. Every field is optional.
12
+ */
13
+ export interface PerspectiveCameraDescriptor {
14
+
15
+ /** The vertical field of view in degrees. By default, 60. */
16
+ fov?: number;
17
+
18
+ /** The aspect ratio (width / height). By default, 1. */
19
+ aspectRatio?: number;
20
+
21
+ /** The near plane. By default, 0.01. */
22
+ near?: number;
23
+
24
+ /** The far plane. By default, 100. */
25
+ far?: number;
26
+
27
+ /** The eye position. Copied. By default, (0, 0, 3). */
28
+ eye?: vec3;
29
+
30
+ /** The point the camera looks at. Copied. By default, the origin. */
31
+ target?: vec3;
32
+
33
+ /** The up vector. Copied. By default, (0, 1, 0). */
34
+ up?: vec3;
35
+ }
8
36
 
9
37
  /**
10
38
  * The perspective camera.
@@ -26,24 +54,33 @@ export class PerspectiveCamera implements ICamera {
26
54
  private _projectionBuffer: IUniformBuffer = null!;
27
55
 
28
56
  /**
29
- * The constructor.
57
+ * The constructor. Call `initialize()` before use (the camera factory does).
30
58
  * @param framework The framework.
31
- * @param fov The field of view in radians.
32
- * @param aspectRatio The aspect ratio.
33
- * @param nearPlane The near plane.
34
- * @param farPlane The far plane.
59
+ * @param descriptor The optional descriptor; omitted fields use the defaults documented on {@link PerspectiveCameraDescriptor}.
60
+ * `fov` is in degrees; {@link fieldOfView} holds it in radians. Vectors are copied.
61
+ * @param scene The optional scene; the camera assigns itself as `scene.camera`.
35
62
  */
36
63
  public constructor(
37
64
  framework: IFramework,
38
- fov: number,
39
- aspectRatio: number,
40
- nearPlane: number,
41
- farPlane: number) {
65
+ descriptor?: PerspectiveCameraDescriptor,
66
+ scene?: Scene) {
42
67
  this._framework = framework;
43
- this.fieldOfView = fov;
44
- this.aspectRatio = aspectRatio;
45
- this.nearPlane = nearPlane;
46
- this.farPlane = farPlane;
68
+ this.fieldOfView = MathHelper.toRadians(descriptor?.fov ?? 60);
69
+ this.aspectRatio = descriptor?.aspectRatio ?? 1;
70
+ this.nearPlane = descriptor?.near ?? 0.01;
71
+ 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
+ if (descriptor?.up) {
79
+ vec3.copy(this.up, descriptor.up);
80
+ }
81
+ if (scene) {
82
+ scene.add(this);
83
+ }
47
84
 
48
85
  this._updateMatrices();
49
86
  }
@@ -159,12 +196,20 @@ export class PerspectiveCamera implements ICamera {
159
196
  */
160
197
  public initialize(): void {
161
198
  const bufferUsage = BufferUsage.UNIFORM | BufferUsage.COPY_DST;
162
- this._positionBuffer = this._framework.bufferFactory.createUniformBuffer(this.eye, bufferUsage);
199
+ this._positionBuffer = this._framework.bufferFactory.createUniformBuffer(this._worldEye(), bufferUsage);
163
200
  this._projectionViewBuffer = this._framework.bufferFactory.createUniformBuffer(this.projectionViewMatrix, bufferUsage);
164
201
  this._projectionBuffer = this._framework.bufferFactory.createUniformBuffer(this.projectionMatrix, bufferUsage);
165
202
  this._viewBuffer = this._framework.bufferFactory.createUniformBuffer(this.viewMatrix, bufferUsage);
166
203
  }
167
204
 
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
+ */
209
+ private _worldEye(): number[] {
210
+ return [this.eye[0], this.eye[1], -this.eye[2], 0];
211
+ }
212
+
168
213
  /**
169
214
  * Updates the camera matrices.
170
215
  */
@@ -190,7 +235,7 @@ export class PerspectiveCamera implements ICamera {
190
235
 
191
236
  /** @inheritDoc */
192
237
  public updateBuffers(): void {
193
- this._positionBuffer.update(this.eye);
238
+ this._positionBuffer.update(this._worldEye());
194
239
  this._projectionBuffer.update(this.projectionMatrix);
195
240
  this._viewBuffer.update(this.viewMatrix);
196
241
  this._projectionViewBuffer.update(this.projectionViewMatrix);
@@ -3,12 +3,29 @@ import {
3
3
  type IContentManager,
4
4
  type IShaderModuleLoader,
5
5
  type ITexture2D,
6
- type IFramework, TextureDescriptor, TextureFormat, ContentConfig, TextureUsage
6
+ type IFramework,
7
+ TextureDescriptor,
8
+ TextureFormat,
9
+ ContentConfig,
10
+ TextureUsage,
11
+ type IMesh,
12
+ ObjLoader,
13
+ Color,
14
+ type ICamera,
15
+ type IMaterial,
16
+ type ObjMaterialDefinition,
17
+ type SubMeshDescriptor,
18
+ type ObjLoadResult,
19
+ type ObjGeometryDefinition,
20
+ type IGeometry,
21
+ type LightsBuffer,
22
+ type Scene,
23
+ type IDisposable,
7
24
  } from "../index.ts";
25
+ import {ObjGeometryMapper} from "../loaders/ObjGeometryMapper.ts";
8
26
  import {Ktx2Factory} from "ris-ktx2";
9
27
  import type {IKtx2Texture} from "ris-ktx2";
10
28
 
11
-
12
29
  /**
13
30
  * The content manager.
14
31
  * The content manager is responsible for managing the content modules and loading the content with the given asset file path or identifier.
@@ -17,6 +34,7 @@ export class ContentManager implements IContentManager {
17
34
 
18
35
  private readonly _ktx2Factory = new Ktx2Factory();
19
36
  private readonly _ktx2TextureCache: {[key: string]: IKtx2Texture} = {};
37
+ private readonly _objLoader = new ObjLoader();
20
38
 
21
39
  /**
22
40
  * The constructor.
@@ -41,9 +59,20 @@ export class ContentManager implements IContentManager {
41
59
  return ktx2Texture;
42
60
  }
43
61
 
62
+ /**
63
+ * Disposes the cached shader modules (their GL programs) and forgets cached KTX2 data.
64
+ * Called from `Framework.dispose()`.
65
+ */
66
+ public dispose(): void {
67
+ (this.shaderModuleLoader as Partial<IDisposable>).dispose?.();
68
+ for (const key of Object.keys(this._ktx2TextureCache)) {
69
+ delete this._ktx2TextureCache[key];
70
+ }
71
+ }
72
+
44
73
  /** @inheritDoc */
45
- public loadShaderModule(shaderModuleId: string): IShaderModule {
46
- return this.shaderModuleLoader.load(shaderModuleId);
74
+ public loadShaderModule(shaderModuleId: string, keyValueDictionary?: { [id:string]: number}): IShaderModule {
75
+ return this.shaderModuleLoader.load(shaderModuleId, keyValueDictionary);
47
76
  }
48
77
 
49
78
  /** @inheritDoc */
@@ -84,4 +113,171 @@ export class ContentManager implements IContentManager {
84
113
  return this._framework.textureFactory.create(width, height, view);
85
114
  }
86
115
 
87
- }
116
+ /** @inheritDoc */
117
+ public async loadMeshAsync(path: string, scene: Scene): Promise<IMesh> {
118
+
119
+ const objResult = await this._loadObj(path);
120
+ const geometry = this._createGeometry(objResult.geometry);
121
+ const subMeshes = this._createSubMeshDescriptors(objResult,
122
+ definition => this._createUnlitMaterial(definition, scene.camera));
123
+
124
+ return this._framework.meshFactory.createWithSubMeshes(scene, geometry, subMeshes);
125
+ }
126
+
127
+ /** @inheritDoc */
128
+ public async loadBlinnPhongMeshAsync(path: string, scene: Scene): Promise<IMesh> {
129
+ // Checked before loading, so a missing camera fails fast.
130
+ const camera = scene.camera;
131
+ if (!camera) {
132
+ throw new Error(`loadBlinnPhongMeshAsync("${path}"): the scene has no camera. Set scene.camera (or pass the scene to createPerspectiveCamera) before loading a Blinn-Phong mesh.`);
133
+ }
134
+ if (!camera.positionBuffer || !camera.projectionViewBuffer) {
135
+ const what = [camera.projectionViewBuffer ? undefined : "projectionViewBuffer", camera.positionBuffer ? undefined : "positionBuffer"]
136
+ .filter(x => x !== undefined).join(" and ");
137
+ throw new Error(`loadBlinnPhongMeshAsync("${path}"): the scene camera has no ${what}. Call camera.initialize() first (the camera factory does).`);
138
+ }
139
+ const objResult = await this._loadObj(path);
140
+ const geometry = this._createGeometry(objResult.geometry);
141
+ const subMeshes = this._createSubMeshDescriptors(objResult,
142
+ definition => this._createBlinnPhongMaterial(definition, camera, scene.__forwardLightsBuffer));
143
+
144
+ return this._framework.meshFactory.createWithSubMeshes(scene, geometry, subMeshes);
145
+ }
146
+
147
+ /**
148
+ * Loads the OBJ file and its .mtl material libraries.
149
+ * @param path The path or url to the .obj file.
150
+ * @returns The plain OBJ data.
151
+ */
152
+ private _loadObj(path: string): Promise<ObjLoadResult> {
153
+ return this._objLoader.loadAsync(path);
154
+ }
155
+
156
+ /**
157
+ * Creates framework geometry from the OBJ geometry.
158
+ * Vertex colours stay white, because each submesh's material carries the colour.
159
+ * @param definition The OBJ geometry definition.
160
+ * @returns The geometry.
161
+ */
162
+ private _createGeometry(definition: ObjGeometryDefinition): IGeometry {
163
+ const descriptor = ObjGeometryMapper.toDescriptor(definition);
164
+ return this._framework.geometryBuilder.create(descriptor);
165
+ }
166
+
167
+
168
+ /**
169
+ * Creates one submesh descriptor per material range.
170
+ * Ranges that use the same material name share one material instance.
171
+ * @param objResult The loaded OBJ data.
172
+ * @param createMaterial Creates the material for a definition (undefined without `usemtl` or .mtl entry).
173
+ * @returns The submesh descriptors, in file order.
174
+ */
175
+ private _createSubMeshDescriptors(
176
+ objResult: ObjLoadResult,
177
+ createMaterial: (definition: ObjMaterialDefinition | undefined) => IMaterial): SubMeshDescriptor[] {
178
+
179
+ const definitionsByName = this._indexMaterialDefinitions(objResult.materials);
180
+ const materialsByName = new Map<string | undefined, IMaterial>();
181
+ const subMeshes: SubMeshDescriptor[] = [];
182
+
183
+ for (const range of objResult.geometry.materialRanges) {
184
+ let material = materialsByName.get(range.materialName);
185
+ if (material === undefined) {
186
+ const definition = this._findMaterialDefinition(definitionsByName, range.materialName);
187
+ material = createMaterial(definition);
188
+ materialsByName.set(range.materialName, material);
189
+ }
190
+
191
+ subMeshes.push({
192
+ material: material,
193
+ indexStart: range.indexStart,
194
+ indexCount: range.indexCount,
195
+ });
196
+ }
197
+
198
+ return subMeshes;
199
+ }
200
+
201
+ /**
202
+ * Indexes material definitions by name.
203
+ * @param definitions The material definitions from the .mtl files.
204
+ * @returns A map from material name to definition.
205
+ */
206
+ private _indexMaterialDefinitions(definitions: ObjMaterialDefinition[]): Map<string, ObjMaterialDefinition> {
207
+ const definitionsByName = new Map<string, ObjMaterialDefinition>();
208
+ for (const definition of definitions) {
209
+ definitionsByName.set(definition.name, definition);
210
+ }
211
+ return definitionsByName;
212
+ }
213
+
214
+ /**
215
+ * Finds the definition for a `usemtl` name.
216
+ * @param definitionsByName The definitions by name.
217
+ * @param materialName The material name, or undefined for faces without `usemtl`.
218
+ * @returns The definition, or undefined when there is none.
219
+ */
220
+ private _findMaterialDefinition(
221
+ definitionsByName: Map<string, ObjMaterialDefinition>,
222
+ materialName: string | undefined): ObjMaterialDefinition | undefined {
223
+ if (materialName === undefined) {
224
+ return undefined;
225
+ }
226
+ return definitionsByName.get(materialName);
227
+ }
228
+
229
+ /**
230
+ * Creates the default unlit material for an OBJ material definition.
231
+ * The diffuse colour is the definition's `Kd` with `d` as alpha; white when there is no definition.
232
+ * @param definition The material definition, or undefined.
233
+ * @param camera The scene's current camera, or undefined; the scene assigns it on update.
234
+ * @returns The unlit material.
235
+ */
236
+ private _createUnlitMaterial(definition: ObjMaterialDefinition | undefined, camera: ICamera | undefined): IMaterial {
237
+ const material = this._framework.materialFactory.createUnlitMaterial({
238
+ camera: camera,
239
+ });
240
+
241
+ const diffuse = definition?.diffuseColor ?? [1, 1, 1];
242
+ const opacity = definition?.opacity ?? 1;
243
+ material.diffuseColor = new Color(diffuse[0], diffuse[1], diffuse[2], opacity);
244
+ return material;
245
+ }
246
+
247
+ /**
248
+ * Creates a Blinn-Phong material for an OBJ material definition.
249
+ * `Kd` (with `d` as alpha) becomes the diffuse colour, white when missing.
250
+ * `Ka` becomes the ambient colour; when missing the diffuse colour is used, so ambient light tints by the surface colour.
251
+ * `Ks` and `Ns` become specular colour and shininess; when missing the material defaults stay (0.5 grey, 32).
252
+ * @param definition The material definition, or undefined.
253
+ * @param camera The scene's camera; its projection view and position buffers are bound.
254
+ * @param lightsBuffer The optional lights buffer; the shader is compiled for its light counts.
255
+ * @returns The Blinn-Phong material.
256
+ */
257
+ private _createBlinnPhongMaterial(
258
+ definition: ObjMaterialDefinition | undefined,
259
+ camera: ICamera,
260
+ lightsBuffer: LightsBuffer | undefined): IMaterial {
261
+
262
+ const material = this._framework.materialFactory.createForwardBlinnPhongMaterial({
263
+ projectionViewBuffer: camera.projectionViewBuffer,
264
+ cameraPositionBuffer: camera.positionBuffer,
265
+ lightsBuffer: lightsBuffer,
266
+ });
267
+ // Matches the scene camera, so Scene.update() does not rebind.
268
+ material.camera = camera;
269
+
270
+ const diffuse = definition?.diffuseColor ?? [1, 1, 1];
271
+ const ambient = definition?.ambientColor ?? diffuse;
272
+ material.diffuseColor = new Color(diffuse[0], diffuse[1], diffuse[2], definition?.opacity ?? 1);
273
+ material.ambientColor = new Color(ambient[0], ambient[1], ambient[2]);
274
+ if (definition?.specularColor) {
275
+ const specular = definition.specularColor;
276
+ material.specularColor = new Color(specular[0], specular[1], specular[2]);
277
+ }
278
+ if (definition?.specularExponent !== undefined) {
279
+ material.shininess = definition.specularExponent;
280
+ }
281
+ return material;
282
+ }
283
+ }