genshin-engine 3.7.0 → 3.9.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/dist/index.d.ts +179 -4
- package/dist/index.js +372 -48
- package/package.json +7 -7
package/dist/index.d.ts
CHANGED
|
@@ -1,27 +1,60 @@
|
|
|
1
|
-
import { BufferAttribute, BufferGeometry, Camera, Color, ColorRepresentation, Data3DTexture, DataTexture, DirectionalLight, Frustum, HemisphereLight, InstancedBufferGeometry, OrthographicCamera, Scene, Vector2, Vector3, Vector3Like } from "three";
|
|
1
|
+
import { BufferAttribute, BufferGeometry, Camera, CanvasTexture, Color, ColorRepresentation, Data3DTexture, DataTexture, DirectionalLight, Frustum, HemisphereLight, InstancedBufferGeometry, Matrix4, OrthographicCamera, Scene, Sprite, Texture, ToneMapping, Vector2, Vector3, Vector3Like } from "three";
|
|
2
|
+
import { MeshBasicNodeMaterial, MeshPhysicalNodeMaterial, MeshToonNodeMaterial, MeshToonNodeMaterialParameters, Node, RenderPipeline, RenderTarget, Renderer, TextureNode, UniformNode, WebGPURenderer } from "three/webgpu";
|
|
2
3
|
import { CSMShadowNode } from "three/examples/jsm/csm/CSMShadowNode.js";
|
|
3
|
-
import { MeshBasicNodeMaterial, MeshToonNodeMaterial, MeshToonNodeMaterialParameters, Node, RenderPipeline, RenderTarget, Renderer, TextureNode, UniformNode, WebGPURenderer } from "three/webgpu";
|
|
4
4
|
import BloomNode from "three/examples/jsm/tsl/display/BloomNode.js";
|
|
5
5
|
import GodraysNode from "three/examples/jsm/tsl/display/GodraysNode.js";
|
|
6
|
+
//#region src/atmosphere/CloudBandOptions.d.ts
|
|
7
|
+
export interface CloudBandOptions {
|
|
8
|
+
count: number;
|
|
9
|
+
distanceRange: [number, number];
|
|
10
|
+
heightRange: [number, number];
|
|
11
|
+
seed: number;
|
|
12
|
+
widthRange: [number, number];
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/atmosphere/CloudSprite.d.ts
|
|
16
|
+
export interface CloudSprite {
|
|
17
|
+
lit: [number, number][][];
|
|
18
|
+
outline: [number, number][][];
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
6
21
|
//#region src/atmosphere/SkyKeyframe.d.ts
|
|
7
22
|
export interface SkyKeyframe {
|
|
23
|
+
cloudLitBackColor?: Color;
|
|
8
24
|
cloudLitColor: Color;
|
|
25
|
+
cloudShadeBackColor?: Color;
|
|
9
26
|
cloudShadeColor: Color;
|
|
27
|
+
haloColor?: Color;
|
|
10
28
|
hemisphereGroundColor: Color;
|
|
11
29
|
hemisphereIntensity: number;
|
|
12
30
|
hemisphereSkyColor: Color;
|
|
31
|
+
horizonBackColor?: Color;
|
|
13
32
|
horizonColor: Color;
|
|
14
33
|
lightColor: Color;
|
|
15
34
|
lightIntensity: number;
|
|
16
35
|
minutes: number;
|
|
17
36
|
starIntensity: number;
|
|
37
|
+
sunHaloColor?: Color;
|
|
38
|
+
zenithBackColor?: Color;
|
|
18
39
|
zenithColor: Color;
|
|
19
40
|
}
|
|
20
41
|
//#endregion
|
|
42
|
+
//#region src/atmosphere/SkyShape.d.ts
|
|
43
|
+
export interface SkyShape {
|
|
44
|
+
frontBackBlend: number;
|
|
45
|
+
haloHeight: number;
|
|
46
|
+
horizonBand: number;
|
|
47
|
+
moonSize: number;
|
|
48
|
+
sunHaloSize: number;
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
21
51
|
//#region src/atmosphere/SkyState.d.ts
|
|
22
52
|
export interface SkyState extends Omit<SkyKeyframe, "minutes"> {
|
|
53
|
+
fogColor?: Color;
|
|
54
|
+
fogDensity?: number;
|
|
23
55
|
lightDirection: Vector3;
|
|
24
56
|
moonDirection: Vector3;
|
|
57
|
+
shape?: SkyShape;
|
|
25
58
|
sunDirection: Vector3;
|
|
26
59
|
}
|
|
27
60
|
//#endregion
|
|
@@ -29,13 +62,27 @@ export interface SkyState extends Omit<SkyKeyframe, "minutes"> {
|
|
|
29
62
|
export interface SkyUniforms {
|
|
30
63
|
cloudCoverage: UniformNode<"float", number>;
|
|
31
64
|
cloudDrift: UniformNode<"vec2", Vector2>;
|
|
65
|
+
cloudFrontBackBlend: UniformNode<"float", number>;
|
|
66
|
+
cloudLitBackColor: UniformNode<"color", Color>;
|
|
32
67
|
cloudLitColor: UniformNode<"color", Color>;
|
|
68
|
+
cloudShadeBackColor: UniformNode<"color", Color>;
|
|
33
69
|
cloudShadeColor: UniformNode<"color", Color>;
|
|
70
|
+
cloudSunBrighten: UniformNode<"float", number>;
|
|
71
|
+
frontBackBlend: UniformNode<"float", number>;
|
|
72
|
+
haloColor: UniformNode<"color", Color>;
|
|
73
|
+
haloHeight: UniformNode<"float", number>;
|
|
74
|
+
horizonBackColor: UniformNode<"color", Color>;
|
|
75
|
+
horizonBand: UniformNode<"float", number>;
|
|
34
76
|
horizonColor: UniformNode<"color", Color>;
|
|
35
77
|
lightColor: UniformNode<"color", Color>;
|
|
36
78
|
moonDirection: UniformNode<"vec3", Vector3>;
|
|
79
|
+
moonGlowColor: UniformNode<"color", Color>;
|
|
80
|
+
moonSize: UniformNode<"float", number>;
|
|
37
81
|
starIntensity: UniformNode<"float", number>;
|
|
38
82
|
sunDirection: UniformNode<"vec3", Vector3>;
|
|
83
|
+
sunHaloColor: UniformNode<"color", Color>;
|
|
84
|
+
sunHaloSize: UniformNode<"float", number>;
|
|
85
|
+
zenithBackColor: UniformNode<"color", Color>;
|
|
39
86
|
zenithColor: UniformNode<"color", Color>;
|
|
40
87
|
}
|
|
41
88
|
//#endregion
|
|
@@ -53,6 +100,10 @@ export interface FogUniforms {
|
|
|
53
100
|
color: UniformNode<"color", Color>;
|
|
54
101
|
density: UniformNode<"float", number>;
|
|
55
102
|
heightFalloff: UniformNode<"float", number>;
|
|
103
|
+
scatterColor: UniformNode<"color", Color>;
|
|
104
|
+
scatterDirection: UniformNode<"vec3", Vector3>;
|
|
105
|
+
scatterPower: UniformNode<"float", number>;
|
|
106
|
+
scatterStrength: UniformNode<"float", number>;
|
|
56
107
|
startDistance: UniformNode<"float", number>;
|
|
57
108
|
}
|
|
58
109
|
//#endregion
|
|
@@ -96,6 +147,37 @@ export declare const applySkyState: (skyState: SkyState, { fogUniforms, godraysL
|
|
|
96
147
|
//#region src/atmosphere/computeSunDirection.d.ts
|
|
97
148
|
export declare const computeSunDirection: (minutes: number, tilt: number, sunDirection: Vector3) => Vector3;
|
|
98
149
|
//#endregion
|
|
150
|
+
//#region src/atmosphere/constants.d.ts
|
|
151
|
+
export declare const DEFAULT_SKY_SHAPE: Readonly<SkyShape>;
|
|
152
|
+
export declare const DEFAULT_SKY_GRADIENT: {
|
|
153
|
+
green: number[];
|
|
154
|
+
red: number[];
|
|
155
|
+
};
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/atmosphere/createCloudAtlasTexture.d.ts
|
|
158
|
+
export declare const getCloudAtlasColumns: (spriteCount: number) => number;
|
|
159
|
+
export declare const createCloudAtlasTexture: (sprites: readonly CloudSprite[], cellSize: number) => CanvasTexture<OffscreenCanvas>;
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region src/atmosphere/createCloudBandSprite.d.ts
|
|
162
|
+
export declare const createCloudBandSprite: (atlas: Texture, clouds: readonly {
|
|
163
|
+
position: [number, number, number];
|
|
164
|
+
spriteIndex: number;
|
|
165
|
+
width: number;
|
|
166
|
+
}[], { aspect, spriteCount }: {
|
|
167
|
+
aspect: number;
|
|
168
|
+
spriteCount: number;
|
|
169
|
+
}, skyUniforms: SkyUniforms) => {
|
|
170
|
+
dispose: () => void;
|
|
171
|
+
places: [number, number, number][];
|
|
172
|
+
sprite: Sprite;
|
|
173
|
+
};
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/atmosphere/createSkyGradientTexture.d.ts
|
|
176
|
+
export declare const createSkyGradientTexture: ({ green, red }: {
|
|
177
|
+
green: readonly number[];
|
|
178
|
+
red: readonly number[];
|
|
179
|
+
}) => DataTexture;
|
|
180
|
+
//#endregion
|
|
99
181
|
//#region src/atmosphere/createSkyState.d.ts
|
|
100
182
|
export declare const createSkyState: () => SkyState;
|
|
101
183
|
//#endregion
|
|
@@ -105,6 +187,16 @@ export declare const createSkyUniforms: () => SkyUniforms;
|
|
|
105
187
|
//#region src/atmosphere/createSunLight.d.ts
|
|
106
188
|
export declare const createSunLight: ({ cascadeCount, maxFar, shadowMapSize }: SunLightOptions) => SunLight;
|
|
107
189
|
//#endregion
|
|
190
|
+
//#region src/atmosphere/orderByViewDepth.d.ts
|
|
191
|
+
export declare const orderByViewDepth: (places: readonly (readonly number[])[], { elements }: Matrix4) => number[];
|
|
192
|
+
//#endregion
|
|
193
|
+
//#region src/atmosphere/placeCloudBand.d.ts
|
|
194
|
+
export declare const placeCloudBand: ({ count, distanceRange: [near, far], heightRange: [low, high], seed, widthRange: [narrow, wide] }: CloudBandOptions, spriteCount: number) => {
|
|
195
|
+
position: [number, number, number];
|
|
196
|
+
spriteIndex: number;
|
|
197
|
+
width: number;
|
|
198
|
+
}[];
|
|
199
|
+
//#endregion
|
|
108
200
|
//#region src/atmosphere/sampleSkyState.d.ts
|
|
109
201
|
export declare const sampleSkyState: (skyKeyframes: readonly SkyKeyframe[], minutes: number, tilt: number, skyState: SkyState) => SkyState;
|
|
110
202
|
//#endregion
|
|
@@ -121,6 +213,26 @@ export declare const advanceGameClock: (gameClock: GameClock, deltaSeconds: numb
|
|
|
121
213
|
export declare const MINUTES_PER_DAY = 1440;
|
|
122
214
|
export declare const GAME_MINUTES_PER_SECOND = 1;
|
|
123
215
|
//#endregion
|
|
216
|
+
//#region src/kits/architecture/LatheSection.d.ts
|
|
217
|
+
export interface LatheSection {
|
|
218
|
+
bottomRadius: number;
|
|
219
|
+
height: number;
|
|
220
|
+
topRadius: number;
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/kits/architecture/LatheStackOptions.d.ts
|
|
224
|
+
export interface LatheStackOptions {
|
|
225
|
+
isFaceted: boolean;
|
|
226
|
+
radialSegments: number;
|
|
227
|
+
sections: LatheSection[];
|
|
228
|
+
}
|
|
229
|
+
//#endregion
|
|
230
|
+
//#region src/kits/architecture/createBoxesGeometry.d.ts
|
|
231
|
+
export declare const createBoxesGeometry: (boxes: readonly (readonly number[])[]) => BufferGeometry;
|
|
232
|
+
//#endregion
|
|
233
|
+
//#region src/kits/architecture/createLatheStackGeometry.d.ts
|
|
234
|
+
export declare const createLatheStackGeometry: ({ isFaceted, radialSegments, sections }: LatheStackOptions) => BufferGeometry;
|
|
235
|
+
//#endregion
|
|
124
236
|
//#region src/kits/statue/createStatueGeometry.d.ts
|
|
125
237
|
export declare const createStatueGeometry: () => BufferGeometry;
|
|
126
238
|
//#endregion
|
|
@@ -180,12 +292,25 @@ export interface RampOptions {
|
|
|
180
292
|
terminator: number;
|
|
181
293
|
}
|
|
182
294
|
//#endregion
|
|
295
|
+
//#region src/materials/addSmoothLoop.d.ts
|
|
296
|
+
export declare const addSmoothLoop: (path: Path2D, points: readonly (readonly [number, number])[]) => void;
|
|
297
|
+
//#endregion
|
|
183
298
|
//#region src/materials/computeRampValues.d.ts
|
|
184
299
|
export declare const computeRampValues: ({ resolution, softness, terminator }: RampOptions) => Uint8Array;
|
|
185
300
|
//#endregion
|
|
186
301
|
//#region src/materials/createRampTexture.d.ts
|
|
187
302
|
export declare const createRampTexture: (rampOptions: RampOptions) => DataTexture;
|
|
188
303
|
//#endregion
|
|
304
|
+
//#region src/nodes/StoneMaterialOptions.d.ts
|
|
305
|
+
export interface StoneMaterialOptions {
|
|
306
|
+
albedo: string;
|
|
307
|
+
rimColor: readonly number[];
|
|
308
|
+
rimPower: number;
|
|
309
|
+
rimStrength: number;
|
|
310
|
+
smoothness: number;
|
|
311
|
+
specularColor: readonly number[];
|
|
312
|
+
}
|
|
313
|
+
//#endregion
|
|
189
314
|
//#region src/nodes/ToonMaterialOptions.d.ts
|
|
190
315
|
export interface ToonMaterialOptions {
|
|
191
316
|
color?: ColorRepresentation;
|
|
@@ -239,8 +364,14 @@ export declare const createLightUniforms: () => LightUniforms;
|
|
|
239
364
|
//#region src/nodes/createRimNode.d.ts
|
|
240
365
|
export declare const createRimNode: ({ rimColor, rimStrength, sunDirection }: LightUniforms) => Node<"vec3">;
|
|
241
366
|
//#endregion
|
|
367
|
+
//#region src/nodes/createSkyColorNode.d.ts
|
|
368
|
+
export declare const createSkyColorNode: ({ frontBackBlend, haloColor, haloHeight, horizonBackColor, horizonBand, horizonColor, sunDirection, sunHaloColor, sunHaloSize, zenithBackColor, zenithColor }: SkyUniforms, gradient: Texture, direction: Node<"vec3">) => Node<"vec3">;
|
|
369
|
+
//#endregion
|
|
242
370
|
//#region src/nodes/createSkyNode.d.ts
|
|
243
|
-
export declare const createSkyNode: (
|
|
371
|
+
export declare const createSkyNode: (uniforms: SkyUniforms, gradient: Texture) => Node<"vec3">;
|
|
372
|
+
//#endregion
|
|
373
|
+
//#region src/nodes/createStoneMaterial.d.ts
|
|
374
|
+
export declare const createStoneMaterial: ({ albedo, rimColor, rimPower, rimStrength, smoothness, specularColor }: StoneMaterialOptions, glowNode?: Node<"vec3">) => MeshPhysicalNodeMaterial;
|
|
244
375
|
//#endregion
|
|
245
376
|
//#region src/nodes/createToonMaterial.d.ts
|
|
246
377
|
export declare const createToonMaterial: ({ color, isOutlined, isVertexColors, lightUniforms, rampTexture }: ToonMaterialOptions) => ToonNodeMaterial;
|
|
@@ -312,7 +443,7 @@ export declare const createGodraysLight: (shadowMapSize: number, halfExtent: num
|
|
|
312
443
|
export declare const createGradeLutTexture: (gradeOptions: GradeOptions) => Data3DTexture;
|
|
313
444
|
//#endregion
|
|
314
445
|
//#region src/post/createHeightFogNode.d.ts
|
|
315
|
-
export declare const createHeightFogNode: (colorNode: Node<"vec4">, depthNode: TextureNode, camera: Camera, { baseHeight, color, density, heightFalloff, startDistance }: FogUniforms) => Node<"vec4">;
|
|
446
|
+
export declare const createHeightFogNode: (colorNode: Node<"vec4">, depthNode: TextureNode, camera: Camera, { baseHeight, color, density, heightFalloff, scatterColor, scatterDirection, scatterPower, scatterStrength, startDistance }: FogUniforms) => Node<"vec4">;
|
|
316
447
|
//#endregion
|
|
317
448
|
//#region src/post/createPostPipeline.d.ts
|
|
318
449
|
export declare const createPostPipeline: ({ camera, fogUniforms, godraysLight, gradeLutTexture, postUniforms: { godraysColor, gradeIntensity, outlineColor, outlineFadeDistance, outlineThickness }, qualityTierSettings: { antialiasingMode, godraysStepCount, isBloomEnabled }, renderer, scene }: PostPipelineOptions) => PostPipeline;
|
|
@@ -320,6 +451,12 @@ export declare const createPostPipeline: ({ camera, fogUniforms, godraysLight, g
|
|
|
320
451
|
//#region src/post/createPostUniforms.d.ts
|
|
321
452
|
export declare const createPostUniforms: () => PostUniforms;
|
|
322
453
|
//#endregion
|
|
454
|
+
//#region src/post/toSceneColor.d.ts
|
|
455
|
+
export declare const toSceneColor: (displayColor: Color) => Color;
|
|
456
|
+
//#endregion
|
|
457
|
+
//#region src/post/toneMapNeutral.d.ts
|
|
458
|
+
export declare const toneMapNeutral: ([red, green, blue]: [number, number, number]) => [number, number, number];
|
|
459
|
+
//#endregion
|
|
323
460
|
//#region src/random/createSeededRandom.d.ts
|
|
324
461
|
export declare const createSeededRandom: (seed: number) => (() => number);
|
|
325
462
|
//#endregion
|
|
@@ -333,6 +470,44 @@ export declare enum QualityTier {
|
|
|
333
470
|
//#region src/renderer/QualityTierSettingsMap.d.ts
|
|
334
471
|
export declare const QualityTierSettingsMap: Readonly<Record<QualityTier, QualityTierSettings>>;
|
|
335
472
|
//#endregion
|
|
473
|
+
//#region src/renderer/constants.d.ts
|
|
474
|
+
export declare const GENSHIN_TONE_MAPPING: ToneMapping;
|
|
475
|
+
//#endregion
|
|
476
|
+
//#region src/renderer/getScreenDirection.d.ts
|
|
477
|
+
export declare const getScreenDirection: ({ aspect, fov, pitch, yaw }: {
|
|
478
|
+
aspect: number;
|
|
479
|
+
fov: number;
|
|
480
|
+
pitch: number;
|
|
481
|
+
yaw: number;
|
|
482
|
+
}, [x, y]: [number, number]) => Vector3;
|
|
483
|
+
//#endregion
|
|
484
|
+
//#region src/scene/SceneMaterial.d.ts
|
|
485
|
+
export interface SceneMaterial {
|
|
486
|
+
colors: Record<string, [number, number, number, number]>;
|
|
487
|
+
floats: Record<string, number>;
|
|
488
|
+
name: string;
|
|
489
|
+
textures: Record<string, {
|
|
490
|
+
name: string;
|
|
491
|
+
offset: [number, number];
|
|
492
|
+
scale: [number, number];
|
|
493
|
+
}>;
|
|
494
|
+
}
|
|
495
|
+
//#endregion
|
|
496
|
+
//#region src/scene/ScenePlacement.d.ts
|
|
497
|
+
export interface ScenePlacement {
|
|
498
|
+
materials: string[];
|
|
499
|
+
mesh: string;
|
|
500
|
+
position: [number, number, number];
|
|
501
|
+
rotation: [number, number, number, number];
|
|
502
|
+
scale: [number, number, number];
|
|
503
|
+
}
|
|
504
|
+
//#endregion
|
|
505
|
+
//#region src/scene/SceneLayout.d.ts
|
|
506
|
+
export interface SceneLayout {
|
|
507
|
+
materials: Record<string, SceneMaterial>;
|
|
508
|
+
placements: ScenePlacement[];
|
|
509
|
+
}
|
|
510
|
+
//#endregion
|
|
336
511
|
//#region src/terrain/TerrainSelection.d.ts
|
|
337
512
|
export interface TerrainSelection {
|
|
338
513
|
count: number;
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { Box3, BufferAttribute, BufferGeometry, Color, CylinderGeometry, Data3DTexture, DataTexture, DirectionalLight, DoubleSide, HalfFloatType, InstancedBufferGeometry, LatheGeometry, LinearFilter, OrthographicCamera, Quaternion, RedFormat, Vector2, Vector3 } from "three";
|
|
2
|
-
import { Fn, If, attribute, cameraFar, cameraNear, cameraPosition, cameraViewMatrix, cos, exp, exp2, float, getViewPosition, hash, instanceIndex, max, mix, modelViewMatrix, modelWorldMatrix, mrt, mx_cell_noise_float, mx_fractal_noise_float, mx_noise_float, normalView, normalWorldGeometry, output, perspectiveDepthToViewZ, positionGeometry, positionLocal, positionView, positionViewDirection, positionWorld, pow, reflect, renderOutput, screenUV, sin, smoothstep, step, texture, texture3D, time, uniform, uv, varying, vec2, vec3, vec4, velocity, viewportDepthTexture, viewportSharedTexture } from "three/tsl";
|
|
1
|
+
import { Box3, BoxGeometry, BufferAttribute, BufferGeometry, CanvasTexture, ClampToEdgeWrapping, Color, CylinderGeometry, Data3DTexture, DataTexture, DirectionalLight, DoubleSide, HalfFloatType, InstancedBufferAttribute, InstancedBufferGeometry, LatheGeometry, LinearFilter, MathUtils, Matrix4, NeutralToneMapping, NoColorSpace, OrthographicCamera, Quaternion, RGBAFormat, RedFormat, Sprite, UnsignedByteType, Vector2, Vector3 } from "three";
|
|
2
|
+
import { Fn, If, abs, asin, attribute, cameraFar, cameraNear, cameraPosition, cameraViewMatrix, clamp, color, cos, exp, exp2, float, getViewPosition, hash, instanceIndex, instancedBufferAttribute, max, min, mix, modelViewMatrix, modelWorldMatrix, mrt, mx_cell_noise_float, mx_fractal_noise_float, mx_noise_float, normalView, normalWorldGeometry, output, perspectiveDepthToViewZ, positionGeometry, positionLocal, positionView, positionViewDirection, positionWorld, pow, reflect, renderOutput, saturate, screenUV, sin, smoothstep, step, texture, texture3D, time, uniform, uv, varying, vec2, vec3, vec4, velocity, viewportDepthTexture, viewportSharedTexture } from "three/tsl";
|
|
3
|
+
import { MeshBasicNodeMaterial, MeshPhysicalNodeMaterial, MeshToonNodeMaterial, RenderPipeline, RenderTarget, SpriteNodeMaterial, ToonOutlinePassNode, WebGPURenderer } from "three/webgpu";
|
|
3
4
|
import { CSMShadowNode } from "three/examples/jsm/csm/CSMShadowNode.js";
|
|
4
5
|
import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js";
|
|
5
|
-
import { MeshBasicNodeMaterial, MeshToonNodeMaterial, NeutralToneMapping, RenderPipeline, RenderTarget, ToonOutlinePassNode, WebGPURenderer } from "three/webgpu";
|
|
6
6
|
import { voronoi2d } from "three/examples/jsm/tsl/math/voronoiNoise.js";
|
|
7
7
|
import { bilateralBlur } from "three/examples/jsm/tsl/display/BilateralBlurNode.js";
|
|
8
8
|
import { bloom } from "three/examples/jsm/tsl/display/BloomNode.js";
|
|
@@ -11,9 +11,72 @@ import { godrays } from "three/examples/jsm/tsl/display/GodraysNode.js";
|
|
|
11
11
|
import { lut3D } from "three/examples/jsm/tsl/display/Lut3DNode.js";
|
|
12
12
|
import { smaa } from "three/examples/jsm/tsl/display/SMAANode.js";
|
|
13
13
|
import { traa } from "three/examples/jsm/tsl/display/TRAANode.js";
|
|
14
|
+
//#region src/atmosphere/constants.ts
|
|
15
|
+
const DEFAULT_SKY_SHAPE = {
|
|
16
|
+
frontBackBlend: 1,
|
|
17
|
+
haloHeight: 1,
|
|
18
|
+
horizonBand: .45,
|
|
19
|
+
moonSize: 1,
|
|
20
|
+
sunHaloSize: 1
|
|
21
|
+
};
|
|
22
|
+
const DEFAULT_SAMPLE_COUNT = 33;
|
|
23
|
+
const DEFAULT_SKY_GRADIENT = {
|
|
24
|
+
green: Array.from({ length: DEFAULT_SAMPLE_COUNT }, () => 0),
|
|
25
|
+
red: Array.from({ length: DEFAULT_SAMPLE_COUNT }, (_, index) => {
|
|
26
|
+
const share = index / 32;
|
|
27
|
+
return 1 - share * share * (3 - 2 * share);
|
|
28
|
+
})
|
|
29
|
+
};
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/post/toneMapNeutral.ts
|
|
32
|
+
const TOE_END = .08;
|
|
33
|
+
const TOE_OFFSET = .04;
|
|
34
|
+
const COMPRESSION_START = .76;
|
|
35
|
+
const DESATURATION = .15;
|
|
36
|
+
const toneMapNeutral = ([red, green, blue]) => {
|
|
37
|
+
const lowest = Math.min(red, green, blue);
|
|
38
|
+
const offset = lowest < TOE_END ? lowest - 6.25 * lowest * lowest : TOE_OFFSET;
|
|
39
|
+
const offsetColor = [
|
|
40
|
+
red - offset,
|
|
41
|
+
green - offset,
|
|
42
|
+
blue - offset
|
|
43
|
+
];
|
|
44
|
+
const peak = Math.max(...offsetColor);
|
|
45
|
+
if (peak < COMPRESSION_START) return offsetColor;
|
|
46
|
+
const headroom = .24;
|
|
47
|
+
const newPeak = 1 - headroom * headroom / (peak + headroom - COMPRESSION_START);
|
|
48
|
+
const whiteShare = 1 - 1 / (DESATURATION * (peak - newPeak) + 1);
|
|
49
|
+
return offsetColor.map((channel) => channel * newPeak / peak + (newPeak - channel * newPeak / peak) * whiteShare);
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/post/toSceneColor.ts
|
|
53
|
+
const INVERSE_STEP_COUNT = 16;
|
|
54
|
+
const SLOPE_NUDGE = 1e-4;
|
|
55
|
+
const SCENE_CHANNEL_LIMIT = 1.5;
|
|
56
|
+
const toSceneColor = (displayColor) => {
|
|
57
|
+
const target = [
|
|
58
|
+
displayColor.r,
|
|
59
|
+
displayColor.g,
|
|
60
|
+
displayColor.b
|
|
61
|
+
];
|
|
62
|
+
let input = [...target];
|
|
63
|
+
for (let step = 0; step < INVERSE_STEP_COUNT; step++) {
|
|
64
|
+
const current = input;
|
|
65
|
+
const output = toneMapNeutral(current);
|
|
66
|
+
input = current.map((channel, index) => {
|
|
67
|
+
const nudged = [...current];
|
|
68
|
+
nudged[index] = channel + SLOPE_NUDGE;
|
|
69
|
+
const slope = ((toneMapNeutral(nudged)[index] ?? 0) - (output[index] ?? 0)) / SLOPE_NUDGE;
|
|
70
|
+
return Math.min(Math.max(channel + ((target[index] ?? 0) - (output[index] ?? 0)) / slope, 0), SCENE_CHANNEL_LIMIT);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return new Color(...input);
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
14
76
|
//#region src/atmosphere/applySkyState.ts
|
|
15
77
|
const GODRAYS_REDRAW_COSINE = Math.cos(.6 * Math.PI / 180);
|
|
16
78
|
const godraysDirection = new Vector3();
|
|
79
|
+
const BLACK = new Color(0, 0, 0);
|
|
17
80
|
const applySkyState = (skyState, { fogUniforms, godraysLight, hemisphere, light, lightDistance, lightUniforms, postUniforms, skyUniforms }) => {
|
|
18
81
|
const { horizonColor, lightColor, lightDirection } = skyState;
|
|
19
82
|
light.position.copy(light.target.position).addScaledVector(lightDirection, lightDistance);
|
|
@@ -25,16 +88,30 @@ const applySkyState = (skyState, { fogUniforms, godraysLight, hemisphere, light,
|
|
|
25
88
|
lightUniforms.lightColor.value.copy(lightColor);
|
|
26
89
|
lightUniforms.sunDirection.value.copy(lightDirection);
|
|
27
90
|
lightUniforms.rimColor.value.copy(horizonColor);
|
|
28
|
-
fogUniforms.color.value.copy(horizonColor);
|
|
91
|
+
fogUniforms.color.value.copy(toSceneColor(skyState.fogColor ?? horizonColor));
|
|
92
|
+
fogUniforms.scatterColor.value.copy(toSceneColor(lightColor));
|
|
93
|
+
fogUniforms.scatterDirection.value.copy(lightDirection);
|
|
29
94
|
postUniforms.godraysColor.value.copy(lightColor);
|
|
30
|
-
skyUniforms.cloudLitColor.value.copy(skyState.cloudLitColor);
|
|
31
|
-
skyUniforms.cloudShadeColor.value.copy(skyState.cloudShadeColor);
|
|
32
|
-
skyUniforms.
|
|
95
|
+
skyUniforms.cloudLitColor.value.copy(toSceneColor(skyState.cloudLitColor));
|
|
96
|
+
skyUniforms.cloudShadeColor.value.copy(toSceneColor(skyState.cloudShadeColor));
|
|
97
|
+
skyUniforms.cloudLitBackColor.value.copy(toSceneColor(skyState.cloudLitBackColor ?? skyState.cloudLitColor));
|
|
98
|
+
skyUniforms.cloudShadeBackColor.value.copy(toSceneColor(skyState.cloudShadeBackColor ?? skyState.cloudShadeColor));
|
|
99
|
+
skyUniforms.horizonColor.value.copy(toSceneColor(horizonColor));
|
|
100
|
+
skyUniforms.horizonBackColor.value.copy(toSceneColor(skyState.horizonBackColor ?? horizonColor));
|
|
101
|
+
skyUniforms.zenithBackColor.value.copy(toSceneColor(skyState.zenithBackColor ?? skyState.zenithColor));
|
|
102
|
+
skyUniforms.haloColor.value.copy(toSceneColor(skyState.haloColor ?? BLACK));
|
|
103
|
+
skyUniforms.sunHaloColor.value.copy(toSceneColor(skyState.sunHaloColor ?? BLACK));
|
|
33
104
|
skyUniforms.lightColor.value.copy(lightColor);
|
|
34
105
|
skyUniforms.moonDirection.value.copy(skyState.moonDirection);
|
|
35
106
|
skyUniforms.starIntensity.value = skyState.starIntensity;
|
|
36
107
|
skyUniforms.sunDirection.value.copy(skyState.sunDirection);
|
|
37
|
-
skyUniforms.zenithColor.value.copy(skyState.zenithColor);
|
|
108
|
+
skyUniforms.zenithColor.value.copy(toSceneColor(skyState.zenithColor));
|
|
109
|
+
const { frontBackBlend, haloHeight, horizonBand, moonSize, sunHaloSize } = skyState.shape ?? DEFAULT_SKY_SHAPE;
|
|
110
|
+
skyUniforms.frontBackBlend.value = frontBackBlend;
|
|
111
|
+
skyUniforms.haloHeight.value = haloHeight;
|
|
112
|
+
skyUniforms.horizonBand.value = horizonBand;
|
|
113
|
+
skyUniforms.moonSize.value = moonSize;
|
|
114
|
+
skyUniforms.sunHaloSize.value = sunHaloSize;
|
|
38
115
|
godraysDirection.subVectors(godraysLight.position, godraysLight.target.position).normalize();
|
|
39
116
|
if (godraysDirection.dot(lightDirection) >= GODRAYS_REDRAW_COSINE) return;
|
|
40
117
|
godraysLight.position.copy(godraysLight.target.position).addScaledVector(lightDirection, lightDistance);
|
|
@@ -52,6 +129,135 @@ const computeSunDirection = (minutes, tilt, sunDirection) => {
|
|
|
52
129
|
return sunDirection.set(Math.sin(hourAngle), height * Math.cos(tilt), height * Math.sin(tilt));
|
|
53
130
|
};
|
|
54
131
|
//#endregion
|
|
132
|
+
//#region src/materials/addSmoothLoop.ts
|
|
133
|
+
const addSmoothLoop = (path, points) => {
|
|
134
|
+
if (points.length < 3) return;
|
|
135
|
+
const readMidpoint = (index) => {
|
|
136
|
+
const [startX = 0, startY = 0] = points[index % points.length] ?? [];
|
|
137
|
+
const [endX = 0, endY = 0] = points[(index + 1) % points.length] ?? [];
|
|
138
|
+
return [(startX + endX) / 2, (startY + endY) / 2];
|
|
139
|
+
};
|
|
140
|
+
path.moveTo(...readMidpoint(points.length - 1));
|
|
141
|
+
for (const [index, [x, y]] of points.entries()) path.quadraticCurveTo(x, y, ...readMidpoint(index));
|
|
142
|
+
path.closePath();
|
|
143
|
+
};
|
|
144
|
+
//#endregion
|
|
145
|
+
//#region src/atmosphere/createCloudAtlasTexture.ts
|
|
146
|
+
const EDGE_BLUR_SHARE = .012;
|
|
147
|
+
const getCloudAtlasColumns = (spriteCount) => Math.ceil(Math.sqrt(spriteCount));
|
|
148
|
+
const createCloudAtlasTexture = (sprites, cellSize) => {
|
|
149
|
+
const columns = getCloudAtlasColumns(sprites.length);
|
|
150
|
+
const canvas = new OffscreenCanvas(columns * cellSize, columns * cellSize);
|
|
151
|
+
const context = canvas.getContext("2d");
|
|
152
|
+
if (context) {
|
|
153
|
+
context.globalCompositeOperation = "lighter";
|
|
154
|
+
context.filter = `blur(${cellSize * EDGE_BLUR_SHARE}px)`;
|
|
155
|
+
const fill = (loops, column, row, style) => {
|
|
156
|
+
const path = new Path2D();
|
|
157
|
+
const toCanvas = ([x, y]) => [(column + x) * cellSize, (row + 1 - y) * cellSize];
|
|
158
|
+
for (const loop of loops) addSmoothLoop(path, loop.map((point) => toCanvas(point)));
|
|
159
|
+
context.fillStyle = style;
|
|
160
|
+
context.fill(path, "evenodd");
|
|
161
|
+
};
|
|
162
|
+
for (const [index, { lit, outline }] of sprites.entries()) {
|
|
163
|
+
const column = index % columns;
|
|
164
|
+
const row = Math.floor(index / columns);
|
|
165
|
+
fill(outline, column, row, "#f00");
|
|
166
|
+
fill(lit, column, row, "#0f0");
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const texture = new CanvasTexture(canvas);
|
|
170
|
+
texture.colorSpace = NoColorSpace;
|
|
171
|
+
texture.magFilter = LinearFilter;
|
|
172
|
+
texture.minFilter = LinearFilter;
|
|
173
|
+
texture.generateMipmaps = false;
|
|
174
|
+
return texture;
|
|
175
|
+
};
|
|
176
|
+
//#endregion
|
|
177
|
+
//#region src/atmosphere/orderByViewDepth.ts
|
|
178
|
+
const orderByViewDepth = (places, { elements }) => {
|
|
179
|
+
const depths = places.map(([x = 0, y = 0, z = 0]) => elements[2] * x + elements[6] * y + elements[10] * z + elements[14]);
|
|
180
|
+
return depths.map((_, index) => index).toSorted((first, second) => (depths[first] ?? 0) - (depths[second] ?? 0));
|
|
181
|
+
};
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/atmosphere/createCloudBandSprite.ts
|
|
184
|
+
const BELOW_FADE_START = .1;
|
|
185
|
+
const BELOW_FADE_SCALE = 5;
|
|
186
|
+
const COVERAGE_LIGHT_SHARE = .4;
|
|
187
|
+
const EDGE_FADE_START = .15;
|
|
188
|
+
const EDGE_FADE_END = .85;
|
|
189
|
+
const DROPPED_COVERAGE = .01;
|
|
190
|
+
const createCloudBandSprite = (atlas, clouds, { aspect, spriteCount }, skyUniforms) => {
|
|
191
|
+
const { cloudCoverage, cloudFrontBackBlend, cloudLitBackColor, cloudLitColor, cloudShadeBackColor, cloudShadeColor, cloudSunBrighten, sunDirection } = skyUniforms;
|
|
192
|
+
const columns = getCloudAtlasColumns(spriteCount);
|
|
193
|
+
const places = clouds.map(({ position }) => [...position]);
|
|
194
|
+
const cloudScales = clouds.map(({ width }) => [width, width / aspect]);
|
|
195
|
+
const cloudCells = clouds.map(({ spriteIndex }) => [spriteIndex % columns, columns - 1 - Math.floor(spriteIndex / columns)]);
|
|
196
|
+
const positions = new InstancedBufferAttribute(new Float32Array(clouds.length * 3), 3);
|
|
197
|
+
const scales = new InstancedBufferAttribute(new Float32Array(clouds.length * 2), 2);
|
|
198
|
+
const cells = new InstancedBufferAttribute(new Float32Array(clouds.length * 2), 2);
|
|
199
|
+
const mask = texture(atlas, uv().add(instancedBufferAttribute(cells)).div(columns));
|
|
200
|
+
const place = instancedBufferAttribute(positions);
|
|
201
|
+
const direction = place.sub(cameraPosition).normalize();
|
|
202
|
+
const elevation = asin(clamp(direction.y, -1, 1)).mul(2 / Math.PI);
|
|
203
|
+
const sunCosine = direction.dot(sunDirection);
|
|
204
|
+
const toward = pow(max(sunCosine.mul(cloudFrontBackBlend).add(float(1).sub(cloudFrontBackBlend)), 0), 3);
|
|
205
|
+
const lit = mix(cloudLitBackColor, cloudLitColor, toward);
|
|
206
|
+
const shade = mix(cloudShadeBackColor, cloudShadeColor, toward);
|
|
207
|
+
const cloudColor = mix(shade, lit, mask.g).add(lit.mul(cloudCoverage.mul(COVERAGE_LIGHT_SHARE))).mul(float(1).add(cloudSunBrighten.mul(sunCosine.mul(.5).add(.5))));
|
|
208
|
+
const material = new SpriteNodeMaterial({
|
|
209
|
+
depthWrite: false,
|
|
210
|
+
transparent: true
|
|
211
|
+
});
|
|
212
|
+
material.positionNode = place;
|
|
213
|
+
material.scaleNode = instancedBufferAttribute(scales);
|
|
214
|
+
material.colorNode = cloudColor;
|
|
215
|
+
material.opacityNode = smoothstep(EDGE_FADE_START, EDGE_FADE_END, mask.r).mul(smoothstep(0, 1, saturate(elevation.add(BELOW_FADE_START).mul(BELOW_FADE_SCALE))));
|
|
216
|
+
material.alphaTest = DROPPED_COVERAGE;
|
|
217
|
+
const sprite = new Sprite(material);
|
|
218
|
+
sprite.center.set(.5, 0);
|
|
219
|
+
sprite.count = clouds.length;
|
|
220
|
+
sprite.frustumCulled = false;
|
|
221
|
+
const modelViewMatrix = new Matrix4();
|
|
222
|
+
sprite.onBeforeRender = (_renderer, _scene, camera) => {
|
|
223
|
+
modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, sprite.matrixWorld);
|
|
224
|
+
for (const [instance, cloud] of orderByViewDepth(places, modelViewMatrix).entries()) {
|
|
225
|
+
positions.set(places[cloud] ?? [], instance * 3);
|
|
226
|
+
scales.set(cloudScales[cloud] ?? [], instance * 2);
|
|
227
|
+
cells.set(cloudCells[cloud] ?? [], instance * 2);
|
|
228
|
+
}
|
|
229
|
+
positions.needsUpdate = true;
|
|
230
|
+
scales.needsUpdate = true;
|
|
231
|
+
cells.needsUpdate = true;
|
|
232
|
+
};
|
|
233
|
+
return {
|
|
234
|
+
dispose: () => {
|
|
235
|
+
material.dispose();
|
|
236
|
+
},
|
|
237
|
+
places,
|
|
238
|
+
sprite
|
|
239
|
+
};
|
|
240
|
+
};
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/atmosphere/createSkyGradientTexture.ts
|
|
243
|
+
const BYTE = 255;
|
|
244
|
+
const createSkyGradientTexture = ({ green, red }) => {
|
|
245
|
+
const width = Math.max(red.length, green.length, 1);
|
|
246
|
+
const data = new Uint8Array(width * 4);
|
|
247
|
+
for (let index = 0; index < width; index++) {
|
|
248
|
+
data[index * 4] = Math.round((red[index] ?? 0) * BYTE);
|
|
249
|
+
data[index * 4 + 1] = Math.round((green[index] ?? 0) * BYTE);
|
|
250
|
+
data[index * 4 + 3] = BYTE;
|
|
251
|
+
}
|
|
252
|
+
const texture = new DataTexture(data, width, 1, RGBAFormat, UnsignedByteType);
|
|
253
|
+
texture.magFilter = LinearFilter;
|
|
254
|
+
texture.minFilter = LinearFilter;
|
|
255
|
+
texture.wrapS = ClampToEdgeWrapping;
|
|
256
|
+
texture.wrapT = ClampToEdgeWrapping;
|
|
257
|
+
texture.needsUpdate = true;
|
|
258
|
+
return texture;
|
|
259
|
+
};
|
|
260
|
+
//#endregion
|
|
55
261
|
//#region src/atmosphere/createSkyState.ts
|
|
56
262
|
const createSkyState = () => ({
|
|
57
263
|
cloudLitColor: new Color(),
|
|
@@ -73,13 +279,27 @@ const createSkyState = () => ({
|
|
|
73
279
|
const createSkyUniforms = () => ({
|
|
74
280
|
cloudCoverage: uniform(0),
|
|
75
281
|
cloudDrift: uniform(new Vector2()),
|
|
282
|
+
cloudFrontBackBlend: uniform(1),
|
|
283
|
+
cloudLitBackColor: uniform(new Color()),
|
|
76
284
|
cloudLitColor: uniform(new Color()),
|
|
285
|
+
cloudShadeBackColor: uniform(new Color()),
|
|
77
286
|
cloudShadeColor: uniform(new Color()),
|
|
287
|
+
cloudSunBrighten: uniform(0),
|
|
288
|
+
frontBackBlend: uniform(DEFAULT_SKY_SHAPE.frontBackBlend),
|
|
289
|
+
haloColor: uniform(new Color(0, 0, 0)),
|
|
290
|
+
haloHeight: uniform(DEFAULT_SKY_SHAPE.haloHeight),
|
|
291
|
+
horizonBackColor: uniform(new Color()),
|
|
292
|
+
horizonBand: uniform(DEFAULT_SKY_SHAPE.horizonBand),
|
|
78
293
|
horizonColor: uniform(new Color()),
|
|
79
294
|
lightColor: uniform(new Color()),
|
|
80
295
|
moonDirection: uniform(new Vector3(0, -1, 0)),
|
|
296
|
+
moonGlowColor: uniform(new Color(0, 0, 0)),
|
|
297
|
+
moonSize: uniform(DEFAULT_SKY_SHAPE.moonSize),
|
|
81
298
|
starIntensity: uniform(0),
|
|
82
299
|
sunDirection: uniform(new Vector3(0, 1, 0)),
|
|
300
|
+
sunHaloColor: uniform(new Color(0, 0, 0)),
|
|
301
|
+
sunHaloSize: uniform(DEFAULT_SKY_SHAPE.sunHaloSize),
|
|
302
|
+
zenithBackColor: uniform(new Color()),
|
|
83
303
|
zenithColor: uniform(new Color())
|
|
84
304
|
});
|
|
85
305
|
//#endregion
|
|
@@ -108,6 +328,36 @@ const createSunLight = ({ cascadeCount, maxFar, shadowMapSize }) => {
|
|
|
108
328
|
};
|
|
109
329
|
};
|
|
110
330
|
//#endregion
|
|
331
|
+
//#region src/random/createSeededRandom.ts
|
|
332
|
+
const createSeededRandom = (seed) => {
|
|
333
|
+
let state = seed;
|
|
334
|
+
return () => {
|
|
335
|
+
state = state + 1831565813 >>> 0;
|
|
336
|
+
let mixed = Math.imul(state ^ state >>> 15, 1 | state);
|
|
337
|
+
mixed ^= mixed + Math.imul(mixed ^ mixed >>> 7, 61 | mixed);
|
|
338
|
+
return ((mixed ^ mixed >>> 14) >>> 0) / 2 ** 32;
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/atmosphere/placeCloudBand.ts
|
|
343
|
+
const placeCloudBand = ({ count, distanceRange: [near, far], heightRange: [low, high], seed, widthRange: [narrow, wide] }, spriteCount) => {
|
|
344
|
+
const random = createSeededRandom(seed);
|
|
345
|
+
return Array.from({ length: count }, () => {
|
|
346
|
+
const angle = random() * Math.PI * 2;
|
|
347
|
+
const distance = Math.sqrt(near ** 2 + random() * (far ** 2 - near ** 2));
|
|
348
|
+
const height = low + random() * (high - low);
|
|
349
|
+
return {
|
|
350
|
+
position: [
|
|
351
|
+
Math.cos(angle) * distance,
|
|
352
|
+
height,
|
|
353
|
+
Math.sin(angle) * distance
|
|
354
|
+
],
|
|
355
|
+
spriteIndex: Math.floor(random() * spriteCount),
|
|
356
|
+
width: narrow + random() * (wide - narrow)
|
|
357
|
+
};
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
//#endregion
|
|
111
361
|
//#region src/atmosphere/sampleSkyState.ts
|
|
112
362
|
const lerp = (from, to, amount) => from + (to - from) * amount;
|
|
113
363
|
const sampleSkyState = (skyKeyframes, minutes, tilt, skyState) => {
|
|
@@ -140,6 +390,28 @@ const advanceGameClock = (gameClock, deltaSeconds) => {
|
|
|
140
390
|
gameClock.minutes = (gameClock.minutes + deltaSeconds * gameClock.minutesPerSecond) % MINUTES_PER_DAY;
|
|
141
391
|
};
|
|
142
392
|
//#endregion
|
|
393
|
+
//#region src/kits/architecture/createBoxesGeometry.ts
|
|
394
|
+
const createBoxesGeometry = (boxes) => {
|
|
395
|
+
const parts = boxes.map(([minX = 0, minY = 0, minZ = 0, maxX = 0, maxY = 0, maxZ = 0]) => new BoxGeometry(maxX - minX, maxY - minY, maxZ - minZ).translate((minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2));
|
|
396
|
+
const geometry = mergeGeometries(parts) ?? new BufferGeometry();
|
|
397
|
+
for (const part of parts) part.dispose();
|
|
398
|
+
return geometry;
|
|
399
|
+
};
|
|
400
|
+
//#endregion
|
|
401
|
+
//#region src/kits/architecture/createLatheStackGeometry.ts
|
|
402
|
+
const createLatheStackGeometry = ({ isFaceted, radialSegments, sections }) => {
|
|
403
|
+
let footHeight = 0;
|
|
404
|
+
const parts = sections.map(({ bottomRadius, height, topRadius }) => {
|
|
405
|
+
const part = new CylinderGeometry(topRadius, bottomRadius, height, radialSegments).translate(0, footHeight + height / 2, 0);
|
|
406
|
+
footHeight += height;
|
|
407
|
+
return isFaceted ? part.toNonIndexed() : part;
|
|
408
|
+
});
|
|
409
|
+
const stackGeometry = mergeGeometries(parts) ?? new BufferGeometry();
|
|
410
|
+
for (const part of parts) part.dispose();
|
|
411
|
+
if (isFaceted) stackGeometry.computeVertexNormals();
|
|
412
|
+
return stackGeometry;
|
|
413
|
+
};
|
|
414
|
+
//#endregion
|
|
143
415
|
//#region src/kits/statue/createStatueGeometry.ts
|
|
144
416
|
const PLINTH_SIDES = 8;
|
|
145
417
|
const FIGURE_SEGMENTS = 24;
|
|
@@ -179,17 +451,6 @@ const createStatueGeometry = () => {
|
|
|
179
451
|
return statueGeometry;
|
|
180
452
|
};
|
|
181
453
|
//#endregion
|
|
182
|
-
//#region src/random/createSeededRandom.ts
|
|
183
|
-
const createSeededRandom = (seed) => {
|
|
184
|
-
let state = seed;
|
|
185
|
-
return () => {
|
|
186
|
-
state = state + 1831565813 >>> 0;
|
|
187
|
-
let mixed = Math.imul(state ^ state >>> 15, 1 | state);
|
|
188
|
-
mixed ^= mixed + Math.imul(mixed ^ mixed >>> 7, 61 | mixed);
|
|
189
|
-
return ((mixed ^ mixed >>> 14) >>> 0) / 2 ** 32;
|
|
190
|
-
};
|
|
191
|
-
};
|
|
192
|
-
//#endregion
|
|
193
454
|
//#region src/kits/tree/computeLeafCards.ts
|
|
194
455
|
const VERTICES_PER_CARD = 4;
|
|
195
456
|
const INDICES_PER_CARD = 6;
|
|
@@ -379,14 +640,18 @@ const createCausticsNode = ({ lightColor }, { causticStrength, deepDepth, level
|
|
|
379
640
|
return lightColor.mul(veins.mul(fade).mul(causticStrength));
|
|
380
641
|
};
|
|
381
642
|
//#endregion
|
|
643
|
+
//#region src/renderer/constants.ts
|
|
644
|
+
const GENSHIN_TONE_MAPPING = NeutralToneMapping;
|
|
645
|
+
//#endregion
|
|
382
646
|
//#region src/nodes/createGenshinRenderer.ts
|
|
383
647
|
const createGenshinRenderer = (canvas) => {
|
|
648
|
+
const isWindows = window.navigator.userAgent.includes("Windows");
|
|
384
649
|
const renderer = new WebGPURenderer({
|
|
385
650
|
antialias: false,
|
|
386
651
|
canvas,
|
|
387
|
-
powerPreference: "high-performance"
|
|
652
|
+
...isWindows ? {} : { powerPreference: "high-performance" }
|
|
388
653
|
});
|
|
389
|
-
renderer.toneMapping =
|
|
654
|
+
renderer.toneMapping = GENSHIN_TONE_MAPPING;
|
|
390
655
|
return renderer;
|
|
391
656
|
};
|
|
392
657
|
//#endregion
|
|
@@ -402,7 +667,7 @@ const createRimNode = ({ rimColor, rimStrength, sunDirection }) => {
|
|
|
402
667
|
//#region src/nodes/createToonMaterial.ts
|
|
403
668
|
const createToonMaterial = ({ color, isOutlined = true, isVertexColors = false, lightUniforms, rampTexture }) => {
|
|
404
669
|
const toonMaterial = new ToonNodeMaterial({
|
|
405
|
-
color,
|
|
670
|
+
...color === void 0 ? {} : { color },
|
|
406
671
|
gradientMap: rampTexture,
|
|
407
672
|
vertexColors: isVertexColors
|
|
408
673
|
}, isOutlined);
|
|
@@ -449,12 +714,37 @@ const createLightUniforms = () => ({
|
|
|
449
714
|
sunDirection: uniform(new Vector3(0, 1, 0))
|
|
450
715
|
});
|
|
451
716
|
//#endregion
|
|
717
|
+
//#region src/nodes/createSkyColorNode.ts
|
|
718
|
+
const LEAST_DIVISOR$1 = 1e-4;
|
|
719
|
+
const HALO_TOWARD_START = .3;
|
|
720
|
+
const HALO_TOWARD_SPAN = .7;
|
|
721
|
+
const HALO_SUN_HEIGHT_START = .2;
|
|
722
|
+
const HALO_SUN_HEIGHT_SPAN = .3;
|
|
723
|
+
const SUN_HALO_MIDDLE_SPREAD = .1;
|
|
724
|
+
const SUN_HALO_MIDDLE_WEIGHT = .12;
|
|
725
|
+
const SUN_HALO_OUTER_SPREAD = .01;
|
|
726
|
+
const SUN_HALO_OUTER_WEIGHT = .03;
|
|
727
|
+
const createSkyColorNode = ({ frontBackBlend, haloColor, haloHeight, horizonBackColor, horizonBand, horizonColor, sunDirection, sunHaloColor, sunHaloSize, zenithBackColor, zenithColor }, gradient, direction) => {
|
|
728
|
+
const height = direction.y;
|
|
729
|
+
const elevation = abs(asin(clamp(height, -1, 1)).mul(2 / Math.PI));
|
|
730
|
+
const sunCosine = direction.dot(sunDirection);
|
|
731
|
+
const toward = pow(max(sunCosine.mul(frontBackBlend).add(float(1).sub(frontBackBlend)), 0), 3);
|
|
732
|
+
const top = mix(zenithBackColor, zenithColor, toward);
|
|
733
|
+
const bottom = mix(horizonBackColor, horizonColor, toward);
|
|
734
|
+
const bottomShare = texture(gradient, vec2(elevation.div(max(horizonBand, LEAST_DIVISOR$1)), .5)).r;
|
|
735
|
+
const haloShare = texture(gradient, vec2(elevation.div(max(haloHeight, LEAST_DIVISOR$1)), .5)).g;
|
|
736
|
+
const sunSide = saturate(sunCosine.mul(.5).add(.5));
|
|
737
|
+
const towardSun = smoothstep(0, 1, max(sunSide.sub(HALO_TOWARD_START).div(HALO_TOWARD_SPAN), 0));
|
|
738
|
+
const sunUp = smoothstep(0, 1, saturate(abs(sunDirection.y).sub(HALO_SUN_HEIGHT_START).div(HALO_SUN_HEIGHT_SPAN)));
|
|
739
|
+
const halo = haloColor.mul(haloShare).mul(sunUp.mul(float(1).sub(towardSun)).add(towardSun));
|
|
740
|
+
const spread = sunHaloSize.mul(abs(height));
|
|
741
|
+
const sunHalo = min(pow(sunSide, spread), 1).add(min(pow(sunSide, spread.mul(SUN_HALO_MIDDLE_SPREAD)), 1).mul(SUN_HALO_MIDDLE_WEIGHT)).add(min(pow(sunSide, spread.mul(SUN_HALO_OUTER_SPREAD)), 1).mul(SUN_HALO_OUTER_WEIGHT)).mul(smoothstep(0, 1, max(sunSide.sub(.5).mul(2), 0)));
|
|
742
|
+
return mix(top, bottom, bottomShare).add(halo).add(sunHaloColor.mul(sunHalo));
|
|
743
|
+
};
|
|
744
|
+
//#endregion
|
|
452
745
|
//#region src/nodes/createSkyNode.ts
|
|
453
|
-
const HORIZON_BAND = .45;
|
|
454
746
|
const SUN_DISC_COSINE = Math.cos(.035);
|
|
455
747
|
const MOON_DISC_COSINE = Math.cos(.05);
|
|
456
|
-
const SUN_GLOW_POWER = 12;
|
|
457
|
-
const HORIZON_GLOW_POWER = 3;
|
|
458
748
|
const SUN_DISC_BRIGHTNESS = 6;
|
|
459
749
|
const CLOUD_SCALE = 1.6;
|
|
460
750
|
const CLOUD_MIN_HEIGHT = .04;
|
|
@@ -462,26 +752,46 @@ const CLOUD_EDGE = .04;
|
|
|
462
752
|
const CLOUD_SHADE_DEPTH = .18;
|
|
463
753
|
const STAR_SCALE = 420;
|
|
464
754
|
const STAR_THRESHOLD = .9975;
|
|
465
|
-
const
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
const
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
755
|
+
const LEAST_DIVISOR = 1e-4;
|
|
756
|
+
const MOON_GLOW_SPREAD = .1;
|
|
757
|
+
const MOON_GLOW_POWER = 6;
|
|
758
|
+
const createSkyNode = (uniforms, gradient) => {
|
|
759
|
+
const { cloudCoverage, cloudDrift, cloudLitColor, cloudShadeColor, lightColor, moonDirection, moonGlowColor, moonSize, starIntensity, sunDirection } = uniforms;
|
|
760
|
+
return Fn(() => {
|
|
761
|
+
const direction = normalWorldGeometry.normalize();
|
|
762
|
+
const height = direction.y;
|
|
763
|
+
const sunCosine = direction.dot(sunDirection);
|
|
764
|
+
const gradientColor = createSkyColorNode(uniforms, gradient, direction);
|
|
765
|
+
const moonCosine = saturate(direction.dot(moonDirection));
|
|
766
|
+
const moonGlow = pow(max(moonCosine.sub(1).div(max(moonSize.mul(MOON_GLOW_SPREAD), LEAST_DIVISOR)).add(1), 0), MOON_GLOW_POWER);
|
|
767
|
+
const sunVisibility = smoothstep(-.1, .05, sunDirection.y);
|
|
768
|
+
const sunDisc = smoothstep(SUN_DISC_COSINE - 5e-4, SUN_DISC_COSINE, sunCosine).mul(sunVisibility);
|
|
769
|
+
const moonDisc = smoothstep(MOON_DISC_COSINE - 5e-4, MOON_DISC_COSINE, direction.dot(moonDirection)).mul(smoothstep(-.05, .05, moonDirection.y));
|
|
770
|
+
const stars = smoothstep(STAR_THRESHOLD, 1, mx_cell_noise_float(direction.mul(STAR_SCALE))).mul(starIntensity).mul(smoothstep(0, .1, height));
|
|
771
|
+
const cloudPosition = direction.xz.div(max(height, CLOUD_MIN_HEIGHT)).mul(CLOUD_SCALE).add(cloudDrift);
|
|
772
|
+
const cloudNoise = mx_fractal_noise_float(vec3(cloudPosition, 0), 4, 2, .5).mul(.5).add(.5);
|
|
773
|
+
const cloudThreshold = float(1).sub(cloudCoverage);
|
|
774
|
+
const cloudDensity = smoothstep(cloudThreshold, cloudThreshold.add(CLOUD_EDGE), cloudNoise).mul(smoothstep(0, .12, height));
|
|
775
|
+
const cloudShade = smoothstep(cloudThreshold.add(CLOUD_SHADE_DEPTH), cloudThreshold.add(.22), cloudNoise);
|
|
776
|
+
const cloudColor = mix(cloudLitColor, cloudShadeColor, cloudShade);
|
|
777
|
+
const sky = gradientColor.add(moonGlowColor.mul(moonGlow)).add(vec3(stars)).add(vec3(.85, .88, 1).mul(moonDisc)).add(lightColor.mul(sunDisc.mul(SUN_DISC_BRIGHTNESS)));
|
|
778
|
+
return mix(sky, cloudColor, cloudDensity);
|
|
779
|
+
})();
|
|
780
|
+
};
|
|
781
|
+
//#endregion
|
|
782
|
+
//#region src/nodes/createStoneMaterial.ts
|
|
783
|
+
const createStoneMaterial = ({ albedo, rimColor, rimPower, rimStrength, smoothness, specularColor }, glowNode = vec3(0)) => {
|
|
784
|
+
const material = new MeshPhysicalNodeMaterial({
|
|
785
|
+
color: new Color(albedo),
|
|
786
|
+
metalness: 0,
|
|
787
|
+
roughness: 1 - smoothness,
|
|
788
|
+
specularColor: new Color().fromArray(specularColor),
|
|
789
|
+
specularIntensity: 1
|
|
790
|
+
});
|
|
791
|
+
const fresnel = float(1).sub(normalView.dot(positionViewDirection).saturate()).pow(rimPower);
|
|
792
|
+
material.emissiveNode = color(new Color().fromArray(rimColor)).mul(fresnel.mul(rimStrength)).add(glowNode);
|
|
793
|
+
return material;
|
|
794
|
+
};
|
|
485
795
|
//#endregion
|
|
486
796
|
//#region src/nodes/createWaterMaterial.ts
|
|
487
797
|
const RIPPLE_SCALE = .08;
|
|
@@ -616,6 +926,10 @@ const createFogUniforms = () => ({
|
|
|
616
926
|
color: uniform(new Color()),
|
|
617
927
|
density: uniform(0),
|
|
618
928
|
heightFalloff: uniform(0),
|
|
929
|
+
scatterColor: uniform(new Color()),
|
|
930
|
+
scatterDirection: uniform(new Vector3(0, 1, 0)),
|
|
931
|
+
scatterPower: uniform(1),
|
|
932
|
+
scatterStrength: uniform(0),
|
|
619
933
|
startDistance: uniform(0)
|
|
620
934
|
});
|
|
621
935
|
//#endregion
|
|
@@ -647,7 +961,7 @@ const createGradeLutTexture = (gradeOptions) => {
|
|
|
647
961
|
//#endregion
|
|
648
962
|
//#region src/post/createHeightFogNode.ts
|
|
649
963
|
const MIN_RAY_CLIMB = 1e-6;
|
|
650
|
-
const createHeightFogNode = (colorNode, depthNode, camera, { baseHeight, color, density, heightFalloff, startDistance }) => {
|
|
964
|
+
const createHeightFogNode = (colorNode, depthNode, camera, { baseHeight, color, density, heightFalloff, scatterColor, scatterDirection, scatterPower, scatterStrength, startDistance }) => {
|
|
651
965
|
const cameraWorldMatrix = uniform(camera.matrixWorld);
|
|
652
966
|
const cameraProjectionMatrixInverse = uniform(camera.projectionMatrixInverse);
|
|
653
967
|
return Fn(() => {
|
|
@@ -668,7 +982,8 @@ const createHeightFogNode = (colorNode, depthNode, camera, { baseHeight, color,
|
|
|
668
982
|
opticalDepth.assign(densityAtStart.mul(float(1).sub(exp(fogLength.mul(climb).negate()))).div(climb));
|
|
669
983
|
});
|
|
670
984
|
const opacity = float(1).sub(exp(opticalDepth.negate()));
|
|
671
|
-
|
|
985
|
+
const scatter = pow(max(ray.normalize().dot(scatterDirection), 0), scatterPower).mul(scatterStrength);
|
|
986
|
+
output.assign(vec4(mix(output.rgb, mix(color, scatterColor, scatter.min(1)), opacity), output.a));
|
|
672
987
|
});
|
|
673
988
|
return output;
|
|
674
989
|
})();
|
|
@@ -770,6 +1085,14 @@ const QualityTierSettingsMap = {
|
|
|
770
1085
|
}
|
|
771
1086
|
};
|
|
772
1087
|
//#endregion
|
|
1088
|
+
//#region src/renderer/getScreenDirection.ts
|
|
1089
|
+
const X_AXIS = new Vector3(1, 0, 0);
|
|
1090
|
+
const Y_AXIS = new Vector3(0, 1, 0);
|
|
1091
|
+
const getScreenDirection = ({ aspect, fov, pitch, yaw }, [x, y]) => {
|
|
1092
|
+
const halfHeight = Math.tan(MathUtils.degToRad(fov) / 2);
|
|
1093
|
+
return new Vector3((x * 2 - 1) * halfHeight * aspect, (1 - y * 2) * halfHeight, -1).normalize().applyAxisAngle(X_AXIS, pitch).applyAxisAngle(Y_AXIS, yaw);
|
|
1094
|
+
};
|
|
1095
|
+
//#endregion
|
|
773
1096
|
//#region src/terrain/constants.ts
|
|
774
1097
|
const TILE_INDEX_OFFSET = 2 ** 19;
|
|
775
1098
|
const TILE_INDEX_SPAN = 2 ** 20;
|
|
@@ -1089,6 +1412,7 @@ const createGrassGeometry = (segmentCount, bladeCount) => {
|
|
|
1089
1412
|
const { indices, positions } = computeGrassBlade(segmentCount);
|
|
1090
1413
|
const grassGeometry = new InstancedBufferGeometry();
|
|
1091
1414
|
grassGeometry.setAttribute("position", new BufferAttribute(positions, 3));
|
|
1415
|
+
grassGeometry.setAttribute("normal", new BufferAttribute(Float32Array.from({ length: positions.length }, (_, index) => index % 3 === 1 ? 1 : 0), 3));
|
|
1092
1416
|
grassGeometry.setIndex(new BufferAttribute(indices, 1));
|
|
1093
1417
|
grassGeometry.instanceCount = bladeCount;
|
|
1094
1418
|
return grassGeometry;
|
|
@@ -1255,4 +1579,4 @@ const computeOutlineDistance = (outline, x, z) => {
|
|
|
1255
1579
|
return isInside ? 0 : Math.sqrt(nearestSquared);
|
|
1256
1580
|
};
|
|
1257
1581
|
//#endregion
|
|
1258
|
-
export { AntialiasingMode, GAME_MINUTES_PER_SECOND, MINUTES_PER_DAY, QualityTier, QualityTierSettingsMap, TERRAIN_LAYER, TILE_INDEX_OFFSET, TILE_INDEX_SPAN, ToonNodeMaterial, advanceGameClock, applySkyState, computeGradeLut, computeGrassBlade, computeLeafCards, computeOriginShift, computeOutlineDistance, computeRampValues, computeSunDirection, computeTerrainIndices, computeTerrainTile, computeTreeSkeleton, createCausticsNode, createFogUniforms, createGenshinRenderer, createGodraysLight, createGradeLutTexture, createGrassGeometry, createGrassMaterial, createGroundCapture, createHeightFogNode, createLeafMaterial, createLightUniforms, createPostPipeline, createPostUniforms, createRampTexture, createRimNode, createSeededRandom, createSimplexNoise, createSkyNode, createSkyState, createSkyUniforms, createStatueGeometry, createSunLight, createTerrainMaterial, createTerrainSelection, createTerrainTileGeometry, createTileStreamer, createToonMaterial, createTreeGeometry, createUnderwaterFogState, createWaterMaterial, createWaterUniforms, createWindNode, createWindUniforms, getParentTerrainTileKey, getTerrainTileColumn, getTerrainTileKey, getTerrainTileLevel, getTerrainTileRow, renderGroundCapture, resolveTerrainDraws, sampleSkyState, selectTerrainTiles, updateUnderwaterFog };
|
|
1582
|
+
export { AntialiasingMode, DEFAULT_SKY_GRADIENT, DEFAULT_SKY_SHAPE, GAME_MINUTES_PER_SECOND, GENSHIN_TONE_MAPPING, MINUTES_PER_DAY, QualityTier, QualityTierSettingsMap, TERRAIN_LAYER, TILE_INDEX_OFFSET, TILE_INDEX_SPAN, ToonNodeMaterial, addSmoothLoop, advanceGameClock, applySkyState, computeGradeLut, computeGrassBlade, computeLeafCards, computeOriginShift, computeOutlineDistance, computeRampValues, computeSunDirection, computeTerrainIndices, computeTerrainTile, computeTreeSkeleton, createBoxesGeometry, createCausticsNode, createCloudAtlasTexture, createCloudBandSprite, createFogUniforms, createGenshinRenderer, createGodraysLight, createGradeLutTexture, createGrassGeometry, createGrassMaterial, createGroundCapture, createHeightFogNode, createLatheStackGeometry, createLeafMaterial, createLightUniforms, createPostPipeline, createPostUniforms, createRampTexture, createRimNode, createSeededRandom, createSimplexNoise, createSkyColorNode, createSkyGradientTexture, createSkyNode, createSkyState, createSkyUniforms, createStatueGeometry, createStoneMaterial, createSunLight, createTerrainMaterial, createTerrainSelection, createTerrainTileGeometry, createTileStreamer, createToonMaterial, createTreeGeometry, createUnderwaterFogState, createWaterMaterial, createWaterUniforms, createWindNode, createWindUniforms, getCloudAtlasColumns, getParentTerrainTileKey, getScreenDirection, getTerrainTileColumn, getTerrainTileKey, getTerrainTileLevel, getTerrainTileRow, orderByViewDepth, placeCloudBand, renderGroundCapture, resolveTerrainDraws, sampleSkyState, selectTerrainTiles, toSceneColor, toneMapNeutral, updateUnderwaterFog };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genshin-engine",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "An anime-style open-world engine for the browser on three.js WebGPU — toon materials, outlines, post-processing, streamed terrain and parametric world kits, as plain TypeScript and TSL modules.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"anime",
|
|
@@ -53,16 +53,16 @@
|
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@arethetypeswrong/core": "^0.18.5",
|
|
56
|
-
"@esposter/configuration": "3.
|
|
57
|
-
"@esposter/shared-node": "3.
|
|
58
|
-
"@types/node": "^26.6.
|
|
56
|
+
"@esposter/configuration": "3.9.0",
|
|
57
|
+
"@esposter/shared-node": "3.9.0",
|
|
58
|
+
"@types/node": "^26.6.4",
|
|
59
59
|
"@types/three": "^0.186.0",
|
|
60
|
-
"publint": "^0.3.
|
|
60
|
+
"publint": "^0.3.25",
|
|
61
61
|
"tsdown": "^0.23.0",
|
|
62
|
-
"vitest": "^5.0.
|
|
62
|
+
"vitest": "^5.0.3"
|
|
63
63
|
},
|
|
64
64
|
"peerDependencies": {
|
|
65
65
|
"three": "^0.186.1"
|
|
66
66
|
},
|
|
67
|
-
"gitHead": "
|
|
67
|
+
"gitHead": "f9f6208c35e6cff4ed33910623c798cd88f09301"
|
|
68
68
|
}
|