react-native-shine 0.0.0 → 0.2.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/LICENSE +20 -0
- package/README.md +35 -0
- package/lib/module/index.js +182 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/roots.js +16 -0
- package/lib/module/roots.js.map +1 -0
- package/lib/module/shaders/bindGroupLayouts.js +45 -0
- package/lib/module/shaders/bindGroupLayouts.js.map +1 -0
- package/lib/module/shaders/bindGroupUtils.js +45 -0
- package/lib/module/shaders/bindGroupUtils.js.map +1 -0
- package/lib/module/shaders/fragmentShaders/bloomFragment.js +66 -0
- package/lib/module/shaders/fragmentShaders/bloomFragment.js.map +1 -0
- package/lib/module/shaders/fragmentShaders/colorMaskFragment.js +28 -0
- package/lib/module/shaders/fragmentShaders/colorMaskFragment.js.map +1 -0
- package/lib/module/shaders/pipelineSetups.js +26 -0
- package/lib/module/shaders/pipelineSetups.js.map +1 -0
- package/lib/module/shaders/resourceManagement.js +19 -0
- package/lib/module/shaders/resourceManagement.js.map +1 -0
- package/lib/module/shaders/tgpuUtils.js +38 -0
- package/lib/module/shaders/tgpuUtils.js.map +1 -0
- package/lib/module/shaders/utils.js +65 -0
- package/lib/module/shaders/utils.js.map +1 -0
- package/lib/module/shaders/vertexShaders/mainVertex.js +35 -0
- package/lib/module/shaders/vertexShaders/mainVertex.js.map +1 -0
- package/lib/module/types/typeUtils.js +92 -0
- package/lib/module/types/typeUtils.js.map +1 -0
- package/lib/module/types/types.js +4 -0
- package/lib/module/types/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/index.d.ts +12 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/roots.d.ts +4 -0
- package/lib/typescript/src/roots.d.ts.map +1 -0
- package/lib/typescript/src/shaders/bindGroupLayouts.d.ts +57 -0
- package/lib/typescript/src/shaders/bindGroupLayouts.d.ts.map +1 -0
- package/lib/typescript/src/shaders/bindGroupUtils.d.ts +53 -0
- package/lib/typescript/src/shaders/bindGroupUtils.d.ts.map +1 -0
- package/lib/typescript/src/shaders/fragmentShaders/bloomFragment.d.ts +6 -0
- package/lib/typescript/src/shaders/fragmentShaders/bloomFragment.d.ts.map +1 -0
- package/lib/typescript/src/shaders/fragmentShaders/colorMaskFragment.d.ts +6 -0
- package/lib/typescript/src/shaders/fragmentShaders/colorMaskFragment.d.ts.map +1 -0
- package/lib/typescript/src/shaders/pipelineSetups.d.ts +7 -0
- package/lib/typescript/src/shaders/pipelineSetups.d.ts.map +1 -0
- package/lib/typescript/src/shaders/resourceManagement.d.ts +3 -0
- package/lib/typescript/src/shaders/resourceManagement.d.ts.map +1 -0
- package/lib/typescript/src/shaders/tgpuUtils.d.ts +6 -0
- package/lib/typescript/src/shaders/tgpuUtils.d.ts.map +1 -0
- package/lib/typescript/src/shaders/utils.d.ts +13 -0
- package/lib/typescript/src/shaders/utils.d.ts.map +1 -0
- package/lib/typescript/src/shaders/vertexShaders/mainVertex.d.ts +6 -0
- package/lib/typescript/src/shaders/vertexShaders/mainVertex.d.ts.map +1 -0
- package/lib/typescript/src/types/typeUtils.d.ts +16 -0
- package/lib/typescript/src/types/typeUtils.d.ts.map +1 -0
- package/lib/typescript/src/types/types.d.ts +33 -0
- package/lib/typescript/src/types/types.d.ts.map +1 -0
- package/package.json +158 -13
- package/src/index.tsx +289 -0
- package/src/roots.ts +16 -0
- package/src/shaders/bindGroupLayouts.ts +40 -0
- package/src/shaders/bindGroupUtils.ts +101 -0
- package/src/shaders/fragmentShaders/bloomFragment.ts +83 -0
- package/src/shaders/fragmentShaders/colorMaskFragment.ts +35 -0
- package/src/shaders/pipelineSetups.ts +33 -0
- package/src/shaders/resourceManagement.ts +22 -0
- package/src/shaders/tgpuUtils.ts +75 -0
- package/src/shaders/utils.ts +103 -0
- package/src/shaders/vertexShaders/mainVertex.ts +35 -0
- package/src/types/typeUtils.ts +122 -0
- package/src/types/types.ts +51 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import tgpu from 'typegpu';
|
|
2
|
+
import * as d from 'typegpu/data';
|
|
3
|
+
import * as std from 'typegpu/std';
|
|
4
|
+
import {
|
|
5
|
+
rotationValuesBindGroupLayout,
|
|
6
|
+
textureBindGroupLayout,
|
|
7
|
+
bloomOptionsBindGroupLayout,
|
|
8
|
+
colorMaskBindGroupLayout,
|
|
9
|
+
} from '../bindGroupLayouts';
|
|
10
|
+
import { bloomColorShift, hueShift, overlayChannels } from '../tgpuUtils';
|
|
11
|
+
|
|
12
|
+
const bloomFragment = tgpu['~unstable'].fragmentFn({
|
|
13
|
+
in: { uv: d.vec2f },
|
|
14
|
+
out: d.vec4f,
|
|
15
|
+
})((input) => {
|
|
16
|
+
const texcoord = d.vec2f(input.uv.x, 1.0 - input.uv.y);
|
|
17
|
+
const uv = d.vec2f(input.uv.x, 1.0 - input.uv.y);
|
|
18
|
+
const centeredCoords = std.sub(std.mul(uv, 2.0), 1); //-1 to 1
|
|
19
|
+
|
|
20
|
+
const rot = rotationValuesBindGroupLayout.$.vec;
|
|
21
|
+
const center = std.add(d.vec2f(0.0), d.vec2f(rot.x, rot.y));
|
|
22
|
+
|
|
23
|
+
const bloomOptions = bloomOptionsBindGroupLayout.$.bloomOptions;
|
|
24
|
+
const bloomIntensity = bloomOptions.bloomIntensity;
|
|
25
|
+
const glowPower = bloomOptions.glowPower;
|
|
26
|
+
const hueBlendPower = bloomOptions.hueBlendPower;
|
|
27
|
+
const hueShiftAngleMax = bloomOptions.hueShiftAngleMax;
|
|
28
|
+
const hueShiftAngleMin = bloomOptions.hueShiftAngleMin;
|
|
29
|
+
const lightIntensity = bloomOptions.lightIntensity;
|
|
30
|
+
|
|
31
|
+
const mask = colorMaskBindGroupLayout.$.mask;
|
|
32
|
+
const maskedColor = mask.baseColor;
|
|
33
|
+
const rgbToleranceRange = mask.rgbToleranceRange;
|
|
34
|
+
|
|
35
|
+
let color = std.textureSample(
|
|
36
|
+
textureBindGroupLayout.$.texture,
|
|
37
|
+
textureBindGroupLayout.$.sampler,
|
|
38
|
+
texcoord
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const maskedColorLower = std.sub(maskedColor, rgbToleranceRange.lower);
|
|
42
|
+
const maskedColorUpper = std.add(maskedColor, rgbToleranceRange.upper);
|
|
43
|
+
const upperCheck = std.all(std.le(color.xyz, maskedColorUpper));
|
|
44
|
+
const lowerCheck = std.all(std.ge(color.xyz, maskedColorLower));
|
|
45
|
+
if (upperCheck && lowerCheck) {
|
|
46
|
+
return color;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
//bloomIntensity
|
|
50
|
+
const dst = std.exp(-std.distance(center, centeredCoords));
|
|
51
|
+
const distToCenter = std.smoothstep(0.0, 1 / bloomIntensity, dst);
|
|
52
|
+
|
|
53
|
+
//glowPower
|
|
54
|
+
let glow = d.vec3f(distToCenter);
|
|
55
|
+
glow = std.mul(glow, glowPower * color.w);
|
|
56
|
+
|
|
57
|
+
//hueBlend
|
|
58
|
+
const hueBlend = (d.f32(hueBlendPower) * dst) / 10.0;
|
|
59
|
+
|
|
60
|
+
//lightIntensity
|
|
61
|
+
glow = std.add(glow, lightIntensity / 10.0);
|
|
62
|
+
let shiftedRGB = bloomColorShift(color.xyz, dst / (lightIntensity * 2));
|
|
63
|
+
|
|
64
|
+
//hueShiftAngleMin/Max
|
|
65
|
+
const hueShiftAngle = std.smoothstep(
|
|
66
|
+
hueShiftAngleMin,
|
|
67
|
+
hueShiftAngleMax,
|
|
68
|
+
distToCenter
|
|
69
|
+
);
|
|
70
|
+
const shiftedHue = hueShift(shiftedRGB, hueShiftAngle);
|
|
71
|
+
shiftedRGB = overlayChannels(shiftedRGB, shiftedHue);
|
|
72
|
+
|
|
73
|
+
color = d.vec4f(std.mix(color.xyz, shiftedRGB, hueBlend), color.w);
|
|
74
|
+
const baseColor = color;
|
|
75
|
+
const blendColor = glow;
|
|
76
|
+
|
|
77
|
+
const combined = overlayChannels(baseColor.xyz, blendColor);
|
|
78
|
+
color = d.vec4f(std.mix(color.xyz, combined, glow), color.w);
|
|
79
|
+
|
|
80
|
+
return color;
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
export default bloomFragment;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import tgpu from 'typegpu';
|
|
2
|
+
import * as d from 'typegpu/data';
|
|
3
|
+
import * as std from 'typegpu/std';
|
|
4
|
+
import {
|
|
5
|
+
textureBindGroupLayout,
|
|
6
|
+
colorMaskBindGroupLayout,
|
|
7
|
+
} from '../bindGroupLayouts';
|
|
8
|
+
|
|
9
|
+
const colorMaskFragment = tgpu['~unstable'].fragmentFn({
|
|
10
|
+
in: { uv: d.vec2f },
|
|
11
|
+
out: d.vec4f,
|
|
12
|
+
})((input) => {
|
|
13
|
+
const texcoord = d.vec2f(input.uv.x, 1.0 - input.uv.y);
|
|
14
|
+
|
|
15
|
+
const mask = colorMaskBindGroupLayout.$.mask;
|
|
16
|
+
const maskedColor = mask.baseColor;
|
|
17
|
+
const rgbToleranceRange = mask.rgbToleranceRange;
|
|
18
|
+
|
|
19
|
+
let color = std.textureSample(
|
|
20
|
+
textureBindGroupLayout.$.texture,
|
|
21
|
+
textureBindGroupLayout.$.sampler,
|
|
22
|
+
texcoord
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const maskedColorLower = std.sub(maskedColor, rgbToleranceRange.lower);
|
|
26
|
+
const maskedColorUpper = std.add(maskedColor, rgbToleranceRange.upper);
|
|
27
|
+
const upperCheck = std.all(std.le(color.xyz, maskedColorUpper));
|
|
28
|
+
const lowerCheck = std.all(std.ge(color.xyz, maskedColorLower));
|
|
29
|
+
if (upperCheck && lowerCheck) {
|
|
30
|
+
return color;
|
|
31
|
+
}
|
|
32
|
+
std.discard();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default colorMaskFragment;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { TgpuRenderPipeline } from 'typegpu';
|
|
2
|
+
import type { BindGroupPair } from '../types/types';
|
|
3
|
+
|
|
4
|
+
export const attachBindGroups = (
|
|
5
|
+
pipeline: TgpuRenderPipeline,
|
|
6
|
+
bindGroupPairs: BindGroupPair[]
|
|
7
|
+
) => {
|
|
8
|
+
for (const pair of bindGroupPairs) {
|
|
9
|
+
pipeline = pipeline.with(pair.layout, pair.group);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return pipeline;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const getDefaultTarget = (
|
|
16
|
+
presentationFormat: GPUTextureFormat
|
|
17
|
+
): GPUColorTargetState => {
|
|
18
|
+
return {
|
|
19
|
+
format: presentationFormat,
|
|
20
|
+
blend: {
|
|
21
|
+
color: {
|
|
22
|
+
srcFactor: 'src-alpha',
|
|
23
|
+
dstFactor: 'one-minus-src-alpha',
|
|
24
|
+
operation: 'add',
|
|
25
|
+
},
|
|
26
|
+
alpha: {
|
|
27
|
+
srcFactor: 'one',
|
|
28
|
+
dstFactor: 'one-minus-src-alpha',
|
|
29
|
+
operation: 'add',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Asset } from 'expo-asset';
|
|
2
|
+
|
|
3
|
+
const getBitmapFromURI = async (uri: string): Promise<ImageBitmap> => {
|
|
4
|
+
if (uriToBitmapMap.has(uri)) return uriToBitmapMap.get(uri)!;
|
|
5
|
+
console.log('bitmap not found in cache, fetching from URI');
|
|
6
|
+
|
|
7
|
+
const ast = Asset.fromURI(uri);
|
|
8
|
+
await ast.downloadAsync();
|
|
9
|
+
const fileURI = ast.localUri || ast.uri;
|
|
10
|
+
|
|
11
|
+
console.log('fetch completed, creating ImageBitmap');
|
|
12
|
+
const response = await fetch(fileURI);
|
|
13
|
+
const blob = await response.blob();
|
|
14
|
+
const imageBitmap = await createImageBitmap(blob);
|
|
15
|
+
|
|
16
|
+
uriToBitmapMap.set(uri, imageBitmap);
|
|
17
|
+
return imageBitmap;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const uriToBitmapMap = new Map<string, ImageBitmap>();
|
|
21
|
+
|
|
22
|
+
export default getBitmapFromURI;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import tgpu from 'typegpu';
|
|
2
|
+
import * as std from 'typegpu/std';
|
|
3
|
+
import * as d from 'typegpu/data';
|
|
4
|
+
|
|
5
|
+
export const hueShift = tgpu.fn(
|
|
6
|
+
[d.vec3f, d.f32],
|
|
7
|
+
d.vec3f
|
|
8
|
+
)((rgb, angle) => {
|
|
9
|
+
const yiqY = std.add(
|
|
10
|
+
std.mul(rgb.x, 0.299),
|
|
11
|
+
std.add(std.mul(rgb.y, 0.587), std.mul(rgb.z, 0.114))
|
|
12
|
+
);
|
|
13
|
+
const yiqI = std.add(
|
|
14
|
+
std.mul(rgb.x, 0.596),
|
|
15
|
+
std.sub(std.mul(rgb.y, -0.274), std.mul(rgb.z, 0.322))
|
|
16
|
+
);
|
|
17
|
+
const yiqQ = std.add(
|
|
18
|
+
std.mul(rgb.x, 0.211),
|
|
19
|
+
std.sub(std.mul(rgb.y, -0.523), std.mul(rgb.z, 0.311))
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// Rotate hue
|
|
23
|
+
const cosA = std.cos(angle);
|
|
24
|
+
const sinA = std.sin(angle);
|
|
25
|
+
const i = std.sub(std.mul(yiqI, cosA), std.mul(yiqQ, sinA));
|
|
26
|
+
const q = std.add(std.mul(yiqI, sinA), std.mul(yiqQ, cosA));
|
|
27
|
+
|
|
28
|
+
// Convert back to RGB
|
|
29
|
+
const r = std.add(std.add(yiqY, std.mul(i, 0.956)), std.mul(q, 0.621));
|
|
30
|
+
const g = std.add(std.add(yiqY, std.mul(i, -0.272)), std.mul(q, -0.647));
|
|
31
|
+
const b = std.add(std.add(yiqY, std.mul(i, -1.105)), std.mul(q, 1.702));
|
|
32
|
+
|
|
33
|
+
return d.vec3f(r, g, b);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const bloomColorShift = tgpu.fn(
|
|
37
|
+
[d.vec3f, d.f32],
|
|
38
|
+
d.vec3f
|
|
39
|
+
)((color, power) => {
|
|
40
|
+
const maxValue = std.max(std.max(color.x, color.y), color.z);
|
|
41
|
+
const scale = std.mix(
|
|
42
|
+
d.f32(1.0),
|
|
43
|
+
d.f32(1.0) / std.max(maxValue, d.f32(0.001)),
|
|
44
|
+
power
|
|
45
|
+
);
|
|
46
|
+
const boosted = std.mul(color, scale);
|
|
47
|
+
const saturated = std.mix(color, boosted, power);
|
|
48
|
+
|
|
49
|
+
return saturated;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const overlayChannel = tgpu.fn(
|
|
53
|
+
[d.f32, d.f32],
|
|
54
|
+
d.f32
|
|
55
|
+
)((base, blend) => {
|
|
56
|
+
const mult = std.mul(2.0, std.mul(base, blend));
|
|
57
|
+
|
|
58
|
+
const screen = std.sub(
|
|
59
|
+
1.0,
|
|
60
|
+
std.mul(2.0, std.mul(std.sub(1.0, base), std.sub(1.0, blend)))
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return std.select(screen, mult, base < d.f32(0.5));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
export const overlayChannels = tgpu.fn(
|
|
67
|
+
[d.vec3f, d.vec3f],
|
|
68
|
+
d.vec3f
|
|
69
|
+
)((base, blend) => {
|
|
70
|
+
return d.vec3f(
|
|
71
|
+
overlayChannel(base.x, blend.x),
|
|
72
|
+
overlayChannel(base.y, blend.y),
|
|
73
|
+
overlayChannel(base.z, blend.z)
|
|
74
|
+
);
|
|
75
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { type TgpuRoot, type TgpuTexture } from 'typegpu';
|
|
2
|
+
import type { quaternion, vec3 } from '../types/types';
|
|
3
|
+
import { Dimensions } from 'react-native';
|
|
4
|
+
|
|
5
|
+
export const createTexture = async (
|
|
6
|
+
root: TgpuRoot,
|
|
7
|
+
size: {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
}
|
|
11
|
+
): Promise<TgpuTexture> => {
|
|
12
|
+
const texture = root['~unstable']
|
|
13
|
+
.createTexture({
|
|
14
|
+
size: [size.width, size.height],
|
|
15
|
+
format: 'rgba8unorm',
|
|
16
|
+
})
|
|
17
|
+
.$usage('sampled', 'render');
|
|
18
|
+
|
|
19
|
+
return texture;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const loadTexture = async (
|
|
23
|
+
root: TgpuRoot,
|
|
24
|
+
imageBitmap: ImageBitmap,
|
|
25
|
+
texture: TgpuTexture
|
|
26
|
+
) => {
|
|
27
|
+
root.device.queue.copyExternalImageToTexture(
|
|
28
|
+
{ source: imageBitmap },
|
|
29
|
+
{ texture: root.unwrap(texture) },
|
|
30
|
+
[imageBitmap.width, imageBitmap.height]
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const rotateVectorByQuaternion = (
|
|
35
|
+
vec: vec3,
|
|
36
|
+
quaternion: quaternion
|
|
37
|
+
): vec3 => {
|
|
38
|
+
'worklet';
|
|
39
|
+
const t: vec3 = [
|
|
40
|
+
quaternion[1] * vec[2] - quaternion[2] * vec[1],
|
|
41
|
+
quaternion[2] * vec[0] - quaternion[0] * vec[2],
|
|
42
|
+
quaternion[0] * vec[1] - quaternion[1] * vec[0],
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
// t2 = qw * forward + t
|
|
46
|
+
const t2: vec3 = [
|
|
47
|
+
quaternion[3] * vec[0] + t[0],
|
|
48
|
+
quaternion[3] * vec[1] + t[1],
|
|
49
|
+
quaternion[3] * vec[2] + t[2],
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const crossQT2: vec3 = [
|
|
53
|
+
quaternion[1] * t2[2] - quaternion[2] * t2[1],
|
|
54
|
+
quaternion[2] * t2[0] - quaternion[0] * t2[2],
|
|
55
|
+
quaternion[0] * t2[1] - quaternion[1] * t2[0],
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
// rotated = vec + 2.0 * cross(q, t2)
|
|
59
|
+
const rotated: vec3 = [
|
|
60
|
+
vec[0] + 2.0 * crossQT2[0],
|
|
61
|
+
vec[1] + 2.0 * crossQT2[1],
|
|
62
|
+
vec[2] + 2.0 * crossQT2[2],
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
return [rotated[0], rotated[1], rotated[2]];
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const clamp = (v: number, min = -1, max = 1) => {
|
|
69
|
+
'worklet';
|
|
70
|
+
return Math.max(min, Math.min(max, v));
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const rotate2D = (
|
|
74
|
+
[x, y]: [number, number],
|
|
75
|
+
angleDeg: number
|
|
76
|
+
): [number, number] => {
|
|
77
|
+
'worklet';
|
|
78
|
+
const rad = (angleDeg * Math.PI) / 180;
|
|
79
|
+
const c = Math.cos(rad);
|
|
80
|
+
const s = Math.sin(rad);
|
|
81
|
+
return [x * c - y * s, x * s + y * c];
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// Simple helper to get angle from dimensions (0 or 90)
|
|
85
|
+
export function getAngleFromDimensions() {
|
|
86
|
+
const { width, height } = Dimensions.get('window');
|
|
87
|
+
return width >= height ? 90 : 0;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Subscribe to orientation change via Dimensions API only
|
|
91
|
+
export function subscribeToOrientationChange(
|
|
92
|
+
callback: (angleDeg: number) => void
|
|
93
|
+
) {
|
|
94
|
+
callback(getAngleFromDimensions());
|
|
95
|
+
const handler = () => {
|
|
96
|
+
callback(getAngleFromDimensions());
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const dimSub = Dimensions.addEventListener('change', handler);
|
|
100
|
+
return () => {
|
|
101
|
+
dimSub.remove();
|
|
102
|
+
};
|
|
103
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import tgpu from 'typegpu';
|
|
2
|
+
import * as d from 'typegpu/data';
|
|
3
|
+
|
|
4
|
+
const mainVertex = tgpu['~unstable'].vertexFn({
|
|
5
|
+
in: { vertexIndex: d.builtin.vertexIndex },
|
|
6
|
+
out: { position: d.builtin.position, uv: d.vec2f },
|
|
7
|
+
})((input) => {
|
|
8
|
+
const position: d.v2f[] = [
|
|
9
|
+
d.vec2f(-1.0, -1.0), // bottom left
|
|
10
|
+
d.vec2f(1.0, 1.0), // top right
|
|
11
|
+
d.vec2f(1.0, -1.0), // bottom right
|
|
12
|
+
d.vec2f(-1.0, -1.0), // bottom left
|
|
13
|
+
d.vec2f(-1.0, 1.0), // top left
|
|
14
|
+
d.vec2f(1.0, 1.0), // top right
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const uv: d.v2f[] = [
|
|
18
|
+
d.vec2f(0.0, 0.0),
|
|
19
|
+
d.vec2f(1.0, 1.0),
|
|
20
|
+
d.vec2f(1.0, 0.0),
|
|
21
|
+
d.vec2f(0.0, 0.0),
|
|
22
|
+
d.vec2f(0.0, 1.0),
|
|
23
|
+
d.vec2f(1.0, 1.0),
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const index = input.vertexIndex;
|
|
27
|
+
const pos = position[index] as d.v2f;
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
position: d.vec4f(pos.xy, 0.0, 1.0),
|
|
31
|
+
uv: uv[index] as d.v2f,
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export default mainVertex;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { f32, vec2f, vec3f, vec4f } from 'typegpu/data';
|
|
2
|
+
import type {
|
|
3
|
+
BindGroupPair,
|
|
4
|
+
BloomOptions,
|
|
5
|
+
ColorMask,
|
|
6
|
+
DeepPartiallyOptional,
|
|
7
|
+
vec3,
|
|
8
|
+
} from './types';
|
|
9
|
+
import { div } from 'typegpu/std';
|
|
10
|
+
import type { TgpuBindGroup, TgpuBindGroupLayout } from 'typegpu';
|
|
11
|
+
|
|
12
|
+
export const createBloomOptions = (
|
|
13
|
+
options: Partial<BloomOptions>
|
|
14
|
+
): BloomOptions => {
|
|
15
|
+
const {
|
|
16
|
+
glowPower,
|
|
17
|
+
hueShiftAngleMax,
|
|
18
|
+
hueShiftAngleMin,
|
|
19
|
+
hueBlendPower,
|
|
20
|
+
lightIntensity,
|
|
21
|
+
bloomIntensity,
|
|
22
|
+
} = options;
|
|
23
|
+
|
|
24
|
+
const bloomOp = {
|
|
25
|
+
glowPower: glowPower ?? 1.0,
|
|
26
|
+
hueShiftAngleMax: hueShiftAngleMax ?? 1.0,
|
|
27
|
+
hueShiftAngleMin: hueShiftAngleMin ?? 0.0,
|
|
28
|
+
hueBlendPower: hueBlendPower ?? 1.0,
|
|
29
|
+
lightIntensity: lightIntensity ?? 1.0,
|
|
30
|
+
bloomIntensity: bloomIntensity ?? 1.0,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return bloomOp;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const mapToF32 = <T extends Record<string, number>>(
|
|
37
|
+
obj: T
|
|
38
|
+
): {
|
|
39
|
+
[K in keyof T]: ReturnType<typeof f32>;
|
|
40
|
+
} => {
|
|
41
|
+
const result = {} as any;
|
|
42
|
+
for (const key in obj) {
|
|
43
|
+
result[key] = f32(obj[key]);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const createColorMask = (
|
|
50
|
+
colorMask: DeepPartiallyOptional<ColorMask, 'baseColor'>
|
|
51
|
+
): ColorMask => {
|
|
52
|
+
const { baseColor, rgbToleranceRange } = colorMask;
|
|
53
|
+
const baseTolerance = {
|
|
54
|
+
upper: [20, 20, 20] as vec3,
|
|
55
|
+
lower: [20, 20, 20] as vec3,
|
|
56
|
+
};
|
|
57
|
+
const tolerance = { ...baseTolerance, ...rgbToleranceRange };
|
|
58
|
+
|
|
59
|
+
const mask: ColorMask = {
|
|
60
|
+
baseColor: baseColor,
|
|
61
|
+
rgbToleranceRange: tolerance,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return mask;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const colorMaskToTyped = (colorMask: ColorMask) => {
|
|
68
|
+
const result = {
|
|
69
|
+
baseColor: div(numberArrToTyped(colorMask.baseColor), 255),
|
|
70
|
+
rgbToleranceRange: {
|
|
71
|
+
upper: div(numberArrToTyped(colorMask.rgbToleranceRange.upper), 255),
|
|
72
|
+
lower: div(numberArrToTyped(colorMask.rgbToleranceRange.lower), 255),
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
return result;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const numberArrToTyped = (vec: number[]) => {
|
|
79
|
+
let convFn: ((...args: number[]) => any) | null = null;
|
|
80
|
+
switch (vec.length) {
|
|
81
|
+
case 2:
|
|
82
|
+
convFn = vec2f;
|
|
83
|
+
break;
|
|
84
|
+
case 3:
|
|
85
|
+
convFn = vec3f;
|
|
86
|
+
break;
|
|
87
|
+
case 4:
|
|
88
|
+
convFn = vec4f;
|
|
89
|
+
break;
|
|
90
|
+
default:
|
|
91
|
+
throw new Error('numberArrToTyped: Vector must be of length [2-4]');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const typed = convFn(...vec);
|
|
95
|
+
return typed;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const createBindGroupPair = (
|
|
99
|
+
bindGroupLayout: TgpuBindGroupLayout,
|
|
100
|
+
bindGroup: TgpuBindGroup
|
|
101
|
+
): BindGroupPair => {
|
|
102
|
+
return { layout: bindGroupLayout, group: bindGroup };
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const createBindGroupPairs = (
|
|
106
|
+
bindGroupLayouts: TgpuBindGroupLayout[],
|
|
107
|
+
bindGroups: TgpuBindGroup[]
|
|
108
|
+
): BindGroupPair[] => {
|
|
109
|
+
if (
|
|
110
|
+
bindGroupLayouts.length > 0 &&
|
|
111
|
+
bindGroupLayouts.length !== bindGroups.length
|
|
112
|
+
)
|
|
113
|
+
throw new Error(
|
|
114
|
+
'createBindGroups: bindGroupLayout and bindGroup arrrays must be of the same length'
|
|
115
|
+
);
|
|
116
|
+
const pairs: BindGroupPair[] = [];
|
|
117
|
+
for (let i = 0; i < bindGroupLayouts.length; i++) {
|
|
118
|
+
pairs.push(createBindGroupPair(bindGroupLayouts[i]!, bindGroups[i]!));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return pairs;
|
|
122
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { TgpuBindGroup, TgpuBindGroupLayout } from 'typegpu';
|
|
2
|
+
|
|
3
|
+
export type vec2 = [number, number];
|
|
4
|
+
export type vec3 = [number, number, number];
|
|
5
|
+
export type vec4 = [number, number, number, number];
|
|
6
|
+
export type quaternion = vec4;
|
|
7
|
+
|
|
8
|
+
export type BloomOptions = {
|
|
9
|
+
glowPower: number;
|
|
10
|
+
hueShiftAngleMax: number;
|
|
11
|
+
hueShiftAngleMin: number;
|
|
12
|
+
hueBlendPower: number;
|
|
13
|
+
lightIntensity: number;
|
|
14
|
+
bloomIntensity: number;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type ColorMask = {
|
|
18
|
+
baseColor: vec3;
|
|
19
|
+
rgbToleranceRange: {
|
|
20
|
+
upper: vec3;
|
|
21
|
+
lower: vec3;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
//makes all keys besides specified optional
|
|
26
|
+
export type PartiallyOptional<T, K extends keyof T> = {
|
|
27
|
+
[P in K]: T[P];
|
|
28
|
+
} & Partial<Omit<T, K>>;
|
|
29
|
+
|
|
30
|
+
export type Primitive =
|
|
31
|
+
| string
|
|
32
|
+
| number
|
|
33
|
+
| boolean
|
|
34
|
+
| bigint
|
|
35
|
+
| symbol
|
|
36
|
+
| null
|
|
37
|
+
| undefined;
|
|
38
|
+
|
|
39
|
+
//makes every object and its' properties optional
|
|
40
|
+
//unless the objects are contained in any kind of array
|
|
41
|
+
export type DeepPartial<T> = {
|
|
42
|
+
[P in keyof T]?: T[P] extends Primitive | any[] ? T[P] : DeepPartial<T[P]>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type DeepPartiallyOptional<T, K extends keyof T> = Required<Pick<T, K>> &
|
|
46
|
+
DeepPartial<Omit<T, K>>;
|
|
47
|
+
|
|
48
|
+
export type BindGroupPair = {
|
|
49
|
+
layout: TgpuBindGroupLayout;
|
|
50
|
+
group: TgpuBindGroup;
|
|
51
|
+
};
|