@footgun/cobalt 0.9.0 → 0.10.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/CHANGELOG.md +9 -0
- package/bundle.js +91 -117
- package/examples/03-tiles/index.html +3 -104
- package/examples/06-displacement/index.html +2 -2
- package/examples/08-light/index.html +70 -10
- package/package.json +1 -1
- package/src/bloom/bloom.js +10 -7
- package/src/displacement/displacement.js +6 -10
- package/src/fb-blit/fb-blit.js +5 -4
- package/src/fb-texture/fb-texture.js +1 -2
- package/src/light/light.js +504 -69
- package/src/light/lights-buffer.js +55 -59
- package/src/light/public-api.js +3 -4
- package/src/light/texture/lights-texture-mask.js +187 -167
- package/src/primitives/primitives.js +4 -1
- package/src/scene-composite/scene-composite.js +8 -11
- package/src/sprite/public-api.js +5 -3
- package/src/sprite/sprite.js +6 -10
- package/src/sprite-hdr/public-api.js +5 -3
- package/src/sprite-hdr/sprite.js +6 -15
- package/src/spritesheet/spritesheet.js +0 -1
- package/src/tile-hdr/atlas.js +0 -1
- package/src/tile-hdr/tile.js +7 -6
- package/src/light/lights-renderer.js +0 -230
- package/src/light/texture/lights-texture-initializer.js +0 -175
- package/src/light/texture/lights-texture.js +0 -85
- package/src/light/viewport.js +0 -40
package/src/tile-hdr/atlas.js
CHANGED
|
@@ -9,7 +9,6 @@ const _buf = new Float32Array(8) //(136) // tile instance data stored in a UBO
|
|
|
9
9
|
// shared tile atlas resource, used by each tile render node
|
|
10
10
|
export default {
|
|
11
11
|
type: 'cobalt:tileAtlas',
|
|
12
|
-
refs: [],
|
|
13
12
|
|
|
14
13
|
// @params Object cobalt renderer world object
|
|
15
14
|
// @params Object options optional data passed when initing this node
|
package/src/tile-hdr/tile.js
CHANGED
|
@@ -15,12 +15,13 @@ Because this processing can happen completely in the fragment shader, there's no
|
|
|
15
15
|
Inspired by/ported from https://blog.tojicode.com/2012/07/sprite-tile-maps-on-gpu.html
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Refs:
|
|
20
|
+
* tileAtlas (textureView, rgba8unorm, read) - tile atlas texture
|
|
21
|
+
* out (textureView, rgba16float, write) - render target
|
|
22
|
+
*/
|
|
18
23
|
export default {
|
|
19
24
|
type: 'cobalt:tileHDR',
|
|
20
|
-
refs: [
|
|
21
|
-
{ name: 'tileAtlas', type: 'textureView', format: 'rgba8unorm', access: 'read' },
|
|
22
|
-
{ name: 'hdr', type: 'textureView', format: 'rgba16float', access: 'write' },
|
|
23
|
-
],
|
|
24
25
|
|
|
25
26
|
// @params Object cobalt renderer world object
|
|
26
27
|
// @params Object options optional data passed when initing this node
|
|
@@ -174,8 +175,8 @@ function draw(cobalt, nodeData, commandEncoder) {
|
|
|
174
175
|
label: 'tile',
|
|
175
176
|
colorAttachments: [
|
|
176
177
|
{
|
|
177
|
-
//
|
|
178
|
-
view: nodeData.refs.
|
|
178
|
+
// out is passsed as a node || FRAME_TEXTURE_VIEW
|
|
179
|
+
view: nodeData.refs.out.data?.view || nodeData.refs.out,
|
|
179
180
|
clearValue: cobalt.clearValue,
|
|
180
181
|
loadOp,
|
|
181
182
|
storeOp: 'store',
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
import { LightsBuffer } from "./lights-buffer.js";
|
|
2
|
-
import { LightsTexture } from "./texture/lights-texture.js";
|
|
3
|
-
|
|
4
|
-
class LightsRenderer {
|
|
5
|
-
device;
|
|
6
|
-
ambientLight = [0.2, 0.2, 0.2];
|
|
7
|
-
targetTexture;
|
|
8
|
-
renderPipeline;
|
|
9
|
-
uniformsBufferGpu;
|
|
10
|
-
bindgroup0;
|
|
11
|
-
bindgroup1;
|
|
12
|
-
renderBundle;
|
|
13
|
-
lightsBuffer;
|
|
14
|
-
lightsTexture;
|
|
15
|
-
constructor(params) {
|
|
16
|
-
this.device = params.device;
|
|
17
|
-
this.targetTexture = params.targetTexture;
|
|
18
|
-
this.lightsBuffer = params.lightsBuffer;
|
|
19
|
-
this.lightsTexture = new LightsTexture(params.device, params.lightsBuffer, params.lightsTextureProperties);
|
|
20
|
-
this.uniformsBufferGpu = params.device.createBuffer({
|
|
21
|
-
label: "LightsRenderer uniforms buffer",
|
|
22
|
-
size: 80,
|
|
23
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
24
|
-
});
|
|
25
|
-
const shaderModule = params.device.createShaderModule({
|
|
26
|
-
label: "LightsRenderer shader module",
|
|
27
|
-
code: `
|
|
28
|
-
struct Uniforms { // align(16) size(80)
|
|
29
|
-
invertViewMatrix: mat4x4<f32>, // offset(0) align(16) size(64)
|
|
30
|
-
ambientLight: vec3<f32>, // offset(64) align(16) size(12)
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
${LightsBuffer.structs.definition}
|
|
34
|
-
|
|
35
|
-
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
36
|
-
@group(0) @binding(1) var<storage,read> lightsBuffer: LightsBuffer;
|
|
37
|
-
@group(0) @binding(2) var lightsTexture: texture_2d<f32>;
|
|
38
|
-
@group(0) @binding(3) var lightsTextureSampler: sampler;
|
|
39
|
-
|
|
40
|
-
@group(1) @binding(0) var albedoTexture: texture_2d<f32>;
|
|
41
|
-
@group(1) @binding(1) var albedoSampler: sampler;
|
|
42
|
-
|
|
43
|
-
struct VertexIn {
|
|
44
|
-
@builtin(vertex_index) vertexIndex: u32,
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
struct VertexOut {
|
|
48
|
-
@builtin(position) position: vec4<f32>,
|
|
49
|
-
@location(0) worldPosition: vec2<f32>,
|
|
50
|
-
@location(1) uv: vec2<f32>,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
@vertex
|
|
54
|
-
fn main_vertex(in: VertexIn) -> VertexOut {
|
|
55
|
-
const corners = array<vec2<f32>, 4>(
|
|
56
|
-
vec2<f32>(-1, -1),
|
|
57
|
-
vec2<f32>(1, -1),
|
|
58
|
-
vec2<f32>(-1, 1),
|
|
59
|
-
vec2<f32>(1, 1),
|
|
60
|
-
);
|
|
61
|
-
let screenPosition = corners[in.vertexIndex];
|
|
62
|
-
|
|
63
|
-
var out: VertexOut;
|
|
64
|
-
out.position = vec4<f32>(screenPosition, 0.0, 1.0);
|
|
65
|
-
out.worldPosition = (uniforms.invertViewMatrix * out.position).xy;
|
|
66
|
-
out.uv = 0.5 + 0.5 * screenPosition * vec2<f32>(1.0, -1.0);
|
|
67
|
-
return out;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
struct FragmentOut {
|
|
71
|
-
@location(0) color: vec4<f32>,
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const cellsGridSizeU = vec2<u32>(${this.lightsTexture.gridSize.x}, ${this.lightsTexture.gridSize.y});
|
|
75
|
-
const cellsGridSizeF = vec2<f32>(${this.lightsTexture.gridSize.x}, ${this.lightsTexture.gridSize.y});
|
|
76
|
-
|
|
77
|
-
fn sampleLightBaseIntensity(lightId: u32, localUv: vec2<f32>) -> f32 {
|
|
78
|
-
let cellIndex = lightId / 4u;
|
|
79
|
-
let indexInCell = lightId % 4u;
|
|
80
|
-
|
|
81
|
-
let cellIdU = vec2<u32>(
|
|
82
|
-
cellIndex % cellsGridSizeU.x,
|
|
83
|
-
cellIndex / cellsGridSizeU.x,
|
|
84
|
-
);
|
|
85
|
-
let cellIdF = vec2<f32>(cellIdU);
|
|
86
|
-
let uv = (cellIdF + localUv) / cellsGridSizeF;
|
|
87
|
-
let uvYInverted = vec2<f32>(uv.x, 1.0 - uv.y);
|
|
88
|
-
let sample = textureSampleLevel(lightsTexture, lightsTextureSampler, uvYInverted, 0.0);
|
|
89
|
-
let channel = vec4<f32>(
|
|
90
|
-
vec4<u32>(indexInCell) == vec4<u32>(0u, 1u, 2u, 3u),
|
|
91
|
-
);
|
|
92
|
-
return dot(sample, channel);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
fn compute_lights(worldPosition: vec2<f32>) -> vec3<f32> {
|
|
96
|
-
var color = vec3<f32>(uniforms.ambientLight);
|
|
97
|
-
|
|
98
|
-
const maxUvDistance = f32(${1 - 2 / params.lightsTextureProperties.resolutionPerLight});
|
|
99
|
-
|
|
100
|
-
let lightsCount = lightsBuffer.count;
|
|
101
|
-
for (var iLight = 0u; iLight < lightsCount; iLight++) {
|
|
102
|
-
let light = lightsBuffer.lights[iLight];
|
|
103
|
-
let lightSize = f32(${params.lightsTextureProperties.resolutionPerLight});
|
|
104
|
-
let relativePosition = (worldPosition - light.position) / lightSize;
|
|
105
|
-
if (max(abs(relativePosition.x), abs(relativePosition.y)) < maxUvDistance) {
|
|
106
|
-
let localUv = 0.5 + 0.5 * relativePosition;
|
|
107
|
-
let lightIntensity = light.intensity * sampleLightBaseIntensity(iLight, localUv);
|
|
108
|
-
color += lightIntensity * light.color;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return color;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
@fragment
|
|
116
|
-
fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
117
|
-
let light = compute_lights(in.worldPosition);
|
|
118
|
-
let albedo = textureSample(albedoTexture, albedoSampler, in.uv);
|
|
119
|
-
let color = albedo.rgb * light;
|
|
120
|
-
|
|
121
|
-
var out: FragmentOut;
|
|
122
|
-
out.color = vec4<f32>(color, 1.0);
|
|
123
|
-
return out;
|
|
124
|
-
}
|
|
125
|
-
`,
|
|
126
|
-
});
|
|
127
|
-
this.renderPipeline = params.device.createRenderPipeline({
|
|
128
|
-
label: "LightsRenderer renderpipeline",
|
|
129
|
-
layout: "auto",
|
|
130
|
-
vertex: {
|
|
131
|
-
module: shaderModule,
|
|
132
|
-
entryPoint: "main_vertex",
|
|
133
|
-
},
|
|
134
|
-
fragment: {
|
|
135
|
-
module: shaderModule,
|
|
136
|
-
entryPoint: "main_fragment",
|
|
137
|
-
targets: [{
|
|
138
|
-
format: this.targetTexture.format,
|
|
139
|
-
}],
|
|
140
|
-
},
|
|
141
|
-
primitive: {
|
|
142
|
-
cullMode: "none",
|
|
143
|
-
topology: "triangle-strip",
|
|
144
|
-
},
|
|
145
|
-
});
|
|
146
|
-
const bindgroupLayout = this.renderPipeline.getBindGroupLayout(0);
|
|
147
|
-
this.bindgroup0 = params.device.createBindGroup({
|
|
148
|
-
label: "LightsRenderer bindgroup 0",
|
|
149
|
-
layout: bindgroupLayout,
|
|
150
|
-
entries: [
|
|
151
|
-
{
|
|
152
|
-
binding: 0,
|
|
153
|
-
resource: { buffer: this.uniformsBufferGpu },
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
binding: 1,
|
|
157
|
-
resource: { buffer: this.lightsBuffer.gpuBuffer },
|
|
158
|
-
},
|
|
159
|
-
{
|
|
160
|
-
binding: 2,
|
|
161
|
-
resource: this.lightsTexture.texture.createView({ label: "LightsRenderer lightsTexture view" }),
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
binding: 3,
|
|
165
|
-
resource: params.device.createSampler({
|
|
166
|
-
label: "LightsRenderer sampler",
|
|
167
|
-
addressModeU: "clamp-to-edge",
|
|
168
|
-
addressModeV: "clamp-to-edge",
|
|
169
|
-
magFilter: params.lightsTextureProperties.filtering,
|
|
170
|
-
minFilter: params.lightsTextureProperties.filtering,
|
|
171
|
-
}),
|
|
172
|
-
},
|
|
173
|
-
]
|
|
174
|
-
});
|
|
175
|
-
this.bindgroup1 = this.buildBindgroup1(params.albedo);
|
|
176
|
-
this.renderBundle = this.buildRenderBundle();
|
|
177
|
-
}
|
|
178
|
-
computeLightsTexture(commandEncoder) {
|
|
179
|
-
this.lightsTexture.update(commandEncoder);
|
|
180
|
-
}
|
|
181
|
-
render(renderpassEncoder, invertVpMatrix) {
|
|
182
|
-
const uniformsBufferCpu = new ArrayBuffer(80);
|
|
183
|
-
new Float32Array(uniformsBufferCpu, 0, 16).set(invertVpMatrix);
|
|
184
|
-
new Float32Array(uniformsBufferCpu, 64, 3).set(this.ambientLight);
|
|
185
|
-
this.device.queue.writeBuffer(this.uniformsBufferGpu, 0, uniformsBufferCpu);
|
|
186
|
-
renderpassEncoder.executeBundles([this.renderBundle]);
|
|
187
|
-
}
|
|
188
|
-
setAlbedo(albedo) {
|
|
189
|
-
this.bindgroup1 = this.buildBindgroup1(albedo);
|
|
190
|
-
this.renderBundle = this.buildRenderBundle();
|
|
191
|
-
}
|
|
192
|
-
setAmbientLight(color) {
|
|
193
|
-
this.ambientLight = [...color];
|
|
194
|
-
}
|
|
195
|
-
setObstacles(segments) {
|
|
196
|
-
this.lightsTexture.setObstacles(segments);
|
|
197
|
-
}
|
|
198
|
-
destroy() {
|
|
199
|
-
this.uniformsBufferGpu.destroy();
|
|
200
|
-
this.lightsTexture.destroy();
|
|
201
|
-
}
|
|
202
|
-
buildBindgroup1(albedo) {
|
|
203
|
-
return this.device.createBindGroup({
|
|
204
|
-
label: "LightsRenderer bindgroup 1",
|
|
205
|
-
layout: this.renderPipeline.getBindGroupLayout(1),
|
|
206
|
-
entries: [
|
|
207
|
-
{
|
|
208
|
-
binding: 0,
|
|
209
|
-
resource: albedo.view,
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
binding: 1,
|
|
213
|
-
resource: albedo.sampler,
|
|
214
|
-
},
|
|
215
|
-
]
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
buildRenderBundle() {
|
|
219
|
-
const renderBundleEncoder = this.device.createRenderBundleEncoder({
|
|
220
|
-
label: "LightsRenderer renderbundle encoder",
|
|
221
|
-
colorFormats: [this.targetTexture.format],
|
|
222
|
-
});
|
|
223
|
-
renderBundleEncoder.setPipeline(this.renderPipeline);
|
|
224
|
-
renderBundleEncoder.setBindGroup(0, this.bindgroup0);
|
|
225
|
-
renderBundleEncoder.setBindGroup(1, this.bindgroup1);
|
|
226
|
-
renderBundleEncoder.draw(4);
|
|
227
|
-
return renderBundleEncoder.finish({ label: "LightsRenderer renderbundle" });
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
export { LightsRenderer };
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { LightsBuffer } from "../lights-buffer.js";
|
|
2
|
-
|
|
3
|
-
class LightsTextureInitializer {
|
|
4
|
-
lightsBuffer;
|
|
5
|
-
renderPipeline;
|
|
6
|
-
bindgroup;
|
|
7
|
-
renderBundle;
|
|
8
|
-
constructor(device, lightsBuffer, lightsTexture, maxLightSize) {
|
|
9
|
-
this.lightsBuffer = lightsBuffer;
|
|
10
|
-
const shaderModule = device.createShaderModule({
|
|
11
|
-
label: "LightsTextureInitializer shader module",
|
|
12
|
-
code: `
|
|
13
|
-
${LightsBuffer.structs.definition}
|
|
14
|
-
|
|
15
|
-
@group(0) @binding(0) var<storage,read> lightsBuffer: LightsBuffer;
|
|
16
|
-
|
|
17
|
-
struct VertexIn {
|
|
18
|
-
@builtin(vertex_index) vertexIndex: u32,
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
struct VertexOut {
|
|
22
|
-
@builtin(position) position: vec4<f32>,
|
|
23
|
-
@location(0) uv: vec2<f32>,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const cellsGridSizeU = vec2<u32>(${lightsTexture.gridSize.x}, ${lightsTexture.gridSize.y});
|
|
27
|
-
const cellsGridSizeF = vec2<f32>(${lightsTexture.gridSize.x}, ${lightsTexture.gridSize.y});
|
|
28
|
-
|
|
29
|
-
@vertex
|
|
30
|
-
fn main_vertex(in: VertexIn) -> VertexOut {
|
|
31
|
-
const corners = array<vec2<f32>, 4>(
|
|
32
|
-
vec2<f32>(-1, -1),
|
|
33
|
-
vec2<f32>(1, -1),
|
|
34
|
-
vec2<f32>(-1, 1),
|
|
35
|
-
vec2<f32>(1, 1),
|
|
36
|
-
);
|
|
37
|
-
let screenPosition = corners[in.vertexIndex];
|
|
38
|
-
|
|
39
|
-
var out: VertexOut;
|
|
40
|
-
out.position = vec4<f32>(screenPosition, 0.0, 1.0);
|
|
41
|
-
out.uv = (0.5 + 0.5 * screenPosition) * cellsGridSizeF;
|
|
42
|
-
return out;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
struct FragmentOut {
|
|
46
|
-
@location(0) color: vec4<f32>,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
struct LightProperties {
|
|
50
|
-
radius: f32,
|
|
51
|
-
intensity: f32,
|
|
52
|
-
attenuationLinear: f32,
|
|
53
|
-
attenuationExp: f32,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
fn get_light_properties(lightId: u32) -> LightProperties {
|
|
57
|
-
var lightProperties: LightProperties;
|
|
58
|
-
if (lightId < lightsBuffer.count) {
|
|
59
|
-
let light = lightsBuffer.lights[lightId];
|
|
60
|
-
lightProperties.radius = light.radius;
|
|
61
|
-
lightProperties.intensity = 1.0;
|
|
62
|
-
lightProperties.attenuationLinear = light.attenuationLinear;
|
|
63
|
-
lightProperties.attenuationExp = light.attenuationExp;
|
|
64
|
-
} else {
|
|
65
|
-
lightProperties.radius = 0.0;
|
|
66
|
-
lightProperties.intensity = 0.0;
|
|
67
|
-
lightProperties.attenuationLinear = 0.0;
|
|
68
|
-
lightProperties.attenuationExp = 0.0;
|
|
69
|
-
}
|
|
70
|
-
return lightProperties;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
@fragment
|
|
74
|
-
fn main_fragment(in: VertexOut) -> FragmentOut {
|
|
75
|
-
let cellId = vec2<u32>(in.uv);
|
|
76
|
-
|
|
77
|
-
let lightIdFrom = 4u * (cellId.x + cellId.y * cellsGridSizeU.x);
|
|
78
|
-
let lightProperties = array<LightProperties, 4>(
|
|
79
|
-
get_light_properties(lightIdFrom + 0u),
|
|
80
|
-
get_light_properties(lightIdFrom + 1u),
|
|
81
|
-
get_light_properties(lightIdFrom + 2u),
|
|
82
|
-
get_light_properties(lightIdFrom + 3u),
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
let sizes = vec4<f32>(
|
|
86
|
-
lightProperties[0].radius,
|
|
87
|
-
lightProperties[1].radius,
|
|
88
|
-
lightProperties[2].radius,
|
|
89
|
-
lightProperties[3].radius,
|
|
90
|
-
);
|
|
91
|
-
|
|
92
|
-
let localUv = fract(in.uv);
|
|
93
|
-
let fromCenter = 2.0 * localUv - 1.0;
|
|
94
|
-
let uvDistanceFromCenter = distance(vec2<f32>(0,0), fromCenter);
|
|
95
|
-
let distancesFromCenter = vec4<f32>(uvDistanceFromCenter / sizes * f32(${maxLightSize}));
|
|
96
|
-
|
|
97
|
-
let intensities = vec4<f32>(
|
|
98
|
-
lightProperties[0].intensity * (1.0 + 1.0 * step(uvDistanceFromCenter, 0.01)),
|
|
99
|
-
lightProperties[1].intensity * (1.0 + 1.0 * step(uvDistanceFromCenter, 0.01)),
|
|
100
|
-
lightProperties[2].intensity * (1.0 + 1.0 * step(uvDistanceFromCenter, 0.01)),
|
|
101
|
-
lightProperties[3].intensity * (1.0 + 1.0 * step(uvDistanceFromCenter, 0.01)),
|
|
102
|
-
);
|
|
103
|
-
let attenuationsLinear = vec4<f32>(
|
|
104
|
-
lightProperties[0].attenuationLinear,
|
|
105
|
-
lightProperties[1].attenuationLinear,
|
|
106
|
-
lightProperties[2].attenuationLinear,
|
|
107
|
-
lightProperties[3].attenuationLinear,
|
|
108
|
-
);
|
|
109
|
-
let attenuationsExp = vec4<f32>(
|
|
110
|
-
lightProperties[0].attenuationExp,
|
|
111
|
-
lightProperties[1].attenuationExp,
|
|
112
|
-
lightProperties[2].attenuationExp,
|
|
113
|
-
lightProperties[3].attenuationExp,
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
var lightIntensities = intensities / (1.0 + distancesFromCenter * (attenuationsLinear + distancesFromCenter * attenuationsExp)); // base intensity equation
|
|
117
|
-
lightIntensities *= cos(distancesFromCenter * ${Math.PI / 2}); // soft limit;
|
|
118
|
-
lightIntensities *= step(distancesFromCenter, vec4<f32>(1.0)); // hard limit
|
|
119
|
-
|
|
120
|
-
var out: FragmentOut;
|
|
121
|
-
out.color = lightIntensities;
|
|
122
|
-
return out;
|
|
123
|
-
}
|
|
124
|
-
`,
|
|
125
|
-
});
|
|
126
|
-
this.renderPipeline = device.createRenderPipeline({
|
|
127
|
-
label: "LightsTextureInitializer renderpipeline",
|
|
128
|
-
layout: "auto",
|
|
129
|
-
vertex: {
|
|
130
|
-
module: shaderModule,
|
|
131
|
-
entryPoint: "main_vertex",
|
|
132
|
-
},
|
|
133
|
-
fragment: {
|
|
134
|
-
module: shaderModule,
|
|
135
|
-
entryPoint: "main_fragment",
|
|
136
|
-
targets: [{
|
|
137
|
-
format: lightsTexture.format,
|
|
138
|
-
}],
|
|
139
|
-
},
|
|
140
|
-
primitive: {
|
|
141
|
-
cullMode: "none",
|
|
142
|
-
topology: "triangle-strip",
|
|
143
|
-
},
|
|
144
|
-
multisample: {
|
|
145
|
-
count: lightsTexture.sampleCount,
|
|
146
|
-
},
|
|
147
|
-
});
|
|
148
|
-
this.bindgroup = device.createBindGroup({
|
|
149
|
-
label: "LightsTextureInitializer bindgroup 0",
|
|
150
|
-
layout: this.renderPipeline.getBindGroupLayout(0),
|
|
151
|
-
entries: [
|
|
152
|
-
{
|
|
153
|
-
binding: 0,
|
|
154
|
-
resource: { buffer: this.lightsBuffer.gpuBuffer },
|
|
155
|
-
},
|
|
156
|
-
]
|
|
157
|
-
});
|
|
158
|
-
const renderBundleEncoder = device.createRenderBundleEncoder({
|
|
159
|
-
label: "LightsTextureInitializer renderbundle encoder",
|
|
160
|
-
colorFormats: [lightsTexture.format],
|
|
161
|
-
sampleCount: lightsTexture.sampleCount,
|
|
162
|
-
});
|
|
163
|
-
renderBundleEncoder.setPipeline(this.renderPipeline);
|
|
164
|
-
renderBundleEncoder.setBindGroup(0, this.bindgroup);
|
|
165
|
-
renderBundleEncoder.draw(4);
|
|
166
|
-
this.renderBundle = renderBundleEncoder.finish({ label: "LightsTextureInitializer renderbundle" });
|
|
167
|
-
}
|
|
168
|
-
getRenderBundle() {
|
|
169
|
-
return this.renderBundle;
|
|
170
|
-
}
|
|
171
|
-
destroy() {
|
|
172
|
-
// nothing to do
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
export { LightsTextureInitializer };
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { LightsTextureInitializer } from "./lights-texture-initializer.js";
|
|
2
|
-
import { LightsTextureMask } from "./lights-texture-mask.js";
|
|
3
|
-
|
|
4
|
-
class LightsTexture {
|
|
5
|
-
lightsBuffer;
|
|
6
|
-
texture;
|
|
7
|
-
gridSize;
|
|
8
|
-
textureMultisampled = null;
|
|
9
|
-
textureRenderpassDescriptor;
|
|
10
|
-
textureInitializer;
|
|
11
|
-
textureMask;
|
|
12
|
-
constructor(device, lightsBuffer, lightsTextureProperties) {
|
|
13
|
-
this.lightsBuffer = lightsBuffer;
|
|
14
|
-
const cellsCount = this.lightsBuffer.maxLightsCount / 4;
|
|
15
|
-
const gridSize = {
|
|
16
|
-
x: Math.ceil(Math.sqrt(cellsCount)),
|
|
17
|
-
y: 0,
|
|
18
|
-
};
|
|
19
|
-
gridSize.y = Math.ceil(cellsCount / gridSize.x);
|
|
20
|
-
this.gridSize = gridSize;
|
|
21
|
-
const lightTextureSize = {
|
|
22
|
-
width: gridSize.x * lightsTextureProperties.resolutionPerLight,
|
|
23
|
-
height: gridSize.y * lightsTextureProperties.resolutionPerLight,
|
|
24
|
-
};
|
|
25
|
-
const format = lightsTextureProperties.textureFormat;
|
|
26
|
-
this.texture = device.createTexture({
|
|
27
|
-
label: "LightsTextureMask texture",
|
|
28
|
-
size: [lightTextureSize.width, lightTextureSize.height],
|
|
29
|
-
format,
|
|
30
|
-
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
31
|
-
});
|
|
32
|
-
if (lightsTextureProperties.antialiased) {
|
|
33
|
-
this.textureMultisampled = device.createTexture({
|
|
34
|
-
label: "LightsTextureMask texture multisampled",
|
|
35
|
-
size: [lightTextureSize.width, lightTextureSize.height],
|
|
36
|
-
format,
|
|
37
|
-
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
38
|
-
sampleCount: 4,
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
const textureToRenderTo = this.textureMultisampled ?? this.texture;
|
|
42
|
-
const textureRenderpassColorAttachment = {
|
|
43
|
-
view: textureToRenderTo.createView(),
|
|
44
|
-
clearValue: [0, 0, 0, 1],
|
|
45
|
-
loadOp: "load",
|
|
46
|
-
storeOp: "store",
|
|
47
|
-
};
|
|
48
|
-
if (lightsTextureProperties.antialiased) {
|
|
49
|
-
textureRenderpassColorAttachment.resolveTarget = this.texture.createView();
|
|
50
|
-
}
|
|
51
|
-
this.textureRenderpassDescriptor = {
|
|
52
|
-
label: "lights-renderer render to texture renderpass",
|
|
53
|
-
colorAttachments: [textureRenderpassColorAttachment],
|
|
54
|
-
};
|
|
55
|
-
const lightsTexture = {
|
|
56
|
-
gridSize,
|
|
57
|
-
format,
|
|
58
|
-
sampleCount: this.textureMultisampled?.sampleCount ?? 1,
|
|
59
|
-
};
|
|
60
|
-
this.textureInitializer = new LightsTextureInitializer(device, lightsBuffer, lightsTexture, lightsTextureProperties.maxLightSize);
|
|
61
|
-
this.textureMask = new LightsTextureMask(device, lightsBuffer, lightsTexture, lightsTextureProperties.maxLightSize);
|
|
62
|
-
}
|
|
63
|
-
update(commandEncoder) {
|
|
64
|
-
this.textureMask.setLightsCount(this.lightsBuffer.lightsCount);
|
|
65
|
-
const renderpassEncoder = commandEncoder.beginRenderPass(this.textureRenderpassDescriptor);
|
|
66
|
-
const [textureWidth, textureHeight] = [this.texture.width, this.texture.height];
|
|
67
|
-
renderpassEncoder.setViewport(0, 0, textureWidth, textureHeight, 0, 1);
|
|
68
|
-
renderpassEncoder.setScissorRect(0, 0, textureWidth, textureHeight);
|
|
69
|
-
renderpassEncoder.executeBundles([
|
|
70
|
-
this.textureInitializer.getRenderBundle(),
|
|
71
|
-
this.textureMask.getRenderBundle(),
|
|
72
|
-
]);
|
|
73
|
-
renderpassEncoder.end();
|
|
74
|
-
}
|
|
75
|
-
setObstacles(segments) {
|
|
76
|
-
this.textureMask.setObstacles(segments);
|
|
77
|
-
}
|
|
78
|
-
destroy() {
|
|
79
|
-
this.texture.destroy();
|
|
80
|
-
this.textureMultisampled?.destroy();
|
|
81
|
-
this.textureInitializer.destroy();
|
|
82
|
-
this.textureMask.destroy();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
export { LightsTexture };
|
package/src/light/viewport.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import * as wgpuMatrix from "wgpu-matrix";
|
|
2
|
-
|
|
3
|
-
class Viewport {
|
|
4
|
-
invViewProjectionMatrix = wgpuMatrix.mat4.identity();
|
|
5
|
-
viewportSize = { width: 1, height: 1 };
|
|
6
|
-
topLeft = [0, 0];
|
|
7
|
-
zoom = 1;
|
|
8
|
-
constructor(params) {
|
|
9
|
-
this.setViewportSize(params.viewportSize.width, params.viewportSize.height);
|
|
10
|
-
const initialTopLeft = params.center ?? this.topLeft;
|
|
11
|
-
this.setTopLeft(...initialTopLeft);
|
|
12
|
-
const initialZoom = params.zoom ?? 1;
|
|
13
|
-
this.setZoom(initialZoom);
|
|
14
|
-
}
|
|
15
|
-
get invertViewProjectionMatrix() {
|
|
16
|
-
return this.invViewProjectionMatrix;
|
|
17
|
-
}
|
|
18
|
-
setViewportSize(width, height) {
|
|
19
|
-
this.viewportSize.width = width;
|
|
20
|
-
this.viewportSize.height = height;
|
|
21
|
-
this.updateMatrices();
|
|
22
|
-
}
|
|
23
|
-
setTopLeft(x, y) {
|
|
24
|
-
this.topLeft[0] = x;
|
|
25
|
-
this.topLeft[1] = y;
|
|
26
|
-
this.updateMatrices();
|
|
27
|
-
}
|
|
28
|
-
setZoom(zoom) {
|
|
29
|
-
this.zoom = zoom;
|
|
30
|
-
this.updateMatrices();
|
|
31
|
-
}
|
|
32
|
-
updateMatrices() {
|
|
33
|
-
wgpuMatrix.mat4.identity(this.invViewProjectionMatrix);
|
|
34
|
-
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.scaling([1, -1, 0]), this.invViewProjectionMatrix, this.invViewProjectionMatrix);
|
|
35
|
-
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.translation([1, 1, 0]), this.invViewProjectionMatrix, this.invViewProjectionMatrix);
|
|
36
|
-
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.scaling([0.5 * this.viewportSize.width / this.zoom, 0.5 * this.viewportSize.height / this.zoom, 0]), this.invViewProjectionMatrix, this.invViewProjectionMatrix);
|
|
37
|
-
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.translation([this.topLeft[0], this.topLeft[1], 0]), this.invViewProjectionMatrix, this.invViewProjectionMatrix);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
export { Viewport };
|