@multiplekex/shallot 0.2.4 → 0.2.5
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/extras/arrows/index.ts +3 -3
- package/src/extras/caustic.ts +37 -0
- package/src/extras/gradient/index.ts +63 -69
- package/src/extras/index.ts +3 -0
- package/src/extras/lines/index.ts +3 -3
- package/src/extras/skylab/index.ts +314 -0
- package/src/extras/text/font.ts +69 -14
- package/src/extras/text/index.ts +8 -5
- package/src/extras/text/sdf.ts +13 -2
- package/src/extras/water.ts +64 -0
- package/src/standard/defaults.ts +2 -0
- package/src/standard/index.ts +2 -0
- package/src/standard/raster/index.ts +517 -0
- package/src/standard/{render → raytracing}/bvh/blas.ts +3 -3
- package/src/standard/{render → raytracing}/bvh/tlas.ts +3 -0
- package/src/standard/{render → raytracing}/depth.ts +9 -9
- package/src/standard/raytracing/index.ts +380 -0
- package/src/standard/{render → raytracing}/instance.ts +3 -0
- package/src/standard/raytracing/shaders.ts +815 -0
- package/src/standard/{render → raytracing}/triangle.ts +1 -1
- package/src/standard/render/camera.ts +88 -80
- package/src/standard/render/index.ts +68 -208
- package/src/standard/render/indirect.ts +9 -10
- package/src/standard/render/mesh/index.ts +35 -166
- package/src/standard/render/overlay.ts +4 -4
- package/src/standard/render/pass.ts +1 -1
- package/src/standard/render/postprocess.ts +75 -50
- package/src/standard/render/scene.ts +28 -16
- package/src/standard/render/surface/compile.ts +6 -8
- package/src/standard/render/surface/noise.ts +15 -2
- package/src/standard/render/surface/shaders.ts +257 -0
- package/src/standard/render/surface/structs.ts +13 -6
- package/src/standard/render/forward/index.ts +0 -259
- package/src/standard/render/forward/raster.ts +0 -228
- package/src/standard/render/shaders.ts +0 -484
- package/src/standard/render/surface/wgsl.ts +0 -573
- /package/src/standard/{render → raytracing}/bvh/radix.ts +0 -0
- /package/src/standard/{render → raytracing}/bvh/structs.ts +0 -0
- /package/src/standard/{render → raytracing}/bvh/traverse.ts +0 -0
- /package/src/standard/{render → raytracing}/intersection.ts +0 -0
- /package/src/standard/{render → raytracing}/ray.ts +0 -0
package/package.json
CHANGED
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
type Draw,
|
|
18
18
|
type SharedPassContext,
|
|
19
19
|
} from "../../standard/render";
|
|
20
|
-
import {
|
|
21
|
-
import { SCENE_STRUCT_WGSL } from "../../standard/render/
|
|
20
|
+
import { Z_FORMAT } from "../../standard/render/scene";
|
|
21
|
+
import { SCENE_STRUCT_WGSL } from "../../standard/render/surface/structs";
|
|
22
22
|
import { Transform } from "../../standard/transforms";
|
|
23
23
|
import { Line, Lines, LinesPlugin } from "../lines";
|
|
24
24
|
|
|
@@ -198,7 +198,7 @@ export function createArrowsPipeline(
|
|
|
198
198
|
topology: "triangle-list",
|
|
199
199
|
},
|
|
200
200
|
depthStencil: {
|
|
201
|
-
format:
|
|
201
|
+
format: Z_FORMAT,
|
|
202
202
|
depthCompare: "less",
|
|
203
203
|
depthWriteEnabled: false,
|
|
204
204
|
},
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { surface } from "../standard/render/surface";
|
|
2
|
+
|
|
3
|
+
export const Caustic = surface({
|
|
4
|
+
fragment: `
|
|
5
|
+
let uv = (*surface).worldPos.xz;
|
|
6
|
+
let t = scene.time * 0.5;
|
|
7
|
+
|
|
8
|
+
// Fine caustic network
|
|
9
|
+
let f1 = sin(uv.x * 4.0 + t * 1.3 + sin(uv.y * 3.0 + t * 0.9) * 0.6);
|
|
10
|
+
let f2 = sin(uv.y * 5.0 - t * 1.1 + sin(uv.x * 3.5 - t * 0.7) * 0.5);
|
|
11
|
+
let f3 = sin((uv.x + uv.y) * 3.5 + t * 0.8);
|
|
12
|
+
let f4 = sin((uv.x - uv.y) * 4.0 - t * 1.2);
|
|
13
|
+
let f5 = sin(uv.x * 6.0 - uv.y * 2.5 + t * 1.5);
|
|
14
|
+
let f6 = sin(uv.y * 6.5 + uv.x * 2.0 - t * 1.0);
|
|
15
|
+
|
|
16
|
+
// Medium detail layer
|
|
17
|
+
let m1 = sin(uv.x * 2.5 + t * 0.7 + sin(uv.y * 1.5 + t * 0.5) * 0.4);
|
|
18
|
+
let m2 = sin(uv.y * 2.8 - t * 0.6 + sin(uv.x * 2.0 - t * 0.4) * 0.3);
|
|
19
|
+
|
|
20
|
+
// Sharp caustic lines using high power
|
|
21
|
+
let c1 = pow(max(0.0, 1.0 - abs(f1)), 12.0);
|
|
22
|
+
let c2 = pow(max(0.0, 1.0 - abs(f2)), 12.0);
|
|
23
|
+
let c3 = pow(max(0.0, 1.0 - abs(f3)), 10.0);
|
|
24
|
+
let c4 = pow(max(0.0, 1.0 - abs(f4)), 10.0);
|
|
25
|
+
let c5 = pow(max(0.0, 1.0 - abs(f5)), 14.0);
|
|
26
|
+
let c6 = pow(max(0.0, 1.0 - abs(f6)), 14.0);
|
|
27
|
+
let c7 = pow(max(0.0, 1.0 - abs(m1)), 8.0);
|
|
28
|
+
let c8 = pow(max(0.0, 1.0 - abs(m2)), 8.0);
|
|
29
|
+
|
|
30
|
+
// Combine layers with variation
|
|
31
|
+
let fine = (c1 + c2 + c3 + c4 + c5 + c6) * 0.12;
|
|
32
|
+
let medium = (c7 + c8) * 0.15;
|
|
33
|
+
let caustic = fine + medium;
|
|
34
|
+
|
|
35
|
+
let light = scene.sunColor.rgb * caustic * 0.3;
|
|
36
|
+
(*surface).baseColor += light;`,
|
|
37
|
+
});
|
|
@@ -443,8 +443,8 @@ export interface Gradients {
|
|
|
443
443
|
compositeBindGroupLayout: GPUBindGroupLayout | null;
|
|
444
444
|
compositeUniformBuffer: GPUBuffer | null;
|
|
445
445
|
gradientAngle: number;
|
|
446
|
-
gradientColor1:
|
|
447
|
-
gradientColor2:
|
|
446
|
+
gradientColor1: Float32Array;
|
|
447
|
+
gradientColor2: Float32Array;
|
|
448
448
|
textureSeed: number;
|
|
449
449
|
textureEnabled: boolean;
|
|
450
450
|
fineNoise: number;
|
|
@@ -453,8 +453,8 @@ export interface Gradients {
|
|
|
453
453
|
largeScale: number;
|
|
454
454
|
fiberIntensity: number;
|
|
455
455
|
textureOpacity: number;
|
|
456
|
-
overlayColor:
|
|
457
|
-
bubbleUniformData: Float32Array
|
|
456
|
+
overlayColor: Float32Array;
|
|
457
|
+
bubbleUniformData: Float32Array;
|
|
458
458
|
bubbleRadius: number;
|
|
459
459
|
blurRadius: number;
|
|
460
460
|
bubbleCount: number;
|
|
@@ -758,6 +758,8 @@ fn fs(input: VertexOutput) -> @location(0) vec4f {
|
|
|
758
758
|
}
|
|
759
759
|
`;
|
|
760
760
|
|
|
761
|
+
const compositeUniformData = new Float32Array(60);
|
|
762
|
+
|
|
761
763
|
function createCompositeNode(res: Gradients): ComputeNode {
|
|
762
764
|
return {
|
|
763
765
|
id: "gradient",
|
|
@@ -766,7 +768,6 @@ function createCompositeNode(res: Gradients): ComputeNode {
|
|
|
766
768
|
|
|
767
769
|
execute(ctx: ExecutionContext) {
|
|
768
770
|
if (res.width === 0 || res.height === 0) return;
|
|
769
|
-
if (!res.bubbleUniformData) return;
|
|
770
771
|
|
|
771
772
|
if (!res.compositeUniformBuffer) {
|
|
772
773
|
res.compositeUniformBuffer = ctx.device.createBuffer({
|
|
@@ -810,49 +811,47 @@ function createCompositeNode(res: Gradients): ComputeNode {
|
|
|
810
811
|
});
|
|
811
812
|
}
|
|
812
813
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
uniformData[10] = res.gradientColor2[2];
|
|
826
|
-
uniformData[11] = res.gradientColor2[3];
|
|
814
|
+
compositeUniformData[0] = res.overlayColor[0];
|
|
815
|
+
compositeUniformData[1] = res.overlayColor[1];
|
|
816
|
+
compositeUniformData[2] = res.overlayColor[2];
|
|
817
|
+
compositeUniformData[3] = res.overlayColor[3];
|
|
818
|
+
compositeUniformData[4] = res.gradientColor1[0];
|
|
819
|
+
compositeUniformData[5] = res.gradientColor1[1];
|
|
820
|
+
compositeUniformData[6] = res.gradientColor1[2];
|
|
821
|
+
compositeUniformData[7] = res.gradientColor1[3];
|
|
822
|
+
compositeUniformData[8] = res.gradientColor2[0];
|
|
823
|
+
compositeUniformData[9] = res.gradientColor2[1];
|
|
824
|
+
compositeUniformData[10] = res.gradientColor2[2];
|
|
825
|
+
compositeUniformData[11] = res.gradientColor2[3];
|
|
827
826
|
|
|
828
827
|
for (let i = 0; i < 4; i++) {
|
|
829
828
|
const srcOffset = i * 8;
|
|
830
829
|
const dstOffset = 12 + i * 8;
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
830
|
+
compositeUniformData[dstOffset + 0] = res.bubbleUniformData[srcOffset + 0];
|
|
831
|
+
compositeUniformData[dstOffset + 1] = res.bubbleUniformData[srcOffset + 1];
|
|
832
|
+
compositeUniformData[dstOffset + 4] = res.bubbleUniformData[srcOffset + 4];
|
|
833
|
+
compositeUniformData[dstOffset + 5] = res.bubbleUniformData[srcOffset + 5];
|
|
834
|
+
compositeUniformData[dstOffset + 6] = res.bubbleUniformData[srcOffset + 6];
|
|
835
|
+
compositeUniformData[dstOffset + 7] = res.bubbleUniformData[srcOffset + 7];
|
|
837
836
|
}
|
|
838
837
|
|
|
839
|
-
const u32View = new Uint32Array(
|
|
838
|
+
const u32View = new Uint32Array(compositeUniformData.buffer);
|
|
840
839
|
u32View[44] = res.textureSeed;
|
|
841
840
|
u32View[45] = res.textureEnabled ? 1 : 0;
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
841
|
+
compositeUniformData[46] = res.fineNoise;
|
|
842
|
+
compositeUniformData[47] = res.mediumNoise;
|
|
843
|
+
compositeUniformData[48] = res.coarseNoise;
|
|
844
|
+
compositeUniformData[49] = res.largeScale;
|
|
845
|
+
compositeUniformData[50] = res.fiberIntensity;
|
|
846
|
+
compositeUniformData[51] = res.textureOpacity;
|
|
847
|
+
compositeUniformData[52] = res.width;
|
|
848
|
+
compositeUniformData[53] = res.height;
|
|
849
|
+
compositeUniformData[54] = res.gradientAngle;
|
|
850
|
+
compositeUniformData[55] = res.bubbleRadius;
|
|
851
|
+
compositeUniformData[56] = res.blurRadius;
|
|
853
852
|
u32View[57] = res.bubbleCount;
|
|
854
853
|
|
|
855
|
-
ctx.queue.writeBuffer(res.compositeUniformBuffer, 0,
|
|
854
|
+
ctx.queue.writeBuffer(res.compositeUniformBuffer, 0, compositeUniformData);
|
|
856
855
|
|
|
857
856
|
const pass = ctx.encoder.beginRenderPass({
|
|
858
857
|
colorAttachments: [
|
|
@@ -931,34 +930,28 @@ export const GradientSystem: System = {
|
|
|
931
930
|
const color1 = parseColor(gradientColor1);
|
|
932
931
|
const color2 = parseColor(gradientColor2);
|
|
933
932
|
res.gradientAngle = angle;
|
|
934
|
-
res.gradientColor1 = [
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
];
|
|
940
|
-
res.gradientColor2 = [
|
|
941
|
-
|
|
942
|
-
color2[1] / 255,
|
|
943
|
-
color2[2] / 255,
|
|
944
|
-
color2[3] / 255,
|
|
945
|
-
];
|
|
933
|
+
res.gradientColor1[0] = color1[0] / 255;
|
|
934
|
+
res.gradientColor1[1] = color1[1] / 255;
|
|
935
|
+
res.gradientColor1[2] = color1[2] / 255;
|
|
936
|
+
res.gradientColor1[3] = color1[3] / 255;
|
|
937
|
+
res.gradientColor2[0] = color2[0] / 255;
|
|
938
|
+
res.gradientColor2[1] = color2[1] / 255;
|
|
939
|
+
res.gradientColor2[2] = color2[2] / 255;
|
|
940
|
+
res.gradientColor2[3] = color2[3] / 255;
|
|
946
941
|
|
|
947
942
|
const bubbleSize = Gradient.bubbleSize[eid] ?? DEFAULT_BUBBLE_CONFIG.size;
|
|
948
943
|
const bubbleBlur = Gradient.bubbleBlur[eid] ?? DEFAULT_BUBBLE_CONFIG.blur;
|
|
949
944
|
|
|
950
|
-
const bubbleUniformData = new Float32Array(4 * 8);
|
|
951
945
|
for (let i = 0; i < b.length; i++) {
|
|
952
946
|
const offset = i * 8;
|
|
953
|
-
bubbleUniformData[offset + 0] = b[i].x / 100;
|
|
954
|
-
bubbleUniformData[offset + 1] = b[i].y / 100;
|
|
947
|
+
res.bubbleUniformData[offset + 0] = b[i].x / 100;
|
|
948
|
+
res.bubbleUniformData[offset + 1] = b[i].y / 100;
|
|
955
949
|
const color = parseColor(b[i].color);
|
|
956
|
-
bubbleUniformData[offset + 4] = color[0] / 255;
|
|
957
|
-
bubbleUniformData[offset + 5] = color[1] / 255;
|
|
958
|
-
bubbleUniformData[offset + 6] = color[2] / 255;
|
|
959
|
-
bubbleUniformData[offset + 7] = color[3] / 255;
|
|
950
|
+
res.bubbleUniformData[offset + 4] = color[0] / 255;
|
|
951
|
+
res.bubbleUniformData[offset + 5] = color[1] / 255;
|
|
952
|
+
res.bubbleUniformData[offset + 6] = color[2] / 255;
|
|
953
|
+
res.bubbleUniformData[offset + 7] = color[3] / 255;
|
|
960
954
|
}
|
|
961
|
-
res.bubbleUniformData = bubbleUniformData;
|
|
962
955
|
res.bubbleRadius = (bubbleSize / 100) * Math.min(res.width, res.height);
|
|
963
956
|
res.blurRadius = (bubbleBlur / 100) * Math.min(res.width, res.height);
|
|
964
957
|
|
|
@@ -979,14 +972,15 @@ export const GradientSystem: System = {
|
|
|
979
972
|
const overlayColor = parseColor(
|
|
980
973
|
Gradient.overlayColor[eid] || DEFAULT_OVERLAY_CONFIG.color
|
|
981
974
|
);
|
|
982
|
-
res.overlayColor = [
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
overlayColor[3] / 255,
|
|
987
|
-
];
|
|
975
|
+
res.overlayColor[0] = overlayColor[0] / 255;
|
|
976
|
+
res.overlayColor[1] = overlayColor[1] / 255;
|
|
977
|
+
res.overlayColor[2] = overlayColor[2] / 255;
|
|
978
|
+
res.overlayColor[3] = overlayColor[3] / 255;
|
|
988
979
|
} else {
|
|
989
|
-
res.overlayColor
|
|
980
|
+
res.overlayColor[0] = 0;
|
|
981
|
+
res.overlayColor[1] = 0;
|
|
982
|
+
res.overlayColor[2] = 0;
|
|
983
|
+
res.overlayColor[3] = 0;
|
|
990
984
|
}
|
|
991
985
|
}
|
|
992
986
|
},
|
|
@@ -1007,8 +1001,8 @@ export const GradientPlugin: Plugin = {
|
|
|
1007
1001
|
compositeBindGroupLayout: null,
|
|
1008
1002
|
compositeUniformBuffer: null,
|
|
1009
1003
|
gradientAngle: 0,
|
|
1010
|
-
gradientColor1: [0, 0, 0, 1],
|
|
1011
|
-
gradientColor2: [0, 0, 0, 1],
|
|
1004
|
+
gradientColor1: new Float32Array([0, 0, 0, 1]),
|
|
1005
|
+
gradientColor2: new Float32Array([0, 0, 0, 1]),
|
|
1012
1006
|
textureSeed: 0,
|
|
1013
1007
|
textureEnabled: true,
|
|
1014
1008
|
fineNoise: DEFAULT_TEXTURE_CONFIG.fineNoise,
|
|
@@ -1017,8 +1011,8 @@ export const GradientPlugin: Plugin = {
|
|
|
1017
1011
|
largeScale: DEFAULT_TEXTURE_CONFIG.largeScale,
|
|
1018
1012
|
fiberIntensity: DEFAULT_TEXTURE_CONFIG.fiberIntensity,
|
|
1019
1013
|
textureOpacity: DEFAULT_TEXTURE_CONFIG.opacity,
|
|
1020
|
-
overlayColor:
|
|
1021
|
-
bubbleUniformData:
|
|
1014
|
+
overlayColor: new Float32Array(4),
|
|
1015
|
+
bubbleUniformData: new Float32Array(4 * 8),
|
|
1022
1016
|
bubbleRadius: 0,
|
|
1023
1017
|
blurRadius: 0,
|
|
1024
1018
|
bubbleCount: 4,
|
package/src/extras/index.ts
CHANGED
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
type Draw,
|
|
18
18
|
type SharedPassContext,
|
|
19
19
|
} from "../../standard/render";
|
|
20
|
-
import {
|
|
21
|
-
import { SCENE_STRUCT_WGSL } from "../../standard/render/
|
|
20
|
+
import { Z_FORMAT } from "../../standard/render/scene";
|
|
21
|
+
import { SCENE_STRUCT_WGSL } from "../../standard/render/surface/structs";
|
|
22
22
|
import { Transform } from "../../standard/transforms";
|
|
23
23
|
|
|
24
24
|
export const LineData = {
|
|
@@ -240,7 +240,7 @@ export function createLinesPipeline(
|
|
|
240
240
|
topology: "triangle-list",
|
|
241
241
|
},
|
|
242
242
|
depthStencil: {
|
|
243
|
-
format:
|
|
243
|
+
format: Z_FORMAT,
|
|
244
244
|
depthCompare: "less",
|
|
245
245
|
depthWriteEnabled: false,
|
|
246
246
|
},
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import type { Plugin, State, System } from "../../core";
|
|
2
|
+
import { setTraits } from "../../core/component";
|
|
3
|
+
import {
|
|
4
|
+
Camera,
|
|
5
|
+
Sky,
|
|
6
|
+
Sun,
|
|
7
|
+
Stars,
|
|
8
|
+
Moon,
|
|
9
|
+
Haze,
|
|
10
|
+
Clouds,
|
|
11
|
+
AmbientLight,
|
|
12
|
+
DirectionalLight,
|
|
13
|
+
} from "../../standard/render";
|
|
14
|
+
|
|
15
|
+
export const Skylab = {
|
|
16
|
+
azimuth: [] as number[],
|
|
17
|
+
elevation: [] as number[],
|
|
18
|
+
};
|
|
19
|
+
setTraits(Skylab, { defaults: () => ({ azimuth: 37, elevation: 45 }) });
|
|
20
|
+
|
|
21
|
+
interface ColorRGB {
|
|
22
|
+
r: number;
|
|
23
|
+
g: number;
|
|
24
|
+
b: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface GradientStop {
|
|
28
|
+
elevation: number;
|
|
29
|
+
sunColor: ColorRGB;
|
|
30
|
+
sunIntensity: number;
|
|
31
|
+
ambientColor: ColorRGB;
|
|
32
|
+
ambientIntensity: number;
|
|
33
|
+
zenith: ColorRGB;
|
|
34
|
+
horizon: ColorRGB;
|
|
35
|
+
sunGlow: number;
|
|
36
|
+
starsIntensity: number;
|
|
37
|
+
moonGlow: number;
|
|
38
|
+
moonElevationOffset: number;
|
|
39
|
+
hazeDensity: number;
|
|
40
|
+
hazeColor: ColorRGB;
|
|
41
|
+
cloudsColor: ColorRGB;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const STOPS: GradientStop[] = [
|
|
45
|
+
{
|
|
46
|
+
elevation: -90,
|
|
47
|
+
sunColor: { r: 0.25, g: 0.3, b: 0.55 },
|
|
48
|
+
sunIntensity: 0.15,
|
|
49
|
+
ambientColor: { r: 0.3, g: 0.25, b: 0.55 },
|
|
50
|
+
ambientIntensity: 0.5,
|
|
51
|
+
zenith: { r: 0.03, g: 0.02, b: 0.1 },
|
|
52
|
+
horizon: { r: 0.05, g: 0.06, b: 0.12 },
|
|
53
|
+
sunGlow: 0,
|
|
54
|
+
starsIntensity: 1.0,
|
|
55
|
+
moonGlow: 0.4,
|
|
56
|
+
moonElevationOffset: 180,
|
|
57
|
+
hazeDensity: 0.001,
|
|
58
|
+
hazeColor: { r: 0.05, g: 0.04, b: 0.12 },
|
|
59
|
+
cloudsColor: { r: 0.1, g: 0.1, b: 0.18 },
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
elevation: -6,
|
|
63
|
+
sunColor: { r: 0.6, g: 0.2, b: 0.3 },
|
|
64
|
+
sunIntensity: 0.1,
|
|
65
|
+
ambientColor: { r: 0.25, g: 0.18, b: 0.45 },
|
|
66
|
+
ambientIntensity: 0.5,
|
|
67
|
+
zenith: { r: 0.05, g: 0.02, b: 0.15 },
|
|
68
|
+
horizon: { r: 0.4, g: 0.15, b: 0.25 },
|
|
69
|
+
sunGlow: 0,
|
|
70
|
+
starsIntensity: 0.6,
|
|
71
|
+
moonGlow: 0.35,
|
|
72
|
+
moonElevationOffset: 160,
|
|
73
|
+
hazeDensity: 0.003,
|
|
74
|
+
hazeColor: { r: 0.25, g: 0.1, b: 0.2 },
|
|
75
|
+
cloudsColor: { r: 0.3, g: 0.12, b: 0.2 },
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
elevation: 0,
|
|
79
|
+
sunColor: { r: 1.0, g: 0.45, b: 0.15 },
|
|
80
|
+
sunIntensity: 0.4,
|
|
81
|
+
ambientColor: { r: 0.35, g: 0.2, b: 0.15 },
|
|
82
|
+
ambientIntensity: 0.5,
|
|
83
|
+
zenith: { r: 0.1, g: 0.08, b: 0.3 },
|
|
84
|
+
horizon: { r: 0.9, g: 0.4, b: 0.15 },
|
|
85
|
+
sunGlow: 1.2,
|
|
86
|
+
starsIntensity: 0.1,
|
|
87
|
+
moonGlow: 0,
|
|
88
|
+
moonElevationOffset: 140,
|
|
89
|
+
hazeDensity: 0.008,
|
|
90
|
+
hazeColor: { r: 0.8, g: 0.4, b: 0.15 },
|
|
91
|
+
cloudsColor: { r: 0.95, g: 0.5, b: 0.2 },
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
elevation: 8,
|
|
95
|
+
sunColor: { r: 1.0, g: 0.7, b: 0.4 },
|
|
96
|
+
sunIntensity: 0.7,
|
|
97
|
+
ambientColor: { r: 0.5, g: 0.4, b: 0.3 },
|
|
98
|
+
ambientIntensity: 0.7,
|
|
99
|
+
zenith: { r: 0.15, g: 0.25, b: 0.55 },
|
|
100
|
+
horizon: { r: 0.85, g: 0.6, b: 0.3 },
|
|
101
|
+
sunGlow: 0.8,
|
|
102
|
+
starsIntensity: 0,
|
|
103
|
+
moonGlow: 0,
|
|
104
|
+
moonElevationOffset: 120,
|
|
105
|
+
hazeDensity: 0.006,
|
|
106
|
+
hazeColor: { r: 0.7, g: 0.55, b: 0.35 },
|
|
107
|
+
cloudsColor: { r: 0.95, g: 0.75, b: 0.5 },
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
elevation: 20,
|
|
111
|
+
sunColor: { r: 1.0, g: 1.0, b: 1.0 },
|
|
112
|
+
sunIntensity: 0.75,
|
|
113
|
+
ambientColor: { r: 0.55, g: 0.52, b: 0.5 },
|
|
114
|
+
ambientIntensity: 1.0,
|
|
115
|
+
zenith: { r: 0.25, g: 0.48, b: 0.82 },
|
|
116
|
+
horizon: { r: 0.3, g: 0.6, b: 0.85 },
|
|
117
|
+
sunGlow: 0.5,
|
|
118
|
+
starsIntensity: 0,
|
|
119
|
+
moonGlow: 0,
|
|
120
|
+
moonElevationOffset: 90,
|
|
121
|
+
hazeDensity: 0.005,
|
|
122
|
+
hazeColor: { r: 0.3, g: 0.5, b: 0.82 },
|
|
123
|
+
cloudsColor: { r: 1.0, g: 1.0, b: 1.0 },
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
elevation: 50,
|
|
127
|
+
sunColor: { r: 1.0, g: 1.0, b: 1.0 },
|
|
128
|
+
sunIntensity: 0.81,
|
|
129
|
+
ambientColor: { r: 0.53, g: 0.536, b: 0.54 },
|
|
130
|
+
ambientIntensity: 1.0,
|
|
131
|
+
zenith: { r: 0.25, g: 0.47, b: 0.815 },
|
|
132
|
+
horizon: { r: 0.24, g: 0.595, b: 0.845 },
|
|
133
|
+
sunGlow: 0.4,
|
|
134
|
+
starsIntensity: 0,
|
|
135
|
+
moonGlow: 0,
|
|
136
|
+
moonElevationOffset: 60,
|
|
137
|
+
hazeDensity: 0.005,
|
|
138
|
+
hazeColor: { r: 0.24, g: 0.465, b: 0.815 },
|
|
139
|
+
cloudsColor: { r: 1.0, g: 1.0, b: 1.0 },
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
function lerpColor(a: ColorRGB, b: ColorRGB, t: number): ColorRGB {
|
|
144
|
+
return {
|
|
145
|
+
r: a.r + (b.r - a.r) * t,
|
|
146
|
+
g: a.g + (b.g - a.g) * t,
|
|
147
|
+
b: a.b + (b.b - a.b) * t,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function lerp(a: number, b: number, t: number): number {
|
|
152
|
+
return a + (b - a) * t;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function packColor(c: ColorRGB): number {
|
|
156
|
+
return (
|
|
157
|
+
(Math.round(Math.min(1, Math.max(0, c.r)) * 255) << 16) |
|
|
158
|
+
(Math.round(Math.min(1, Math.max(0, c.g)) * 255) << 8) |
|
|
159
|
+
Math.round(Math.min(1, Math.max(0, c.b)) * 255)
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface SkylabOutput {
|
|
164
|
+
sunColor: number;
|
|
165
|
+
sunIntensity: number;
|
|
166
|
+
ambientColor: number;
|
|
167
|
+
ambientIntensity: number;
|
|
168
|
+
zenith: number;
|
|
169
|
+
horizon: number;
|
|
170
|
+
sunGlow: number;
|
|
171
|
+
starsIntensity: number;
|
|
172
|
+
moonGlow: number;
|
|
173
|
+
moonAzimuth: number;
|
|
174
|
+
moonElevation: number;
|
|
175
|
+
hazeDensity: number;
|
|
176
|
+
hazeColor: number;
|
|
177
|
+
cloudsColor: number;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function sampleGradient(elevationDegrees: number): SkylabOutput {
|
|
181
|
+
const el = Math.max(-90, Math.min(90, elevationDegrees));
|
|
182
|
+
|
|
183
|
+
let lo = 0;
|
|
184
|
+
let hi = STOPS.length - 1;
|
|
185
|
+
for (let i = 0; i < STOPS.length - 1; i++) {
|
|
186
|
+
if (el >= STOPS[i].elevation && el <= STOPS[i + 1].elevation) {
|
|
187
|
+
lo = i;
|
|
188
|
+
hi = i + 1;
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (el <= STOPS[0].elevation) {
|
|
194
|
+
lo = 0;
|
|
195
|
+
hi = 0;
|
|
196
|
+
} else if (el >= STOPS[STOPS.length - 1].elevation) {
|
|
197
|
+
lo = STOPS.length - 1;
|
|
198
|
+
hi = STOPS.length - 1;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const a = STOPS[lo];
|
|
202
|
+
const b = STOPS[hi];
|
|
203
|
+
const range = b.elevation - a.elevation;
|
|
204
|
+
const t = range > 0 ? (el - a.elevation) / range : 0;
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
sunColor: packColor(lerpColor(a.sunColor, b.sunColor, t)),
|
|
208
|
+
sunIntensity: lerp(a.sunIntensity, b.sunIntensity, t),
|
|
209
|
+
ambientColor: packColor(lerpColor(a.ambientColor, b.ambientColor, t)),
|
|
210
|
+
ambientIntensity: lerp(a.ambientIntensity, b.ambientIntensity, t),
|
|
211
|
+
zenith: packColor(lerpColor(a.zenith, b.zenith, t)),
|
|
212
|
+
horizon: packColor(lerpColor(a.horizon, b.horizon, t)),
|
|
213
|
+
sunGlow: lerp(a.sunGlow, b.sunGlow, t),
|
|
214
|
+
starsIntensity: lerp(a.starsIntensity, b.starsIntensity, t),
|
|
215
|
+
moonGlow: lerp(a.moonGlow, b.moonGlow, t),
|
|
216
|
+
moonAzimuth: 0,
|
|
217
|
+
moonElevation: lerp(a.moonElevationOffset, b.moonElevationOffset, t),
|
|
218
|
+
hazeDensity: lerp(a.hazeDensity, b.hazeDensity, t),
|
|
219
|
+
hazeColor: packColor(lerpColor(a.hazeColor, b.hazeColor, t)),
|
|
220
|
+
cloudsColor: packColor(lerpColor(a.cloudsColor, b.cloudsColor, t)),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export function directionToElevation(dx: number, dy: number, dz: number): number {
|
|
225
|
+
const len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
226
|
+
if (len < 0.0001) return 90;
|
|
227
|
+
return Math.asin(Math.min(1, Math.max(-1, -dy / len))) * (180 / Math.PI);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function directionToAzimuth(dx: number, dy: number, dz: number): number {
|
|
231
|
+
const len = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
232
|
+
if (len < 0.0001) return 0;
|
|
233
|
+
return (Math.atan2(-dx / len, -dz / len) * (180 / Math.PI) + 360) % 360;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export function toDirection(azimuthDeg: number, elevationDeg: number): [number, number, number] {
|
|
237
|
+
const az = (azimuthDeg * Math.PI) / 180;
|
|
238
|
+
const el = (elevationDeg * Math.PI) / 180;
|
|
239
|
+
const cosEl = Math.cos(el);
|
|
240
|
+
return [-Math.sin(az) * cosEl, -Math.sin(el), -Math.cos(az) * cosEl];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function moonDirection(sunAzimuth: number, sunElevation: number): [number, number, number] {
|
|
244
|
+
const moonAz = (sunAzimuth + 180) % 360;
|
|
245
|
+
return toDirection(moonAz, Math.abs(sunElevation));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function lightDirection(azimuth: number, elevation: number): [number, number, number] {
|
|
249
|
+
if (elevation >= 0) return toDirection(azimuth, elevation);
|
|
250
|
+
if (elevation <= -6) return moonDirection(azimuth, elevation);
|
|
251
|
+
const t = -elevation / 6;
|
|
252
|
+
const [sx, sy, sz] = toDirection(azimuth, elevation);
|
|
253
|
+
const [mx, my, mz] = moonDirection(azimuth, elevation);
|
|
254
|
+
return [sx + (mx - sx) * t, sy + (my - sy) * t, sz + (mz - sz) * t];
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const SkylabSystem: System = {
|
|
258
|
+
group: "simulation",
|
|
259
|
+
|
|
260
|
+
update(state: State) {
|
|
261
|
+
for (const eid of state.query([Camera, Skylab])) {
|
|
262
|
+
if (!Camera.active[eid]) continue;
|
|
263
|
+
|
|
264
|
+
const azimuth = Skylab.azimuth[eid];
|
|
265
|
+
const elevation = Skylab.elevation[eid];
|
|
266
|
+
const [dirX, dirY, dirZ] = lightDirection(azimuth, elevation);
|
|
267
|
+
const output = sampleGradient(elevation);
|
|
268
|
+
|
|
269
|
+
for (const lightEid of state.query([DirectionalLight])) {
|
|
270
|
+
DirectionalLight.directionX[lightEid] = dirX;
|
|
271
|
+
DirectionalLight.directionY[lightEid] = dirY;
|
|
272
|
+
DirectionalLight.directionZ[lightEid] = dirZ;
|
|
273
|
+
DirectionalLight.color[lightEid] = output.sunColor;
|
|
274
|
+
DirectionalLight.intensity[lightEid] = output.sunIntensity;
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
for (const lightEid of state.query([AmbientLight])) {
|
|
279
|
+
AmbientLight.color[lightEid] = output.ambientColor;
|
|
280
|
+
AmbientLight.intensity[lightEid] = output.ambientIntensity;
|
|
281
|
+
break;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
if (!state.hasComponent(eid, Sky)) state.addComponent(eid, Sky);
|
|
285
|
+
Sky.zenith[eid] = output.zenith;
|
|
286
|
+
Sky.horizon[eid] = output.horizon;
|
|
287
|
+
|
|
288
|
+
if (!state.hasComponent(eid, Sun)) state.addComponent(eid, Sun);
|
|
289
|
+
Sun.glow[eid] = output.sunGlow;
|
|
290
|
+
|
|
291
|
+
if (!state.hasComponent(eid, Stars)) state.addComponent(eid, Stars);
|
|
292
|
+
Stars.intensity[eid] = output.starsIntensity;
|
|
293
|
+
|
|
294
|
+
if (!state.hasComponent(eid, Moon)) state.addComponent(eid, Moon);
|
|
295
|
+
Moon.glow[eid] = output.moonGlow;
|
|
296
|
+
Moon.azimuth[eid] = (azimuth + 180) % 360;
|
|
297
|
+
Moon.elevation[eid] = Math.abs(elevation);
|
|
298
|
+
|
|
299
|
+
if (!state.hasComponent(eid, Haze)) state.addComponent(eid, Haze);
|
|
300
|
+
Haze.density[eid] = output.hazeDensity;
|
|
301
|
+
Haze.color[eid] = output.hazeColor;
|
|
302
|
+
|
|
303
|
+
if (!state.hasComponent(eid, Clouds)) state.addComponent(eid, Clouds);
|
|
304
|
+
Clouds.color[eid] = output.cloudsColor;
|
|
305
|
+
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
export const SkylabPlugin: Plugin = {
|
|
312
|
+
systems: [SkylabSystem],
|
|
313
|
+
components: { Skylab },
|
|
314
|
+
};
|