@multiplekex/shallot 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/component.ts +1 -1
- package/src/core/index.ts +1 -13
- package/src/core/math.ts +186 -0
- package/src/core/state.ts +1 -1
- package/src/core/xml.ts +56 -41
- package/src/extras/orbit/index.ts +1 -1
- package/src/extras/text/index.ts +10 -65
- package/src/extras/{water.ts → water/index.ts} +59 -4
- package/src/standard/raster/batch.ts +149 -0
- package/src/standard/raster/forward.ts +832 -0
- package/src/standard/raster/index.ts +146 -472
- package/src/standard/raster/shadow.ts +408 -0
- package/src/standard/raytracing/bvh/blas.ts +335 -87
- package/src/standard/raytracing/bvh/radix.ts +225 -228
- package/src/standard/raytracing/bvh/refit.ts +711 -0
- package/src/standard/raytracing/bvh/structs.ts +0 -55
- package/src/standard/raytracing/bvh/tlas.ts +153 -141
- package/src/standard/raytracing/bvh/traverse.ts +72 -64
- package/src/standard/raytracing/index.ts +233 -204
- package/src/standard/raytracing/instance.ts +30 -18
- package/src/standard/raytracing/ray.ts +1 -1
- package/src/standard/raytracing/shaders.ts +23 -40
- package/src/standard/render/camera.ts +10 -28
- package/src/standard/render/data.ts +1 -1
- package/src/standard/render/index.ts +68 -12
- package/src/standard/render/light.ts +2 -2
- package/src/standard/render/mesh.ts +404 -0
- package/src/standard/render/overlay.ts +5 -2
- package/src/standard/render/postprocess.ts +263 -267
- package/src/standard/render/surface/index.ts +81 -12
- package/src/standard/render/surface/shaders.ts +265 -11
- package/src/standard/render/surface/structs.ts +10 -0
- package/src/standard/tween/tween.ts +44 -115
- package/src/standard/render/mesh/box.ts +0 -20
- package/src/standard/render/mesh/index.ts +0 -315
- package/src/standard/render/mesh/plane.ts +0 -11
- package/src/standard/render/mesh/sphere.ts +0 -40
- package/src/standard/render/mesh/unified.ts +0 -96
- package/src/standard/render/surface/compile.ts +0 -65
- package/src/standard/render/surface/noise.ts +0 -58
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SurfaceData } from "../render/surface";
|
|
2
2
|
import {
|
|
3
3
|
compileVertexBody,
|
|
4
|
-
|
|
4
|
+
SPECULAR_WGSL,
|
|
5
5
|
SKY_DIR_WGSL,
|
|
6
6
|
HAZE_WGSL,
|
|
7
7
|
SKY_WGSL,
|
|
@@ -22,26 +22,6 @@ import {
|
|
|
22
22
|
DATA_STRUCT_WGSL,
|
|
23
23
|
} from "../render/surface/structs";
|
|
24
24
|
|
|
25
|
-
const SPECULAR_WGSL = /* wgsl */ `
|
|
26
|
-
const DIELECTRIC_F0: f32 = 0.04;
|
|
27
|
-
|
|
28
|
-
fn blinnPhongSpecular(N: vec3<f32>, L: vec3<f32>, V: vec3<f32>, roughness: f32) -> f32 {
|
|
29
|
-
let H = normalize(L + V);
|
|
30
|
-
let NdotH = max(dot(N, H), 0.0);
|
|
31
|
-
let shininess = pow(2.0, (1.0 - roughness) * 10.0);
|
|
32
|
-
let intensity = (1.0 - roughness) * (1.0 - roughness);
|
|
33
|
-
return pow(NdotH, shininess) * intensity;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
fn schlickFresnel(cosTheta: f32, F0: vec3<f32>) -> vec3<f32> {
|
|
37
|
-
return F0 + (vec3(1.0) - F0) * pow(1.0 - cosTheta, 5.0);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
fn computeF0Vec(baseColor: vec3<f32>, metallic: f32) -> vec3<f32> {
|
|
41
|
-
return mix(vec3(DIELECTRIC_F0), baseColor, metallic);
|
|
42
|
-
}
|
|
43
|
-
`;
|
|
44
|
-
|
|
45
25
|
const REFRACTION_WGSL = /* wgsl */ `
|
|
46
26
|
fn refractRay(I: vec3<f32>, N: vec3<f32>, eta: f32) -> vec4<f32> {
|
|
47
27
|
let cosI = -dot(I, N);
|
|
@@ -140,13 +120,8 @@ fn sampleSoftShadow(origin: vec3<f32>, sunDir: vec3<f32>, softness: f32, samples
|
|
|
140
120
|
}
|
|
141
121
|
`;
|
|
142
122
|
|
|
143
|
-
function compileApplyLighting(
|
|
144
|
-
if (lit === false) {
|
|
145
|
-
return "return surface.baseColor;";
|
|
146
|
-
}
|
|
147
|
-
|
|
123
|
+
function compileApplyLighting(shadows?: boolean, reflections?: boolean): string {
|
|
148
124
|
if (shadows && reflections) {
|
|
149
|
-
// shadowFactor is now passed as parameter, computed once in main kernel
|
|
150
125
|
return `
|
|
151
126
|
let V = -rayDir;
|
|
152
127
|
let L = -scene.sunDirection.xyz;
|
|
@@ -186,7 +161,7 @@ function compileApplyLighting(lit?: boolean, shadows?: boolean, reflections?: bo
|
|
|
186
161
|
|
|
187
162
|
let F0 = computeF0Vec(surface.baseColor, surface.metallic);
|
|
188
163
|
let F = schlickFresnel(NdotV, F0);
|
|
189
|
-
let diffuseWeight =
|
|
164
|
+
let diffuseWeight = 1.0 - surface.metallic;
|
|
190
165
|
let ambient = scene.ambientColor.rgb * scene.ambientColor.a;
|
|
191
166
|
let sunDiffuse = scene.sunColor.rgb * NdotL * shadowFactor;
|
|
192
167
|
let diffuseColor = surface.baseColor * (ambient + sunDiffuse) * diffuseWeight + surface.emission;
|
|
@@ -226,13 +201,25 @@ function compileApplyLighting(lit?: boolean, shadows?: boolean, reflections?: bo
|
|
|
226
201
|
return finalColor;`;
|
|
227
202
|
}
|
|
228
203
|
|
|
229
|
-
return
|
|
230
|
-
|
|
204
|
+
return `
|
|
205
|
+
let V = -rayDir;
|
|
206
|
+
let L = -scene.sunDirection.xyz;
|
|
207
|
+
let NdotL = max(dot(surface.normal, L), 0.0);
|
|
208
|
+
let NdotV = max(dot(surface.normal, V), 0.0);
|
|
209
|
+
let F0 = computeF0Vec(surface.baseColor, surface.metallic);
|
|
210
|
+
let F = schlickFresnel(NdotV, F0);
|
|
211
|
+
let diffuseWeight = 1.0 - surface.metallic;
|
|
212
|
+
let ambient = scene.ambientColor.rgb * scene.ambientColor.a;
|
|
213
|
+
let sunDiffuse = scene.sunColor.rgb * NdotL;
|
|
214
|
+
let diffuseColor = surface.baseColor * (ambient + sunDiffuse) * diffuseWeight + surface.emission;
|
|
215
|
+
let specTerm = blinnPhongSpecular(surface.normal, L, V, surface.roughness);
|
|
216
|
+
let specular = scene.sunColor.rgb * specTerm * F * NdotL;
|
|
217
|
+
return diffuseColor + specular;`;
|
|
231
218
|
}
|
|
232
219
|
|
|
233
220
|
const EPSILON = 1e-7;
|
|
234
221
|
|
|
235
|
-
|
|
222
|
+
const RT_STRUCTS = /* wgsl */ `
|
|
236
223
|
${RAY_STRUCT_WGSL}
|
|
237
224
|
${HIT_RESULT_STRUCT_WGSL}
|
|
238
225
|
${SURFACE_DATA_STRUCT_WGSL}
|
|
@@ -241,7 +228,7 @@ ${SKY_STRUCT_WGSL}
|
|
|
241
228
|
${DATA_STRUCT_WGSL}
|
|
242
229
|
`;
|
|
243
230
|
|
|
244
|
-
|
|
231
|
+
const RT_BINDINGS = /* wgsl */ `
|
|
245
232
|
@group(0) @binding(0) var<uniform> scene: Scene;
|
|
246
233
|
@group(0) @binding(1) var<storage, read> data: array<Data>;
|
|
247
234
|
@group(0) @binding(2) var output_scene: texture_storage_2d<rgba8unorm, write>;
|
|
@@ -250,7 +237,7 @@ export const RT_BINDINGS = /* wgsl */ `
|
|
|
250
237
|
@group(0) @binding(5) var<uniform> sky: Sky;
|
|
251
238
|
`;
|
|
252
239
|
|
|
253
|
-
|
|
240
|
+
const RT_UTILS = /* wgsl */ `
|
|
254
241
|
fn getData(eid: u32) -> Data {
|
|
255
242
|
return data[eid];
|
|
256
243
|
}
|
|
@@ -272,7 +259,7 @@ fn getInstanceCount() -> u32 {
|
|
|
272
259
|
}
|
|
273
260
|
`;
|
|
274
261
|
|
|
275
|
-
|
|
262
|
+
const RT_RAY_GEN = /* wgsl */ `
|
|
276
263
|
${SKY_DIR_WGSL}
|
|
277
264
|
|
|
278
265
|
struct PrimaryRay {
|
|
@@ -323,7 +310,7 @@ fn generateRay(screenX: f32, screenY: f32) -> PrimaryRay {
|
|
|
323
310
|
}
|
|
324
311
|
`;
|
|
325
312
|
|
|
326
|
-
|
|
313
|
+
const RT_INTERSECTION = /* wgsl */ `
|
|
327
314
|
const EPSILON: f32 = ${EPSILON};
|
|
328
315
|
`;
|
|
329
316
|
|
|
@@ -334,7 +321,7 @@ export function compileRTSurface(data: SurfaceData): string {
|
|
|
334
321
|
function compileSurfaceVariant(id: number, data: SurfaceData): string {
|
|
335
322
|
const vertexBody = compileVertexBody(data.vertex);
|
|
336
323
|
const fragmentBody = data.fragment ?? "";
|
|
337
|
-
const lightingCode = compileApplyLighting(
|
|
324
|
+
const lightingCode = compileApplyLighting(true, false);
|
|
338
325
|
|
|
339
326
|
return `
|
|
340
327
|
fn userVertexTransform_${id}(worldPos: vec3<f32>, normal: vec3<f32>, eid: u32) -> vec3<f32> {
|
|
@@ -809,7 +796,3 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
|
809
796
|
}
|
|
810
797
|
`;
|
|
811
798
|
}
|
|
812
|
-
|
|
813
|
-
export function compileForwardShader(surface: SurfaceData): string {
|
|
814
|
-
return compileUberShader([surface]);
|
|
815
|
-
}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { setTraits } from "../../core/component";
|
|
2
2
|
import { perspective, orthographic, multiply, invert, extractFrustumPlanes } from "../../core/math";
|
|
3
3
|
import { WorldTransform } from "../transforms";
|
|
4
|
-
|
|
5
|
-
export const RenderMode = {
|
|
6
|
-
Raster: 0,
|
|
7
|
-
Raytracing: 1,
|
|
8
|
-
} as const;
|
|
4
|
+
import { SCENE_UNIFORM_SIZE, SKY_UNIFORM_SIZE } from "./scene";
|
|
9
5
|
|
|
10
6
|
export const CameraMode = {
|
|
11
7
|
Perspective: 0,
|
|
@@ -18,7 +14,6 @@ export const Camera = {
|
|
|
18
14
|
far: [] as number[],
|
|
19
15
|
active: [] as number[],
|
|
20
16
|
clearColor: [] as number[],
|
|
21
|
-
renderMode: [] as number[],
|
|
22
17
|
mode: [] as number[],
|
|
23
18
|
size: [] as number[],
|
|
24
19
|
};
|
|
@@ -30,7 +25,6 @@ setTraits(Camera, {
|
|
|
30
25
|
far: 1000,
|
|
31
26
|
active: 1,
|
|
32
27
|
clearColor: 0x1a1a1a,
|
|
33
|
-
renderMode: RenderMode.Raster,
|
|
34
28
|
mode: CameraMode.Perspective,
|
|
35
29
|
size: 5,
|
|
36
30
|
}),
|
|
@@ -46,8 +40,6 @@ setTraits(Tonemap, {
|
|
|
46
40
|
|
|
47
41
|
export const FXAA = {};
|
|
48
42
|
|
|
49
|
-
export const Raytracing = {};
|
|
50
|
-
|
|
51
43
|
export const Vignette = {
|
|
52
44
|
strength: [] as number[],
|
|
53
45
|
inner: [] as number[],
|
|
@@ -80,17 +72,7 @@ setTraits(Quantize, {
|
|
|
80
72
|
defaults: () => ({ bands: 8 }),
|
|
81
73
|
});
|
|
82
74
|
|
|
83
|
-
export const Shadows = {
|
|
84
|
-
softness: [] as number[],
|
|
85
|
-
samples: [] as number[],
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
setTraits(Shadows, {
|
|
89
|
-
defaults: () => ({
|
|
90
|
-
softness: 0.5,
|
|
91
|
-
samples: 1,
|
|
92
|
-
}),
|
|
93
|
-
});
|
|
75
|
+
export const Shadows = {};
|
|
94
76
|
|
|
95
77
|
export const Reflections = {
|
|
96
78
|
depth: [] as number[],
|
|
@@ -199,7 +181,7 @@ setTraits(Viewport, {
|
|
|
199
181
|
defaults: () => ({ width: 0, height: 0 }),
|
|
200
182
|
});
|
|
201
183
|
|
|
202
|
-
|
|
184
|
+
interface SkyParams {
|
|
203
185
|
zenith: number;
|
|
204
186
|
horizon: number;
|
|
205
187
|
}
|
|
@@ -212,31 +194,31 @@ export function unpackColor(packed: number): { r: number; g: number; b: number }
|
|
|
212
194
|
};
|
|
213
195
|
}
|
|
214
196
|
|
|
215
|
-
|
|
197
|
+
interface HazeParams {
|
|
216
198
|
density: number;
|
|
217
199
|
color: number;
|
|
218
200
|
}
|
|
219
201
|
|
|
220
|
-
|
|
202
|
+
interface MoonParams {
|
|
221
203
|
phase: number;
|
|
222
204
|
glow: number;
|
|
223
205
|
azimuth: number;
|
|
224
206
|
elevation: number;
|
|
225
207
|
}
|
|
226
208
|
|
|
227
|
-
|
|
209
|
+
interface StarsParams {
|
|
228
210
|
intensity: number;
|
|
229
211
|
amount: number;
|
|
230
212
|
}
|
|
231
213
|
|
|
232
|
-
|
|
214
|
+
interface CloudsParams {
|
|
233
215
|
coverage: number;
|
|
234
216
|
density: number;
|
|
235
217
|
height: number;
|
|
236
218
|
color: number;
|
|
237
219
|
}
|
|
238
220
|
|
|
239
|
-
|
|
221
|
+
interface SunParams {
|
|
240
222
|
size: number;
|
|
241
223
|
glow: number;
|
|
242
224
|
color: number;
|
|
@@ -258,7 +240,7 @@ export function hasSkyComponent(
|
|
|
258
240
|
return state.hasComponent(eid, Sky);
|
|
259
241
|
}
|
|
260
242
|
|
|
261
|
-
const sceneBuffer = new ArrayBuffer(
|
|
243
|
+
const sceneBuffer = new ArrayBuffer(SCENE_UNIFORM_SIZE);
|
|
262
244
|
const scene = new Float32Array(sceneBuffer);
|
|
263
245
|
const sceneU32 = new Uint32Array(sceneBuffer);
|
|
264
246
|
|
|
@@ -314,7 +296,7 @@ export function uploadCamera(
|
|
|
314
296
|
device.queue.writeBuffer(buffer, 176, scene, 44, 44);
|
|
315
297
|
}
|
|
316
298
|
|
|
317
|
-
const skyArrayBuffer = new ArrayBuffer(
|
|
299
|
+
const skyArrayBuffer = new ArrayBuffer(SKY_UNIFORM_SIZE);
|
|
318
300
|
const skyF32 = new Float32Array(skyArrayBuffer);
|
|
319
301
|
|
|
320
302
|
export function uploadSky(
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
Camera,
|
|
8
8
|
Tonemap,
|
|
9
9
|
FXAA,
|
|
10
|
-
Raytracing,
|
|
11
10
|
Vignette,
|
|
12
11
|
Bloom,
|
|
13
12
|
Quantize,
|
|
@@ -25,6 +24,33 @@ import {
|
|
|
25
24
|
uploadSky,
|
|
26
25
|
} from "./camera";
|
|
27
26
|
import { AmbientLight, DirectionalLight, packLightUniforms } from "./light";
|
|
27
|
+
|
|
28
|
+
export interface ShadowSettingsProvider {
|
|
29
|
+
softness: number[];
|
|
30
|
+
samples: number[];
|
|
31
|
+
isActive: (state: State, eid: number) => boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const shadowSettingsProviders: ShadowSettingsProvider[] = [];
|
|
35
|
+
|
|
36
|
+
export function registerShadowSettings(settings: ShadowSettingsProvider): void {
|
|
37
|
+
shadowSettingsProviders.push(settings);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getShadowSettings(
|
|
41
|
+
state: State,
|
|
42
|
+
eid: number
|
|
43
|
+
): { softness: number; samples: number } {
|
|
44
|
+
for (const provider of shadowSettingsProviders) {
|
|
45
|
+
if (provider.isActive(state, eid)) {
|
|
46
|
+
return {
|
|
47
|
+
softness: provider.softness[eid] ?? 0,
|
|
48
|
+
samples: Math.max(1, provider.samples[eid] ?? 16),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { softness: 0, samples: 16 };
|
|
53
|
+
}
|
|
28
54
|
import {
|
|
29
55
|
Mesh,
|
|
30
56
|
MeshShapes,
|
|
@@ -34,6 +60,7 @@ import {
|
|
|
34
60
|
MeshEmission,
|
|
35
61
|
MeshVolumes,
|
|
36
62
|
createShapeAtlas,
|
|
63
|
+
getMeshVersion,
|
|
37
64
|
} from "./mesh";
|
|
38
65
|
import { Surface, SurfaceIds } from "./surface";
|
|
39
66
|
import { createSceneBuffer, createSkyBuffer, ensureTextures } from "./scene";
|
|
@@ -45,10 +72,8 @@ import { createDataNode } from "./data";
|
|
|
45
72
|
export {
|
|
46
73
|
Camera,
|
|
47
74
|
CameraMode,
|
|
48
|
-
RenderMode,
|
|
49
75
|
Tonemap,
|
|
50
76
|
FXAA,
|
|
51
|
-
Raytracing,
|
|
52
77
|
Vignette,
|
|
53
78
|
Bloom,
|
|
54
79
|
Quantize,
|
|
@@ -67,14 +92,25 @@ export {
|
|
|
67
92
|
uploadSky,
|
|
68
93
|
} from "./camera";
|
|
69
94
|
export { AmbientLight, DirectionalLight } from "./light";
|
|
70
|
-
export {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
95
|
+
export {
|
|
96
|
+
Mesh,
|
|
97
|
+
MeshShape,
|
|
98
|
+
Volume,
|
|
99
|
+
mesh,
|
|
100
|
+
getMesh,
|
|
101
|
+
getMeshByName,
|
|
102
|
+
getMeshVersion,
|
|
103
|
+
meshCount,
|
|
104
|
+
clearMeshes,
|
|
105
|
+
computeShapeAABB,
|
|
106
|
+
createBox,
|
|
107
|
+
createSphere,
|
|
108
|
+
createPlane,
|
|
109
|
+
} from "./mesh";
|
|
110
|
+
export type { MeshData, AABB } from "./mesh";
|
|
75
111
|
export { Surface, SurfaceType } from "./surface";
|
|
76
112
|
|
|
77
|
-
export { surface, compose } from "./surface";
|
|
113
|
+
export { surface, getSurfaceByName, compose } from "./surface";
|
|
78
114
|
export type { SurfaceData } from "./surface";
|
|
79
115
|
|
|
80
116
|
export { Pass, registerDraw, unregisterDraw, getDrawsByPass, Draws } from "./pass";
|
|
@@ -99,6 +135,7 @@ export interface Render {
|
|
|
99
135
|
width: number;
|
|
100
136
|
height: number;
|
|
101
137
|
entityCount: number;
|
|
138
|
+
meshVersion: number;
|
|
102
139
|
scene: GPUBuffer;
|
|
103
140
|
sky: GPUBuffer;
|
|
104
141
|
matrices: GPUBuffer;
|
|
@@ -168,14 +205,33 @@ const RenderSystem: System = {
|
|
|
168
205
|
resources.textureViews
|
|
169
206
|
);
|
|
170
207
|
|
|
208
|
+
const currentMeshVersion = getMeshVersion();
|
|
209
|
+
if (currentMeshVersion !== render.meshVersion) {
|
|
210
|
+
render.meshVertices.destroy();
|
|
211
|
+
render.meshIndices.destroy();
|
|
212
|
+
render.meshMeta.destroy();
|
|
213
|
+
const shapeAtlas = createShapeAtlas(device);
|
|
214
|
+
render.meshVertices = shapeAtlas.vertices;
|
|
215
|
+
render.meshIndices = shapeAtlas.indices;
|
|
216
|
+
render.meshMeta = shapeAtlas.meta;
|
|
217
|
+
render.meshVersion = currentMeshVersion;
|
|
218
|
+
}
|
|
219
|
+
|
|
171
220
|
render.entityCount = state.maxEid + 1;
|
|
172
221
|
const uploadCount = render.entityCount;
|
|
173
222
|
|
|
174
223
|
for (const eid of state.query([Camera])) {
|
|
175
224
|
if (Camera.active[eid]) {
|
|
176
225
|
const hasShadows = state.hasComponent(eid, Shadows);
|
|
177
|
-
|
|
178
|
-
|
|
226
|
+
|
|
227
|
+
let shadowSoftness = 0;
|
|
228
|
+
let shadowSamples = 0;
|
|
229
|
+
|
|
230
|
+
if (hasShadows) {
|
|
231
|
+
const shadowSettings = getShadowSettings(state, eid);
|
|
232
|
+
shadowSoftness = shadowSettings.softness;
|
|
233
|
+
shadowSamples = shadowSettings.samples;
|
|
234
|
+
}
|
|
179
235
|
|
|
180
236
|
const hasReflections = state.hasComponent(eid, Reflections);
|
|
181
237
|
const reflectionDepth = hasReflections
|
|
@@ -368,7 +424,6 @@ export const RenderPlugin: Plugin = {
|
|
|
368
424
|
DirectionalLight,
|
|
369
425
|
Tonemap,
|
|
370
426
|
FXAA,
|
|
371
|
-
Raytracing,
|
|
372
427
|
Vignette,
|
|
373
428
|
Bloom,
|
|
374
429
|
Quantize,
|
|
@@ -412,6 +467,7 @@ export const RenderPlugin: Plugin = {
|
|
|
412
467
|
surfaces: createPropertyBuffer(MAX_ENTITIES * 4, "surfaces"),
|
|
413
468
|
data: createPropertyBuffer(MAX_ENTITIES * 64, "data"),
|
|
414
469
|
entityCount: 1,
|
|
470
|
+
meshVersion: getMeshVersion(),
|
|
415
471
|
postProcess: {
|
|
416
472
|
tonemap: false,
|
|
417
473
|
exposure: 1.0,
|
|
@@ -36,12 +36,12 @@ export function normalizeDirection(x: number, y: number, z: number): [number, nu
|
|
|
36
36
|
return [x / len, y / len, z / len];
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
interface AmbientLightData {
|
|
40
40
|
color: number;
|
|
41
41
|
intensity: number;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
interface DirectionalLightData {
|
|
45
45
|
color: number;
|
|
46
46
|
intensity: number;
|
|
47
47
|
directionX: number;
|