bplinejs 0.0.101-beta.10
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/README.md +215 -0
- package/docs/API.md +471 -0
- package/lib/Camera/index.d.ts +88 -0
- package/lib/Camera/index.js +178 -0
- package/lib/Camera/index.js.map +1 -0
- package/lib/Color/index.d.ts +99 -0
- package/lib/Color/index.js +178 -0
- package/lib/Color/index.js.map +1 -0
- package/lib/Geometry/Geo.d.ts +131 -0
- package/lib/Geometry/Geo.js +180 -0
- package/lib/Geometry/Geo.js.map +1 -0
- package/lib/Geometry/Poly2D.d.ts +53 -0
- package/lib/Geometry/Poly2D.js +133 -0
- package/lib/Geometry/Poly2D.js.map +1 -0
- package/lib/Geometry/Rect2d.d.ts +89 -0
- package/lib/Geometry/Rect2d.js +128 -0
- package/lib/Geometry/Rect2d.js.map +1 -0
- package/lib/Geometry/index.d.ts +6 -0
- package/lib/Geometry/index.js +4 -0
- package/lib/Group/index.d.ts +70 -0
- package/lib/Group/index.js +110 -0
- package/lib/Group/index.js.map +1 -0
- package/lib/ID.d.ts +6 -0
- package/lib/ID.js +15 -0
- package/lib/ID.js.map +1 -0
- package/lib/IMesh/index.d.ts +104 -0
- package/lib/IMesh/index.js +333 -0
- package/lib/IMesh/index.js.map +1 -0
- package/lib/Material/Material.d.ts +158 -0
- package/lib/Material/Material.js +229 -0
- package/lib/Material/Material.js.map +1 -0
- package/lib/Material/baseMaterial.d.ts +15 -0
- package/lib/Material/baseMaterial.js +24 -0
- package/lib/Material/baseMaterial.js.map +1 -0
- package/lib/Material/index.d.ts +4 -0
- package/lib/Material/index.js +3 -0
- package/lib/Material/shaders/base/poly/fragment.js +6 -0
- package/lib/Material/shaders/base/poly/fragment.js.map +1 -0
- package/lib/Material/shaders/base/poly/vertex.js +6 -0
- package/lib/Material/shaders/base/poly/vertex.js.map +1 -0
- package/lib/Material/shaders/base/rect/fragment.js +6 -0
- package/lib/Material/shaders/base/rect/fragment.js.map +1 -0
- package/lib/Material/shaders/base/rect/vertex.js +6 -0
- package/lib/Material/shaders/base/rect/vertex.js.map +1 -0
- package/lib/Material/shaders/line/fragment.js +6 -0
- package/lib/Material/shaders/line/fragment.js.map +1 -0
- package/lib/Material/shaders/line/vertex.js +6 -0
- package/lib/Material/shaders/line/vertex.js.map +1 -0
- package/lib/Mesh/index.d.ts +154 -0
- package/lib/Mesh/index.js +254 -0
- package/lib/Mesh/index.js.map +1 -0
- package/lib/Object/index.d.ts +95 -0
- package/lib/Object/index.js +212 -0
- package/lib/Object/index.js.map +1 -0
- package/lib/Raws/index.d.ts +87 -0
- package/lib/Raws/index.js +164 -0
- package/lib/Raws/index.js.map +1 -0
- package/lib/Render/BufferManager.d.ts +93 -0
- package/lib/Render/BufferManager.js +281 -0
- package/lib/Render/BufferManager.js.map +1 -0
- package/lib/Render/DepthManager.d.ts +22 -0
- package/lib/Render/DepthManager.js +95 -0
- package/lib/Render/DepthManager.js.map +1 -0
- package/lib/Render/DestroyManager.d.ts +74 -0
- package/lib/Render/DestroyManager.js +221 -0
- package/lib/Render/DestroyManager.js.map +1 -0
- package/lib/Render/DevelopmentValidator.d.ts +73 -0
- package/lib/Render/DevelopmentValidator.js +188 -0
- package/lib/Render/DevelopmentValidator.js.map +1 -0
- package/lib/Render/DrawCallManager.d.ts +58 -0
- package/lib/Render/DrawCallManager.js +267 -0
- package/lib/Render/DrawCallManager.js.map +1 -0
- package/lib/Render/PipelineManager.d.ts +46 -0
- package/lib/Render/PipelineManager.js +254 -0
- package/lib/Render/PipelineManager.js.map +1 -0
- package/lib/Render/SamplerManager.d.ts +26 -0
- package/lib/Render/SamplerManager.js +42 -0
- package/lib/Render/SamplerManager.js.map +1 -0
- package/lib/Render/SceneUpdate.d.ts +9 -0
- package/lib/Render/SceneUpdate.js +18 -0
- package/lib/Render/SceneUpdate.js.map +1 -0
- package/lib/Render/TextureManager.d.ts +33 -0
- package/lib/Render/TextureManager.js +152 -0
- package/lib/Render/TextureManager.js.map +1 -0
- package/lib/Render/index.d.ts +212 -0
- package/lib/Render/index.js +347 -0
- package/lib/Render/index.js.map +1 -0
- package/lib/Render/types.d.ts +191 -0
- package/lib/Scene/index.d.ts +124 -0
- package/lib/Scene/index.js +225 -0
- package/lib/Scene/index.js.map +1 -0
- package/lib/Style/EdgeStyle.d.ts +28 -0
- package/lib/Style/EdgeStyle.js +67 -0
- package/lib/Style/EdgeStyle.js.map +1 -0
- package/lib/Style/JoinStyle.d.ts +27 -0
- package/lib/Style/JoinStyle.js +53 -0
- package/lib/Style/JoinStyle.js.map +1 -0
- package/lib/Style/PartStyle.d.ts +50 -0
- package/lib/Style/PartStyle.js +92 -0
- package/lib/Style/PartStyle.js.map +1 -0
- package/lib/Style/PointsStyle.d.ts +43 -0
- package/lib/Style/PointsStyle.js +98 -0
- package/lib/Style/PointsStyle.js.map +1 -0
- package/lib/Style/SolidStyle.d.ts +37 -0
- package/lib/Style/SolidStyle.js +83 -0
- package/lib/Style/SolidStyle.js.map +1 -0
- package/lib/Style/TexturedStyle.d.ts +29 -0
- package/lib/Style/TexturedStyle.js +66 -0
- package/lib/Style/TexturedStyle.js.map +1 -0
- package/lib/Style/WireframeStyle.d.ts +7 -0
- package/lib/Style/WireframeStyle.js +13 -0
- package/lib/Style/WireframeStyle.js.map +1 -0
- package/lib/Style/WriteStyleData.d.ts +10 -0
- package/lib/Style/WriteStyleData.js +59 -0
- package/lib/Style/WriteStyleData.js.map +1 -0
- package/lib/Style/index.d.ts +50 -0
- package/lib/Style/index.js +92 -0
- package/lib/Style/index.js.map +1 -0
- package/lib/Style/types.d.ts +21 -0
- package/lib/Texture/Layers.d.ts +26 -0
- package/lib/Texture/Layers.js +42 -0
- package/lib/Texture/Layers.js.map +1 -0
- package/lib/Texture/index.d.ts +116 -0
- package/lib/Texture/index.js +198 -0
- package/lib/Texture/index.js.map +1 -0
- package/lib/global-types.d.ts +8 -0
- package/lib/index.d.ts +43 -0
- package/lib/index.js +34 -0
- package/package.json +130 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import IMesh from "../IMesh/index.js";
|
|
2
|
+
import DepthManager from "./DepthManager.js";
|
|
3
|
+
//#region src/scripts/Render/DrawCallManager.ts
|
|
4
|
+
/**
|
|
5
|
+
* 负责编码 BindGroup、DrawCall 并向 GPUQueue 提交命令。
|
|
6
|
+
* @class
|
|
7
|
+
*/
|
|
8
|
+
var DrawCallManager = class {
|
|
9
|
+
pipeline;
|
|
10
|
+
samplerManager;
|
|
11
|
+
depthManager;
|
|
12
|
+
/**
|
|
13
|
+
* 创建 DrawCall 管理器。
|
|
14
|
+
* @param pipeline 当前 Render 的共享管线资源
|
|
15
|
+
* @param samplerManager Sampler 管理器
|
|
16
|
+
*/
|
|
17
|
+
constructor(pipeline, samplerManager) {
|
|
18
|
+
this.pipeline = pipeline;
|
|
19
|
+
this.depthManager = new DepthManager(pipeline);
|
|
20
|
+
this.samplerManager = samplerManager;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* warmup 只创建深度附件,不提交绘制。
|
|
24
|
+
* @param width 画布物理像素宽度
|
|
25
|
+
* @param height 画布物理像素高度
|
|
26
|
+
*/
|
|
27
|
+
prepare(width, height) {
|
|
28
|
+
this.depthManager.ensureTexture(width, height);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 编码并提交当前场景的基础绘制命令。
|
|
32
|
+
* @param scene 场景对象
|
|
33
|
+
* @param backgroundColor 清空画布使用的 RGBA 颜色
|
|
34
|
+
* @param alphaMode Canvas Alpha 合成方式
|
|
35
|
+
* @returns 无返回值
|
|
36
|
+
*/
|
|
37
|
+
draw(scene, backgroundColor, alphaMode) {
|
|
38
|
+
const device = this.pipeline.device;
|
|
39
|
+
const context = this.pipeline.context;
|
|
40
|
+
if (device === void 0 || context === void 0) return;
|
|
41
|
+
const commandEncoder = device.createCommandEncoder();
|
|
42
|
+
const target = context.getCurrentTexture();
|
|
43
|
+
const depth = this.depthManager.ensureTexture(target.width, target.height);
|
|
44
|
+
if (depth === void 0) return;
|
|
45
|
+
const textureView = target.createView();
|
|
46
|
+
const clearValue = alphaMode === "premultiplied" ? {
|
|
47
|
+
r: backgroundColor.r * backgroundColor.a,
|
|
48
|
+
g: backgroundColor.g * backgroundColor.a,
|
|
49
|
+
b: backgroundColor.b * backgroundColor.a,
|
|
50
|
+
a: backgroundColor.a
|
|
51
|
+
} : backgroundColor;
|
|
52
|
+
const renderPass = commandEncoder.beginRenderPass({
|
|
53
|
+
colorAttachments: [{
|
|
54
|
+
view: textureView,
|
|
55
|
+
clearValue,
|
|
56
|
+
loadOp: "clear",
|
|
57
|
+
storeOp: "store"
|
|
58
|
+
}],
|
|
59
|
+
depthStencilAttachment: {
|
|
60
|
+
view: depth.view,
|
|
61
|
+
depthClearValue: 1,
|
|
62
|
+
depthLoadOp: "clear",
|
|
63
|
+
depthStoreOp: "discard"
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
const viewBuffer = this.pipeline.buffers.cameraUniform[0];
|
|
67
|
+
const orthogonalBuffer = this.pipeline.buffers.cameraUniform[1];
|
|
68
|
+
const renderCameraBuffer = this.pipeline.buffers.cameraUniform[2];
|
|
69
|
+
for (let index = scene.drawList.length - 1; index >= 0; index--) {
|
|
70
|
+
const mesh = scene.drawList[index];
|
|
71
|
+
const material = mesh.material;
|
|
72
|
+
if (material?.depthTest && material.depthWrite && !material.transparent) this.drawMesh(device, renderPass, mesh, viewBuffer, orthogonalBuffer, renderCameraBuffer);
|
|
73
|
+
}
|
|
74
|
+
for (const mesh of scene.drawList) {
|
|
75
|
+
const material = mesh.material;
|
|
76
|
+
if (material?.depthTest && (!material.depthWrite || material.transparent)) this.drawMesh(device, renderPass, mesh, viewBuffer, orthogonalBuffer, renderCameraBuffer);
|
|
77
|
+
}
|
|
78
|
+
for (const mesh of scene.drawList) if (mesh.material !== void 0 && !mesh.material.depthTest) this.drawMesh(device, renderPass, mesh, viewBuffer, orthogonalBuffer, renderCameraBuffer);
|
|
79
|
+
renderPass.end();
|
|
80
|
+
device.queue.submit([commandEncoder.finish()]);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 编码单个 Mesh 的资源绑定与索引绘制命令。
|
|
84
|
+
* @param device 当前 WebGPU 设备
|
|
85
|
+
* @param renderPass 当前 RenderPass
|
|
86
|
+
* @param mesh 当前 Mesh
|
|
87
|
+
* @param viewBuffer 相机视图矩阵缓冲
|
|
88
|
+
* @param orthogonalBuffer 相机投影矩阵缓冲
|
|
89
|
+
* @param renderCameraBuffer Render 与 Camera 公共参数缓冲
|
|
90
|
+
* @returns 无返回值
|
|
91
|
+
*/
|
|
92
|
+
drawMesh(device, renderPass, mesh, viewBuffer, orthogonalBuffer, renderCameraBuffer) {
|
|
93
|
+
const geometry = mesh.data;
|
|
94
|
+
const depthBuffer = this.pipeline.buffers.meshDepth.get(mesh.id);
|
|
95
|
+
const material = mesh.material;
|
|
96
|
+
const matrixBuffer = this.pipeline.buffers.meshMatrix.get(mesh.id);
|
|
97
|
+
const geometryBuffer = geometry === void 0 ? void 0 : this.pipeline.buffers.geometry.get(geometry.id);
|
|
98
|
+
if (depthBuffer === void 0 || mesh.count === 0 || matrixBuffer === void 0 || geometryBuffer === void 0 || geometry === void 0 || !geometry.style.solid.enabled && !geometry.style.edge.enabled && !geometry.style.wireframe.enabled && !geometry.style.points.enabled || material === void 0) return;
|
|
99
|
+
const pipelineTemplate = this.pipeline.pipelineTemplates.get(material.getPipelineKey(geometry.type));
|
|
100
|
+
const triangles = geometryBuffer.geometry;
|
|
101
|
+
if (pipelineTemplate === void 0) return;
|
|
102
|
+
const materialBindGroup = this.createMaterialBindGroup(device, mesh, material, pipelineTemplate);
|
|
103
|
+
if (materialBindGroup === void 0) return;
|
|
104
|
+
const layout = pipelineTemplate.defaultBindGroupLayout;
|
|
105
|
+
let binding = matrixBuffer.bindGroup;
|
|
106
|
+
if (binding?.layout !== layout || binding.view !== viewBuffer || binding.projection !== orthogonalBuffer || binding.parameters !== renderCameraBuffer || binding.geometry !== geometryBuffer.uniform || binding.depth !== depthBuffer.buffer) {
|
|
107
|
+
binding = {
|
|
108
|
+
layout,
|
|
109
|
+
view: viewBuffer,
|
|
110
|
+
projection: orthogonalBuffer,
|
|
111
|
+
parameters: renderCameraBuffer,
|
|
112
|
+
geometry: geometryBuffer.uniform,
|
|
113
|
+
depth: depthBuffer.buffer,
|
|
114
|
+
group: device.createBindGroup({
|
|
115
|
+
layout,
|
|
116
|
+
entries: [
|
|
117
|
+
{
|
|
118
|
+
binding: 0,
|
|
119
|
+
resource: { buffer: matrixBuffer.buffer }
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
binding: 1,
|
|
123
|
+
resource: { buffer: viewBuffer }
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
binding: 2,
|
|
127
|
+
resource: { buffer: orthogonalBuffer }
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
binding: 3,
|
|
131
|
+
resource: { buffer: renderCameraBuffer }
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
binding: 4,
|
|
135
|
+
resource: { buffer: geometryBuffer.uniform }
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
binding: 5,
|
|
139
|
+
resource: { buffer: depthBuffer.buffer }
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
})
|
|
143
|
+
};
|
|
144
|
+
matrixBuffer.bindGroup = binding;
|
|
145
|
+
}
|
|
146
|
+
renderPass.setBindGroup(0, binding.group);
|
|
147
|
+
renderPass.setBindGroup(1, materialBindGroup);
|
|
148
|
+
const individualStyles = mesh instanceof IMesh;
|
|
149
|
+
const hasLine = geometry.style.wireframe.enabled && (individualStyles || material.style.wireframe.enabled) && pipelineTemplate.lineRenderPipeline !== void 0 && geometryBuffer.linePoints !== void 0 && geometry.linePoints !== void 0;
|
|
150
|
+
const canDrawTriangles = geometry.style.solid.enabled && (individualStyles || material.style.solid.enabled) || geometry.style.edge.enabled && (individualStyles || material.style.edge.enabled) || geometry.style.points.enabled && (individualStyles || material.style.points.enabled);
|
|
151
|
+
/**
|
|
152
|
+
* 使用同一套合并顶点与材质资源绘制指定索引范围。
|
|
153
|
+
* @param firstIndex 起始索引,不是字节偏移
|
|
154
|
+
* @param count 本次索引数量
|
|
155
|
+
* @param first 起始实例编号,原生线框回退时用于保持整体顺序
|
|
156
|
+
* @param amount 本次绘制的实例条数
|
|
157
|
+
* @returns 无返回值
|
|
158
|
+
*/
|
|
159
|
+
const DrawTriangles = (firstIndex, count, first, amount) => {
|
|
160
|
+
if (!canDrawTriangles || count === 0 || triangles?.vertexType === void 0 || triangles.position === void 0 || triangles.miterScale === void 0 || pipelineTemplate.renderPipeline === void 0) return;
|
|
161
|
+
renderPass.setPipeline(pipelineTemplate.renderPipeline);
|
|
162
|
+
renderPass.setVertexBuffer(0, triangles.vertex);
|
|
163
|
+
renderPass.setVertexBuffer(1, triangles.uv);
|
|
164
|
+
renderPass.setVertexBuffer(2, triangles.normal);
|
|
165
|
+
renderPass.setVertexBuffer(3, triangles.miterScale);
|
|
166
|
+
renderPass.setVertexBuffer(4, triangles.position);
|
|
167
|
+
renderPass.setVertexBuffer(5, triangles.vertexType);
|
|
168
|
+
renderPass.setIndexBuffer(triangles.index, triangles.indexFormat);
|
|
169
|
+
renderPass.drawIndexed(count, amount, firstIndex, 0, first);
|
|
170
|
+
};
|
|
171
|
+
const amount = hasLine ? 1 : mesh.count;
|
|
172
|
+
for (let first = 0; first < mesh.count; first += amount) {
|
|
173
|
+
const totalIndices = geometry.index?.length ?? 0;
|
|
174
|
+
const splitPoints = hasLine && (individualStyles || material.style.points.enabled) && triangles !== void 0 && triangles.pointsFirstIndex < totalIndices;
|
|
175
|
+
const firstCount = splitPoints ? triangles?.pointsFirstIndex ?? 0 : totalIndices;
|
|
176
|
+
DrawTriangles(0, firstCount, first, amount);
|
|
177
|
+
if (hasLine && pipelineTemplate.lineRenderPipeline !== void 0 && geometryBuffer.linePoints !== void 0 && geometry.linePoints !== void 0) {
|
|
178
|
+
renderPass.setPipeline(pipelineTemplate.lineRenderPipeline);
|
|
179
|
+
renderPass.setVertexBuffer(0, geometryBuffer.linePoints.vertex);
|
|
180
|
+
renderPass.setVertexBuffer(1, geometryBuffer.linePoints.normal);
|
|
181
|
+
renderPass.setIndexBuffer(geometryBuffer.linePoints.index, geometryBuffer.linePoints.indexFormat);
|
|
182
|
+
renderPass.drawIndexed(geometry.linePoints.index.length, amount, 0, 0, first);
|
|
183
|
+
}
|
|
184
|
+
if (splitPoints) DrawTriangles(firstCount, totalIndices - firstCount, first, amount);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* 一次绑定 Mesh 实例样式 Storage 与三种几何的贴图,Sampler 各自独立。
|
|
189
|
+
* @param device 当前 WebGPU 设备
|
|
190
|
+
* @param mesh 当前 Mesh,提供独立实例样式缓冲
|
|
191
|
+
* @param material 当前材质
|
|
192
|
+
* @param pipelineTemplate 当前几何类型对应的 Pipeline 模板
|
|
193
|
+
* @returns 材质 BindGroup,必要资源未就绪时返回 undefined
|
|
194
|
+
*/
|
|
195
|
+
createMaterialBindGroup(device, mesh, material, pipelineTemplate) {
|
|
196
|
+
const fallbackTexture = this.pipeline.fallbackTexture;
|
|
197
|
+
const baseSampler = this.samplerManager.get(material.style.solid.addressModeU, material.style.solid.addressModeV);
|
|
198
|
+
const edgeSampler = this.samplerManager.get(material.style.edge.addressModeU, material.style.edge.addressModeV);
|
|
199
|
+
const pointsSampler = this.samplerManager.get(material.style.points.addressModeU, material.style.points.addressModeV);
|
|
200
|
+
const styleBuffer = this.pipeline.buffers.meshStyle.get(mesh.id);
|
|
201
|
+
if (fallbackTexture === void 0 || baseSampler === void 0 || edgeSampler === void 0 || pointsSampler === void 0 || styleBuffer === void 0) return;
|
|
202
|
+
/**
|
|
203
|
+
* 获取当前贴图视图,空源或尚未上传时使用白色后备资源。
|
|
204
|
+
* @param texture CPU 贴图引用
|
|
205
|
+
* @returns 可绑定的纹理视图
|
|
206
|
+
*/
|
|
207
|
+
const GetView = (texture) => {
|
|
208
|
+
return texture === void 0 ? fallbackTexture.view : this.pipeline.textures.get(texture.id)?.view ?? fallbackTexture.view;
|
|
209
|
+
};
|
|
210
|
+
const textures = mesh.textures;
|
|
211
|
+
const baseView = GetView(textures[0]);
|
|
212
|
+
const edgeView = GetView(textures[1]);
|
|
213
|
+
const pointsView = GetView(textures[2]);
|
|
214
|
+
const layout = pipelineTemplate.materialBindGroupLayout;
|
|
215
|
+
let binding = styleBuffer.bindGroup;
|
|
216
|
+
if (binding?.layout !== layout || binding.baseView !== baseView || binding.edgeView !== edgeView || binding.pointsView !== pointsView || binding.baseSampler !== baseSampler || binding.edgeSampler !== edgeSampler || binding.pointsSampler !== pointsSampler) {
|
|
217
|
+
binding = {
|
|
218
|
+
layout,
|
|
219
|
+
baseView,
|
|
220
|
+
edgeView,
|
|
221
|
+
pointsView,
|
|
222
|
+
baseSampler,
|
|
223
|
+
edgeSampler,
|
|
224
|
+
pointsSampler,
|
|
225
|
+
group: device.createBindGroup({
|
|
226
|
+
layout,
|
|
227
|
+
entries: [
|
|
228
|
+
{
|
|
229
|
+
binding: 0,
|
|
230
|
+
resource: { buffer: styleBuffer.buffer }
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
binding: 1,
|
|
234
|
+
resource: baseView
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
binding: 2,
|
|
238
|
+
resource: baseSampler
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
binding: 3,
|
|
242
|
+
resource: edgeView
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
binding: 4,
|
|
246
|
+
resource: edgeSampler
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
binding: 5,
|
|
250
|
+
resource: pointsView
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
binding: 6,
|
|
254
|
+
resource: pointsSampler
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
})
|
|
258
|
+
};
|
|
259
|
+
styleBuffer.bindGroup = binding;
|
|
260
|
+
}
|
|
261
|
+
return binding.group;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
//#endregion
|
|
265
|
+
export { DrawCallManager as default };
|
|
266
|
+
|
|
267
|
+
//# sourceMappingURL=DrawCallManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DrawCallManager.js","names":[],"sources":["../../src/scripts/Render/DrawCallManager.ts"],"sourcesContent":["import type { Material2d } from \"../global-types\";\nimport IMesh from \"../IMesh\";\nimport type { MeshLike } from \"../Mesh\";\nimport type Scene from \"../Scene\";\nimport DepthManager from \"./DepthManager\";\nimport SamplerManager from \"./SamplerManager\";\nimport type {\n GeometryBufferLike,\n PipelineLike,\n PipelineTemplateLike,\n} from \"./types\";\n\ninterface DrawCallManagerLike {\n prepare(width: number, height: number): void;\n draw(scene: Scene, backgroundColor: GPUColorDict, alphaMode: GPUCanvasAlphaMode): void;\n}\n\n/**\n * 负责编码 BindGroup、DrawCall 并向 GPUQueue 提交命令。\n * @class\n */\nclass DrawCallManager implements DrawCallManagerLike {\n private readonly pipeline: PipelineLike;\n private readonly samplerManager: SamplerManager;\n private readonly depthManager: DepthManager;\n\n /**\n * 创建 DrawCall 管理器。\n * @param pipeline 当前 Render 的共享管线资源\n * @param samplerManager Sampler 管理器\n */\n public constructor(pipeline: PipelineLike, samplerManager: SamplerManager) {\n this.pipeline = pipeline;\n this.depthManager = new DepthManager(pipeline);\n this.samplerManager = samplerManager;\n }\n\n /**\n * warmup 只创建深度附件,不提交绘制。\n * @param width 画布物理像素宽度\n * @param height 画布物理像素高度\n */\n public prepare(width: number, height: number): void {\n this.depthManager.ensureTexture(width, height);\n }\n\n /**\n * 编码并提交当前场景的基础绘制命令。\n * @param scene 场景对象\n * @param backgroundColor 清空画布使用的 RGBA 颜色\n * @param alphaMode Canvas Alpha 合成方式\n * @returns 无返回值\n */\n public draw(scene: Scene, backgroundColor: GPUColorDict, alphaMode: GPUCanvasAlphaMode): void {\n const device: GPUDevice | undefined = this.pipeline.device;\n const context: GPUCanvasContext | undefined = this.pipeline.context;\n\n if (device === undefined || context === undefined) {\n return;\n }\n\n const commandEncoder: GPUCommandEncoder = device.createCommandEncoder();\n const target: GPUTexture = context.getCurrentTexture();\n const depth = this.depthManager.ensureTexture(target.width, target.height);\n if (depth === undefined) return;\n const textureView: GPUTextureView = target.createView();\n const clearValue: GPUColorDict = alphaMode === \"premultiplied\"\n ? {\n r: backgroundColor.r * backgroundColor.a,\n g: backgroundColor.g * backgroundColor.a,\n b: backgroundColor.b * backgroundColor.a,\n a: backgroundColor.a,\n }\n : backgroundColor;\n const renderPass: GPURenderPassEncoder = commandEncoder.beginRenderPass({\n colorAttachments: [{\n view: textureView,\n clearValue,\n loadOp: \"clear\",\n storeOp: \"store\",\n }],\n depthStencilAttachment: {\n view: depth.view, depthClearValue: 1,\n depthLoadOp: \"clear\", depthStoreOp: \"discard\",\n },\n });\n const viewBuffer: GPUBuffer = this.pipeline.buffers.cameraUniform[0];\n const orthogonalBuffer: GPUBuffer = this.pipeline.buffers.cameraUniform[1];\n const renderCameraBuffer: GPUBuffer = this.pipeline.buffers.cameraUniform[2];\n\n // 只反向提交可安全提前写深度的不透明对象,drawList 本身不重排。\n for (let index = scene.drawList.length - 1; index >= 0; index--) {\n const mesh = scene.drawList[index];\n const material = mesh.material;\n if (material?.depthTest && material.depthWrite && !material.transparent) {\n this.drawMesh(device, renderPass, mesh, viewBuffer, orthogonalBuffer, renderCameraBuffer);\n }\n }\n // 透明 / 不写深度对象仍按原始后→前顺序,测试已有的不透明深度。\n for (const mesh of scene.drawList) {\n const material = mesh.material;\n if (material?.depthTest && (!material.depthWrite || material.transparent)) {\n this.drawMesh(device, renderPass, mesh, viewBuffer, orthogonalBuffer, renderCameraBuffer);\n }\n }\n // 关闭测试意味着忽略世界遮挡:作为覆盖层最后绘制,层内仍遵循原队列顺序。\n for (const mesh of scene.drawList) {\n if (mesh.material !== undefined && !mesh.material.depthTest) {\n this.drawMesh(device, renderPass, mesh, viewBuffer, orthogonalBuffer, renderCameraBuffer);\n }\n }\n\n renderPass.end();\n device.queue.submit([commandEncoder.finish()]);\n }\n\n /**\n * 编码单个 Mesh 的资源绑定与索引绘制命令。\n * @param device 当前 WebGPU 设备\n * @param renderPass 当前 RenderPass\n * @param mesh 当前 Mesh\n * @param viewBuffer 相机视图矩阵缓冲\n * @param orthogonalBuffer 相机投影矩阵缓冲\n * @param renderCameraBuffer Render 与 Camera 公共参数缓冲\n * @returns 无返回值\n */\n private drawMesh(\n device: GPUDevice,\n renderPass: GPURenderPassEncoder,\n mesh: MeshLike,\n viewBuffer: GPUBuffer,\n orthogonalBuffer: GPUBuffer,\n renderCameraBuffer: GPUBuffer,\n ): void {\n const geometry = mesh.data;\n const depthBuffer = this.pipeline.buffers.meshDepth.get(mesh.id);\n const material: Material2d | undefined = mesh.material;\n const matrixBuffer = this.pipeline.buffers.meshMatrix.get(mesh.id);\n const geometryBuffer: GeometryBufferLike | undefined = geometry === undefined\n ? undefined\n : this.pipeline.buffers.geometry.get(geometry.id);\n\n if (depthBuffer === undefined || mesh.count === 0 || matrixBuffer === undefined || geometryBuffer === undefined || geometry === undefined || (!geometry.style.solid.enabled && !geometry.style.edge.enabled && !geometry.style.wireframe.enabled && !geometry.style.points.enabled) || material === undefined) {\n return;\n }\n\n const pipelineTemplate: PipelineTemplateLike | undefined = this.pipeline.pipelineTemplates.get(material.getPipelineKey(geometry.type));\n const triangles = geometryBuffer.geometry;\n\n if (pipelineTemplate === undefined) {\n return;\n }\n\n const materialBindGroup: GPUBindGroup | undefined = this.createMaterialBindGroup(device, mesh, material, pipelineTemplate);\n\n if (materialBindGroup === undefined) {\n return;\n }\n\n // writeBuffer 只改变内容,不改变绑定对象。扩容、几何重建、布局更换才需重建绑定。\n const layout = pipelineTemplate.defaultBindGroupLayout;\n let binding = matrixBuffer.bindGroup;\n if (binding?.layout !== layout || binding.view !== viewBuffer\n || binding.projection !== orthogonalBuffer || binding.parameters !== renderCameraBuffer\n || binding.geometry !== geometryBuffer.uniform || binding.depth !== depthBuffer.buffer) {\n binding = {\n layout, view: viewBuffer, projection: orthogonalBuffer, parameters: renderCameraBuffer,\n geometry: geometryBuffer.uniform, depth: depthBuffer.buffer,\n group: device.createBindGroup({\n layout,\n entries: [\n { binding: 0, resource: { buffer: matrixBuffer.buffer } },\n { binding: 1, resource: { buffer: viewBuffer } },\n { binding: 2, resource: { buffer: orthogonalBuffer } },\n { binding: 3, resource: { buffer: renderCameraBuffer } },\n { binding: 4, resource: { buffer: geometryBuffer.uniform } },\n { binding: 5, resource: { buffer: depthBuffer.buffer } },\n ],\n }),\n };\n matrixBuffer.bindGroup = binding;\n }\n\n renderPass.setBindGroup(0, binding.group);\n renderPass.setBindGroup(1, materialBindGroup);\n const individualStyles: boolean = mesh instanceof IMesh;\n const hasLine: boolean = geometry.style.wireframe.enabled\n && (individualStyles || material.style.wireframe.enabled)\n && pipelineTemplate.lineRenderPipeline !== undefined\n && geometryBuffer.linePoints !== undefined\n && geometry.linePoints !== undefined;\n const canDrawTriangles: boolean = (geometry.style.solid.enabled && (individualStyles || material.style.solid.enabled))\n || (geometry.style.edge.enabled && (individualStyles || material.style.edge.enabled))\n || (geometry.style.points.enabled && (individualStyles || material.style.points.enabled));\n\n /**\n * 使用同一套合并顶点与材质资源绘制指定索引范围。\n * @param firstIndex 起始索引,不是字节偏移\n * @param count 本次索引数量\n * @param first 起始实例编号,原生线框回退时用于保持整体顺序\n * @param amount 本次绘制的实例条数\n * @returns 无返回值\n */\n const DrawTriangles = (firstIndex: number, count: number, first: number, amount: number): void => {\n if (!canDrawTriangles || count === 0 || triangles?.vertexType === undefined\n || triangles.position === undefined || triangles.miterScale === undefined\n || pipelineTemplate.renderPipeline === undefined) {\n return;\n }\n renderPass.setPipeline(pipelineTemplate.renderPipeline);\n renderPass.setVertexBuffer(0, triangles.vertex);\n renderPass.setVertexBuffer(1, triangles.uv);\n renderPass.setVertexBuffer(2, triangles.normal);\n renderPass.setVertexBuffer(3, triangles.miterScale);\n renderPass.setVertexBuffer(4, triangles.position);\n renderPass.setVertexBuffer(5, triangles.vertexType);\n renderPass.setIndexBuffer(triangles.index, triangles.indexFormat);\n renderPass.drawIndexed(count, amount, firstIndex, 0, first);\n };\n // 原生线框是另一种 topology,按实例回退绘制,保留透明对象之间的完整层级。\n // 只有合并三角面时仍是一次 drawIndexed(indexCount, count)。\n const amount: number = hasLine ? 1 : mesh.count;\n for (let first = 0; first < mesh.count; first += amount) {\n const totalIndices: number = geometry.index?.length ?? 0;\n const splitPoints: boolean = hasLine && (individualStyles || material.style.points.enabled)\n && triangles !== undefined && triangles.pointsFirstIndex < totalIndices;\n const firstCount: number = splitPoints ? triangles?.pointsFirstIndex ?? 0 : totalIndices;\n DrawTriangles(0, firstCount, first, amount);\n\n if (hasLine && pipelineTemplate.lineRenderPipeline !== undefined\n && geometryBuffer.linePoints !== undefined && geometry.linePoints !== undefined) {\n renderPass.setPipeline(pipelineTemplate.lineRenderPipeline);\n renderPass.setVertexBuffer(0, geometryBuffer.linePoints.vertex);\n renderPass.setVertexBuffer(1, geometryBuffer.linePoints.normal);\n renderPass.setIndexBuffer(geometryBuffer.linePoints.index, geometryBuffer.linePoints.indexFormat);\n renderPass.drawIndexed(geometry.linePoints.index.length, amount, 0, 0, first);\n }\n // line-list 不能与 triangle-list 放进同一次绘制;关键点仍最后覆盖线框。\n if (splitPoints) DrawTriangles(firstCount, totalIndices - firstCount, first, amount);\n }\n }\n\n /**\n * 一次绑定 Mesh 实例样式 Storage 与三种几何的贴图,Sampler 各自独立。\n * @param device 当前 WebGPU 设备\n * @param mesh 当前 Mesh,提供独立实例样式缓冲\n * @param material 当前材质\n * @param pipelineTemplate 当前几何类型对应的 Pipeline 模板\n * @returns 材质 BindGroup,必要资源未就绪时返回 undefined\n */\n private createMaterialBindGroup(\n device: GPUDevice,\n mesh: MeshLike,\n material: Material2d,\n pipelineTemplate: PipelineTemplateLike,\n ): GPUBindGroup | undefined {\n const fallbackTexture = this.pipeline.fallbackTexture;\n const baseSampler = this.samplerManager.get(material.style.solid.addressModeU, material.style.solid.addressModeV);\n const edgeSampler = this.samplerManager.get(material.style.edge.addressModeU, material.style.edge.addressModeV);\n const pointsSampler = this.samplerManager.get(material.style.points.addressModeU, material.style.points.addressModeV);\n const styleBuffer = this.pipeline.buffers.meshStyle.get(mesh.id);\n if (fallbackTexture === undefined || baseSampler === undefined || edgeSampler === undefined\n || pointsSampler === undefined || styleBuffer === undefined) {\n return undefined;\n }\n /**\n * 获取当前贴图视图,空源或尚未上传时使用白色后备资源。\n * @param texture CPU 贴图引用\n * @returns 可绑定的纹理视图\n */\n const GetView = (texture: MeshLike[\"textures\"][number]): GPUTextureView => {\n return texture === undefined ? fallbackTexture.view : this.pipeline.textures.get(texture.id)?.view ?? fallbackTexture.view;\n };\n const textures = mesh.textures;\n const baseView = GetView(textures[0]);\n const edgeView = GetView(textures[1]);\n const pointsView = GetView(textures[2]);\n const layout = pipelineTemplate.materialBindGroupLayout;\n let binding = styleBuffer.bindGroup;\n // 比较实际 GPU 引用而非材质版本:颜色、透明度变化只上传原缓冲即可。\n if (binding?.layout !== layout || binding.baseView !== baseView\n || binding.edgeView !== edgeView || binding.pointsView !== pointsView\n || binding.baseSampler !== baseSampler || binding.edgeSampler !== edgeSampler\n || binding.pointsSampler !== pointsSampler) {\n binding = {\n layout, baseView, edgeView, pointsView, baseSampler, edgeSampler, pointsSampler,\n group: device.createBindGroup({\n layout,\n entries: [\n { binding: 0, resource: { buffer: styleBuffer.buffer } },\n { binding: 1, resource: baseView },\n { binding: 2, resource: baseSampler },\n { binding: 3, resource: edgeView },\n { binding: 4, resource: edgeSampler },\n { binding: 5, resource: pointsView },\n { binding: 6, resource: pointsSampler },\n ],\n }),\n };\n styleBuffer.bindGroup = binding;\n }\n return binding.group;\n }\n}\n\nexport default DrawCallManager;\nexport type { DrawCallManagerLike };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type Scene from "../Scene";
|
|
2
|
+
import SamplerManager from "./SamplerManager";
|
|
3
|
+
import TextureManager from "./TextureManager";
|
|
4
|
+
import type { PipelineLike } from "./types";
|
|
5
|
+
interface PipelineManagerLike {
|
|
6
|
+
initResources(device: GPUDevice): void;
|
|
7
|
+
draw(scene: Scene): void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 管理 BindGroupLayout、Sampler 和可复用的 GPURenderPipeline 模板。
|
|
11
|
+
* @class
|
|
12
|
+
*/
|
|
13
|
+
declare class PipelineManager implements PipelineManagerLike {
|
|
14
|
+
private readonly pipeline;
|
|
15
|
+
private readonly textureManager;
|
|
16
|
+
private readonly samplerManager;
|
|
17
|
+
/**
|
|
18
|
+
* 创建管线管理器。
|
|
19
|
+
* @param pipeline 当前 Render 的共享管线资源
|
|
20
|
+
* @param textureManager 贴图管理器
|
|
21
|
+
* @param samplerManager Sampler 管理器
|
|
22
|
+
*/
|
|
23
|
+
constructor(pipeline: PipelineLike, textureManager: TextureManager, samplerManager: SamplerManager);
|
|
24
|
+
/**
|
|
25
|
+
* 创建当前 Render 共用的 Layout 和后备贴图。
|
|
26
|
+
* @param device 当前 Render 对应的 WebGPU 设备
|
|
27
|
+
* @returns 无返回值
|
|
28
|
+
*/
|
|
29
|
+
initResources(device: GPUDevice): void;
|
|
30
|
+
/**
|
|
31
|
+
* 按 materialList 创建材质管线和采样器,几何类型组合由 Scene 维护。
|
|
32
|
+
* @param scene 场景对象
|
|
33
|
+
* @returns 无返回值
|
|
34
|
+
*/
|
|
35
|
+
draw(scene: Scene): void;
|
|
36
|
+
/**
|
|
37
|
+
* 按几何类型选择统一三角面 Shader,原生线框仍使用独立管线。
|
|
38
|
+
* 未支持的几何不会误用矩形 Shader。
|
|
39
|
+
* @param material 材质状态和源码集合
|
|
40
|
+
* @param geometryType Geometry.type
|
|
41
|
+
* @returns 模板,设备或 Layout 未就绪时为 undefined
|
|
42
|
+
*/
|
|
43
|
+
private createPipelineTemplate;
|
|
44
|
+
}
|
|
45
|
+
export default PipelineManager;
|
|
46
|
+
export type { PipelineManagerLike };
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import fragment_default from "../Material/shaders/line/fragment.js";
|
|
2
|
+
import vertex_default from "../Material/shaders/line/vertex.js";
|
|
3
|
+
//#region src/scripts/Render/PipelineManager.ts
|
|
4
|
+
/**
|
|
5
|
+
* 管理 BindGroupLayout、Sampler 和可复用的 GPURenderPipeline 模板。
|
|
6
|
+
* @class
|
|
7
|
+
*/
|
|
8
|
+
var PipelineManager = class {
|
|
9
|
+
pipeline;
|
|
10
|
+
textureManager;
|
|
11
|
+
samplerManager;
|
|
12
|
+
/**
|
|
13
|
+
* 创建管线管理器。
|
|
14
|
+
* @param pipeline 当前 Render 的共享管线资源
|
|
15
|
+
* @param textureManager 贴图管理器
|
|
16
|
+
* @param samplerManager Sampler 管理器
|
|
17
|
+
*/
|
|
18
|
+
constructor(pipeline, textureManager, samplerManager) {
|
|
19
|
+
this.pipeline = pipeline;
|
|
20
|
+
this.textureManager = textureManager;
|
|
21
|
+
this.samplerManager = samplerManager;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 创建当前 Render 共用的 Layout 和后备贴图。
|
|
25
|
+
* @param device 当前 Render 对应的 WebGPU 设备
|
|
26
|
+
* @returns 无返回值
|
|
27
|
+
*/
|
|
28
|
+
initResources(device) {
|
|
29
|
+
this.pipeline.defaultBindGroupLayout = device.createBindGroupLayout({
|
|
30
|
+
label: "Default Matrix Bind Group Layout",
|
|
31
|
+
entries: [
|
|
32
|
+
{
|
|
33
|
+
binding: 0,
|
|
34
|
+
visibility: GPUShaderStage.VERTEX,
|
|
35
|
+
buffer: { type: "read-only-storage" }
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
binding: 1,
|
|
39
|
+
visibility: GPUShaderStage.VERTEX,
|
|
40
|
+
buffer: { type: "uniform" }
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
binding: 2,
|
|
44
|
+
visibility: GPUShaderStage.VERTEX,
|
|
45
|
+
buffer: { type: "uniform" }
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
binding: 3,
|
|
49
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
50
|
+
buffer: { type: "uniform" }
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
binding: 4,
|
|
54
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
55
|
+
buffer: { type: "uniform" }
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
binding: 5,
|
|
59
|
+
visibility: GPUShaderStage.VERTEX,
|
|
60
|
+
buffer: { type: "uniform" }
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
});
|
|
64
|
+
this.pipeline.baseMaterialBindGroupLayout = device.createBindGroupLayout({
|
|
65
|
+
label: "BaseMaterial Bind Group Layout",
|
|
66
|
+
entries: [
|
|
67
|
+
{
|
|
68
|
+
binding: 0,
|
|
69
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
70
|
+
buffer: { type: "read-only-storage" }
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
binding: 1,
|
|
74
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
75
|
+
texture: {
|
|
76
|
+
sampleType: "float",
|
|
77
|
+
viewDimension: "2d-array"
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
binding: 2,
|
|
82
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
83
|
+
sampler: { type: "filtering" }
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
binding: 3,
|
|
87
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
88
|
+
texture: {
|
|
89
|
+
sampleType: "float",
|
|
90
|
+
viewDimension: "2d-array"
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
binding: 4,
|
|
95
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
96
|
+
sampler: { type: "filtering" }
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
binding: 5,
|
|
100
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
101
|
+
texture: {
|
|
102
|
+
sampleType: "float",
|
|
103
|
+
viewDimension: "2d-array"
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
binding: 6,
|
|
108
|
+
visibility: GPUShaderStage.FRAGMENT,
|
|
109
|
+
sampler: { type: "filtering" }
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
});
|
|
113
|
+
this.pipeline.fallbackTexture = this.textureManager.createFallbackTexture(device);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 按 materialList 创建材质管线和采样器,几何类型组合由 Scene 维护。
|
|
117
|
+
* @param scene 场景对象
|
|
118
|
+
* @returns 无返回值
|
|
119
|
+
*/
|
|
120
|
+
draw(scene) {
|
|
121
|
+
for (const material of scene.materialList) {
|
|
122
|
+
this.samplerManager.get(material.style.solid.addressModeU, material.style.solid.addressModeV);
|
|
123
|
+
this.samplerManager.get(material.style.edge.addressModeU, material.style.edge.addressModeV);
|
|
124
|
+
this.samplerManager.get(material.style.points.addressModeU, material.style.points.addressModeV);
|
|
125
|
+
for (const geometryType of scene.getMaterialGeometryTypes(material.id)) {
|
|
126
|
+
const key = material.getPipelineKey(geometryType);
|
|
127
|
+
if (this.pipeline.pipelineTemplates.has(key)) continue;
|
|
128
|
+
const template = this.createPipelineTemplate(material, geometryType);
|
|
129
|
+
if (template !== void 0) this.pipeline.pipelineTemplates.set(key, template);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 按几何类型选择统一三角面 Shader,原生线框仍使用独立管线。
|
|
135
|
+
* 未支持的几何不会误用矩形 Shader。
|
|
136
|
+
* @param material 材质状态和源码集合
|
|
137
|
+
* @param geometryType Geometry.type
|
|
138
|
+
* @returns 模板,设备或 Layout 未就绪时为 undefined
|
|
139
|
+
*/
|
|
140
|
+
createPipelineTemplate(material, geometryType) {
|
|
141
|
+
const device = this.pipeline.device;
|
|
142
|
+
const format = this.pipeline.format;
|
|
143
|
+
const defaultBindGroupLayout = this.pipeline.defaultBindGroupLayout;
|
|
144
|
+
const materialBindGroupLayout = this.pipeline.baseMaterialBindGroupLayout;
|
|
145
|
+
if (device === void 0 || format === void 0 || defaultBindGroupLayout === void 0 || materialBindGroupLayout === void 0) return;
|
|
146
|
+
const layout = device.createPipelineLayout({ bindGroupLayouts: [defaultBindGroupLayout, materialBindGroupLayout] });
|
|
147
|
+
const blend = material.transparent ? {
|
|
148
|
+
color: {
|
|
149
|
+
srcFactor: "src-alpha",
|
|
150
|
+
dstFactor: "one-minus-src-alpha",
|
|
151
|
+
operation: "add"
|
|
152
|
+
},
|
|
153
|
+
alpha: {
|
|
154
|
+
srcFactor: "one",
|
|
155
|
+
dstFactor: "one-minus-src-alpha",
|
|
156
|
+
operation: "add"
|
|
157
|
+
}
|
|
158
|
+
} : void 0;
|
|
159
|
+
/**
|
|
160
|
+
* 创建一套图元管线,顶点缓冲槽位顺序由 attributes 决定。
|
|
161
|
+
* @param label 调试标签
|
|
162
|
+
* @param vertex 顶点源码
|
|
163
|
+
* @param fragment 片元源码
|
|
164
|
+
* @param topology 图元类型
|
|
165
|
+
* @param attributes 顶点属性布局
|
|
166
|
+
* @returns 已创建的管线,源码未提供时为 undefined
|
|
167
|
+
*/
|
|
168
|
+
const CreatePipeline = (label, vertex, fragment, topology, attributes) => {
|
|
169
|
+
if (vertex === void 0 || fragment === void 0) return;
|
|
170
|
+
return device.createRenderPipeline({
|
|
171
|
+
label,
|
|
172
|
+
layout,
|
|
173
|
+
vertex: {
|
|
174
|
+
module: device.createShaderModule({ code: vertex }),
|
|
175
|
+
entryPoint: "main",
|
|
176
|
+
buffers: attributes
|
|
177
|
+
},
|
|
178
|
+
fragment: {
|
|
179
|
+
module: device.createShaderModule({ code: fragment }),
|
|
180
|
+
entryPoint: "main",
|
|
181
|
+
targets: [{
|
|
182
|
+
format,
|
|
183
|
+
blend
|
|
184
|
+
}]
|
|
185
|
+
},
|
|
186
|
+
depthStencil: {
|
|
187
|
+
format: "depth32float",
|
|
188
|
+
depthWriteEnabled: material.depthWrite,
|
|
189
|
+
depthCompare: material.depthTest ? "less-equal" : "always"
|
|
190
|
+
},
|
|
191
|
+
primitive: {
|
|
192
|
+
topology,
|
|
193
|
+
frontFace: "cw",
|
|
194
|
+
cullMode: topology === "line-list" ? "none" : material.cullMode
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
const vectorAttributes = [
|
|
199
|
+
0,
|
|
200
|
+
1,
|
|
201
|
+
2
|
|
202
|
+
].map((location) => ({
|
|
203
|
+
arrayStride: 8,
|
|
204
|
+
attributes: [{
|
|
205
|
+
shaderLocation: location,
|
|
206
|
+
offset: 0,
|
|
207
|
+
format: "float32x2"
|
|
208
|
+
}]
|
|
209
|
+
}));
|
|
210
|
+
let renderPipeline;
|
|
211
|
+
if (geometryType === "Rect2d" || geometryType === "Poly2D") {
|
|
212
|
+
const polygon = geometryType === "Poly2D";
|
|
213
|
+
renderPipeline = CreatePipeline(polygon ? "BaseMaterial Poly Pipeline" : "BaseMaterial Rect Pipeline", polygon ? material.polyVertexShader : material.rectVertexShader, polygon ? material.polyFragmentShader : material.rectFragmentShader, "triangle-list", [
|
|
214
|
+
...vectorAttributes,
|
|
215
|
+
{
|
|
216
|
+
arrayStride: 4,
|
|
217
|
+
attributes: [{
|
|
218
|
+
shaderLocation: 3,
|
|
219
|
+
offset: 0,
|
|
220
|
+
format: "float32"
|
|
221
|
+
}]
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
arrayStride: 8,
|
|
225
|
+
attributes: [{
|
|
226
|
+
shaderLocation: 4,
|
|
227
|
+
offset: 0,
|
|
228
|
+
format: "float32x2"
|
|
229
|
+
}]
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
arrayStride: 4,
|
|
233
|
+
attributes: [{
|
|
234
|
+
shaderLocation: 5,
|
|
235
|
+
offset: 0,
|
|
236
|
+
format: "float32"
|
|
237
|
+
}]
|
|
238
|
+
}
|
|
239
|
+
]);
|
|
240
|
+
}
|
|
241
|
+
const lineRenderPipeline = CreatePipeline("Line Pipeline", vertex_default, fragment_default, "line-list", [vectorAttributes[0], vectorAttributes[2]]);
|
|
242
|
+
return {
|
|
243
|
+
key: material.getPipelineKey(geometryType),
|
|
244
|
+
renderPipeline,
|
|
245
|
+
lineRenderPipeline,
|
|
246
|
+
defaultBindGroupLayout,
|
|
247
|
+
materialBindGroupLayout
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
//#endregion
|
|
252
|
+
export { PipelineManager as default };
|
|
253
|
+
|
|
254
|
+
//# sourceMappingURL=PipelineManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PipelineManager.js","names":[],"sources":["../../src/scripts/Render/PipelineManager.ts"],"sourcesContent":["import type { Material2d } from \"../global-types\";\nimport lineFragmentShader from \"../Material/shaders/line/fragment.shader?raw\";\nimport lineVertexShader from \"../Material/shaders/line/vertex.shader?raw\";\nimport type Scene from \"../Scene\";\nimport SamplerManager from \"./SamplerManager\";\nimport TextureManager from \"./TextureManager\";\nimport type { PipelineLike, PipelineTemplateLike } from \"./types\";\n\ninterface PipelineManagerLike {\n initResources(device: GPUDevice): void;\n draw(scene: Scene): void;\n}\n\n/**\n * 管理 BindGroupLayout、Sampler 和可复用的 GPURenderPipeline 模板。\n * @class\n */\nclass PipelineManager implements PipelineManagerLike {\n private readonly pipeline: PipelineLike;\n private readonly textureManager: TextureManager;\n private readonly samplerManager: SamplerManager;\n\n /**\n * 创建管线管理器。\n * @param pipeline 当前 Render 的共享管线资源\n * @param textureManager 贴图管理器\n * @param samplerManager Sampler 管理器\n */\n public constructor(\n pipeline: PipelineLike,\n textureManager: TextureManager,\n samplerManager: SamplerManager,\n ) {\n this.pipeline = pipeline;\n this.textureManager = textureManager;\n this.samplerManager = samplerManager;\n }\n\n /**\n * 创建当前 Render 共用的 Layout 和后备贴图。\n * @param device 当前 Render 对应的 WebGPU 设备\n * @returns 无返回值\n */\n public initResources(device: GPUDevice): void {\n this.pipeline.defaultBindGroupLayout = device.createBindGroupLayout({\n label: \"Default Matrix Bind Group Layout\",\n entries: [\n { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: \"read-only-storage\" } },\n { binding: 1, visibility: GPUShaderStage.VERTEX, buffer: { type: \"uniform\" } },\n { binding: 2, visibility: GPUShaderStage.VERTEX, buffer: { type: \"uniform\" } },\n { binding: 3, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: \"uniform\" } },\n { binding: 4, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: \"uniform\" } },\n { binding: 5, visibility: GPUShaderStage.VERTEX, buffer: { type: \"uniform\" } },\n ],\n });\n this.pipeline.baseMaterialBindGroupLayout = device.createBindGroupLayout({\n label: \"BaseMaterial Bind Group Layout\",\n entries: [\n { binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: \"read-only-storage\" } },\n { binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: \"float\", viewDimension: \"2d-array\" } },\n { binding: 2, visibility: GPUShaderStage.FRAGMENT, sampler: { type: \"filtering\" } },\n // 三套贴图和寻址状态同时绑定,Shader 根据 vertexType 选择。\n { binding: 3, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: \"float\", viewDimension: \"2d-array\" } },\n { binding: 4, visibility: GPUShaderStage.FRAGMENT, sampler: { type: \"filtering\" } },\n { binding: 5, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: \"float\", viewDimension: \"2d-array\" } },\n { binding: 6, visibility: GPUShaderStage.FRAGMENT, sampler: { type: \"filtering\" } },\n ],\n });\n this.pipeline.fallbackTexture = this.textureManager.createFallbackTexture(device);\n }\n\n /**\n * 按 materialList 创建材质管线和采样器,几何类型组合由 Scene 维护。\n * @param scene 场景对象\n * @returns 无返回值\n */\n public draw(scene: Scene): void {\n for (const material of scene.materialList) {\n this.samplerManager.get(material.style.solid.addressModeU, material.style.solid.addressModeV);\n this.samplerManager.get(material.style.edge.addressModeU, material.style.edge.addressModeV);\n this.samplerManager.get(material.style.points.addressModeU, material.style.points.addressModeV);\n for (const geometryType of scene.getMaterialGeometryTypes(material.id)) {\n const key: string = material.getPipelineKey(geometryType);\n if (this.pipeline.pipelineTemplates.has(key)) continue;\n const template = this.createPipelineTemplate(material, geometryType);\n if (template !== undefined) this.pipeline.pipelineTemplates.set(key, template);\n }\n }\n }\n\n /**\n * 按几何类型选择统一三角面 Shader,原生线框仍使用独立管线。\n * 未支持的几何不会误用矩形 Shader。\n * @param material 材质状态和源码集合\n * @param geometryType Geometry.type\n * @returns 模板,设备或 Layout 未就绪时为 undefined\n */\n private createPipelineTemplate(material: Material2d, geometryType: string): PipelineTemplateLike | undefined {\n const device = this.pipeline.device;\n const format = this.pipeline.format;\n const defaultBindGroupLayout = this.pipeline.defaultBindGroupLayout;\n const materialBindGroupLayout = this.pipeline.baseMaterialBindGroupLayout;\n if (device === undefined || format === undefined || defaultBindGroupLayout === undefined || materialBindGroupLayout === undefined) {\n return undefined;\n }\n const layout: GPUPipelineLayout = device.createPipelineLayout({\n bindGroupLayouts: [defaultBindGroupLayout, materialBindGroupLayout],\n });\n const blend: GPUBlendState | undefined = material.transparent ? {\n color: { srcFactor: \"src-alpha\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n alpha: { srcFactor: \"one\", dstFactor: \"one-minus-src-alpha\", operation: \"add\" },\n } : undefined;\n\n /**\n * 创建一套图元管线,顶点缓冲槽位顺序由 attributes 决定。\n * @param label 调试标签\n * @param vertex 顶点源码\n * @param fragment 片元源码\n * @param topology 图元类型\n * @param attributes 顶点属性布局\n * @returns 已创建的管线,源码未提供时为 undefined\n */\n const CreatePipeline = (\n label: string,\n vertex: string | undefined,\n fragment: string | undefined,\n topology: GPUPrimitiveTopology,\n attributes: GPUVertexBufferLayout[],\n ): GPURenderPipeline | undefined => {\n if (vertex === undefined || fragment === undefined) {\n return undefined;\n }\n return device.createRenderPipeline({\n label,\n layout,\n vertex: {\n module: device.createShaderModule({ code: vertex }),\n entryPoint: \"main\",\n buffers: attributes,\n },\n fragment: {\n module: device.createShaderModule({ code: fragment }),\n entryPoint: \"main\",\n targets: [{ format, blend }],\n },\n depthStencil: {\n format: \"depth32float\",\n depthWriteEnabled: material.depthWrite,\n // 同一实例的面/边框/点共享深度,equal 允许后绘制分区覆盖前面的分区。\n depthCompare: material.depthTest ? \"less-equal\" : \"always\",\n },\n primitive: {\n topology,\n // 现有 2D 几何采用顺时针三角面;line-list 不剔除面。\n frontFace: \"cw\",\n cullMode: topology === \"line-list\" ? \"none\" : material.cullMode,\n },\n });\n };\n\n const vectorAttributes: GPUVertexBufferLayout[] = [0, 1, 2].map((location: number): GPUVertexBufferLayout => ({\n arrayStride: 8,\n attributes: [{ shaderLocation: location, offset: 0, format: \"float32x2\" }],\n }));\n let renderPipeline: GPURenderPipeline | undefined;\n if (geometryType === \"Rect2d\" || geometryType === \"Poly2D\") {\n const polygon: boolean = geometryType === \"Poly2D\";\n renderPipeline = CreatePipeline(\n polygon ? \"BaseMaterial Poly Pipeline\" : \"BaseMaterial Rect Pipeline\",\n polygon ? material.polyVertexShader : material.rectVertexShader,\n polygon ? material.polyFragmentShader : material.rectFragmentShader,\n \"triangle-list\", [\n ...vectorAttributes,\n { arrayStride: 4, attributes: [{ shaderLocation: 3, offset: 0, format: \"float32\" }] },\n { arrayStride: 8, attributes: [{ shaderLocation: 4, offset: 0, format: \"float32x2\" }] },\n { arrayStride: 4, attributes: [{ shaderLocation: 5, offset: 0, format: \"float32\" }] },\n ],\n );\n }\n const lineRenderPipeline = CreatePipeline(\"Line Pipeline\", lineVertexShader, lineFragmentShader, \"line-list\", [\n vectorAttributes[0], vectorAttributes[2],\n ]);\n\n return {\n key: material.getPipelineKey(geometryType),\n renderPipeline,\n lineRenderPipeline,\n defaultBindGroupLayout,\n materialBindGroupLayout,\n };\n }\n}\n\nexport default PipelineManager;\nexport type { PipelineManagerLike };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PipelineLike } from "./types";
|
|
2
|
+
interface SamplerManagerLike {
|
|
3
|
+
get(addressModeU: GPUAddressMode, addressModeV: GPUAddressMode): GPUSampler | undefined;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* 管理当前 Render 对应 GPUDevice 创建的 Sampler 缓存。
|
|
7
|
+
* 相同 U/V 寻址组合在多个材质和 DrawCall 之间复用同一个 GPUSampler。
|
|
8
|
+
* @class
|
|
9
|
+
*/
|
|
10
|
+
declare class SamplerManager implements SamplerManagerLike {
|
|
11
|
+
private readonly pipeline;
|
|
12
|
+
/**
|
|
13
|
+
* 创建 Sampler 管理器。
|
|
14
|
+
* @param pipeline 当前 Render 的共享管线资源
|
|
15
|
+
*/
|
|
16
|
+
constructor(pipeline: PipelineLike);
|
|
17
|
+
/**
|
|
18
|
+
* 获取或创建指定寻址组合的 Sampler。
|
|
19
|
+
* @param addressModeU 水平方向寻址方式
|
|
20
|
+
* @param addressModeV 垂直方向寻址方式
|
|
21
|
+
* @returns 可复用 Sampler,GPUDevice 尚未就绪时返回 undefined
|
|
22
|
+
*/
|
|
23
|
+
get(addressModeU: GPUAddressMode, addressModeV: GPUAddressMode): GPUSampler | undefined;
|
|
24
|
+
}
|
|
25
|
+
export default SamplerManager;
|
|
26
|
+
export type { SamplerManagerLike };
|