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,221 @@
|
|
|
1
|
+
//#region src/scripts/Render/DestroyManager.ts
|
|
2
|
+
/**
|
|
3
|
+
* 统一负责当前 Render 的 GPU 资源销毁与无引用缓存回收。
|
|
4
|
+
* @class
|
|
5
|
+
*/
|
|
6
|
+
var DestroyManager = class {
|
|
7
|
+
pipeline;
|
|
8
|
+
/**
|
|
9
|
+
* 创建销毁管理器。
|
|
10
|
+
* @param pipeline 当前 Render 的共享管线资源
|
|
11
|
+
*/
|
|
12
|
+
constructor(pipeline) {
|
|
13
|
+
this.pipeline = pipeline;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* 销毁指定 Mesh 的模型矩阵缓冲及可取得的关联资源。
|
|
17
|
+
* @param mesh Mesh 对象或全局 ID
|
|
18
|
+
* @returns 是否销毁了任意资源
|
|
19
|
+
*/
|
|
20
|
+
destroyMesh(mesh) {
|
|
21
|
+
const meshId = typeof mesh === "number" ? mesh : mesh.id;
|
|
22
|
+
const matrixBuffer = this.pipeline.buffers.meshMatrix.get(meshId);
|
|
23
|
+
let destroyed = false;
|
|
24
|
+
if (matrixBuffer !== void 0) {
|
|
25
|
+
matrixBuffer.buffer.destroy();
|
|
26
|
+
this.pipeline.buffers.meshMatrix.delete(meshId);
|
|
27
|
+
destroyed = true;
|
|
28
|
+
}
|
|
29
|
+
const depthBuffer = this.pipeline.buffers.meshDepth.get(meshId);
|
|
30
|
+
if (depthBuffer !== void 0) {
|
|
31
|
+
depthBuffer.buffer.destroy();
|
|
32
|
+
this.pipeline.buffers.meshDepth.delete(meshId);
|
|
33
|
+
destroyed = true;
|
|
34
|
+
}
|
|
35
|
+
const styleBuffer = this.pipeline.buffers.meshStyle.get(meshId);
|
|
36
|
+
if (styleBuffer !== void 0) {
|
|
37
|
+
styleBuffer.buffer.destroy();
|
|
38
|
+
this.pipeline.buffers.meshStyle.delete(meshId);
|
|
39
|
+
destroyed = true;
|
|
40
|
+
}
|
|
41
|
+
if (typeof mesh !== "number") {
|
|
42
|
+
for (const texture of mesh.textures) if (texture !== void 0) destroyed = this.destroyTexture(texture) || destroyed;
|
|
43
|
+
if (mesh.data !== void 0) destroyed = this.destroyGeometry(mesh.data) || destroyed;
|
|
44
|
+
if (mesh.material !== void 0) destroyed = this.destroyMaterial(mesh.material) || destroyed;
|
|
45
|
+
}
|
|
46
|
+
return destroyed;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 销毁指定 Texture 的 GPUTexture 缓存。
|
|
50
|
+
* @param texture Texture 对象或全局 ID
|
|
51
|
+
* @returns 是否找到并销毁了对应资源
|
|
52
|
+
*/
|
|
53
|
+
destroyTexture(texture) {
|
|
54
|
+
const textureId = typeof texture === "number" ? texture : texture.id;
|
|
55
|
+
let destroyed = false;
|
|
56
|
+
for (const [id, resource] of this.pipeline.textures) {
|
|
57
|
+
if (id !== textureId && !resource.sourceIds?.has(textureId)) continue;
|
|
58
|
+
this.releaseTextureBindings(resource.view);
|
|
59
|
+
resource.texture.destroy();
|
|
60
|
+
this.pipeline.textures.delete(id);
|
|
61
|
+
destroyed = true;
|
|
62
|
+
}
|
|
63
|
+
return destroyed;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 销毁所有关联此 Material 的 Mesh 实例样式缓冲,并在可取得对象时销毁其基础、边框和点型贴图。
|
|
67
|
+
* @param material Material 对象或全局 ID
|
|
68
|
+
* @returns 是否销毁了任意资源
|
|
69
|
+
*/
|
|
70
|
+
destroyMaterial(material) {
|
|
71
|
+
const materialId = typeof material === "number" ? material : material.id;
|
|
72
|
+
let destroyed = false;
|
|
73
|
+
for (const [meshId, styleBuffer] of this.pipeline.buffers.meshStyle) {
|
|
74
|
+
if (styleBuffer.materialId !== materialId) continue;
|
|
75
|
+
styleBuffer.buffer.destroy();
|
|
76
|
+
this.pipeline.buffers.meshStyle.delete(meshId);
|
|
77
|
+
destroyed = true;
|
|
78
|
+
}
|
|
79
|
+
if (typeof material !== "number") {
|
|
80
|
+
const textureIds = /* @__PURE__ */ new Set();
|
|
81
|
+
if (material.style.solid.texture !== void 0) {
|
|
82
|
+
textureIds.add(material.style.solid.texture.id);
|
|
83
|
+
destroyed = this.destroyTexture(material.style.solid.texture) || destroyed;
|
|
84
|
+
}
|
|
85
|
+
if (material.style.edge.texture !== void 0 && !textureIds.has(material.style.edge.texture.id)) {
|
|
86
|
+
textureIds.add(material.style.edge.texture.id);
|
|
87
|
+
destroyed = this.destroyTexture(material.style.edge.texture) || destroyed;
|
|
88
|
+
}
|
|
89
|
+
if (material.style.points.texture !== void 0 && !textureIds.has(material.style.points.texture.id)) destroyed = this.destroyTexture(material.style.points.texture) || destroyed;
|
|
90
|
+
}
|
|
91
|
+
return destroyed;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* 销毁指定 Geometry 的全部 GPUBuffer。
|
|
95
|
+
* @param geometry Geometry 对象或全局 ID
|
|
96
|
+
* @returns 是否找到并销毁了对应资源
|
|
97
|
+
*/
|
|
98
|
+
destroyGeometry(geometry) {
|
|
99
|
+
const geometryId = typeof geometry === "number" ? geometry : geometry.id;
|
|
100
|
+
const geometryBuffer = this.pipeline.buffers.geometry.get(geometryId);
|
|
101
|
+
if (geometryBuffer === void 0) return false;
|
|
102
|
+
this.destroyGeometryBuffer(geometryBuffer);
|
|
103
|
+
this.pipeline.buffers.geometry.delete(geometryId);
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 更新场景资源使用记录并回收所有场景均未引用的缓存。
|
|
108
|
+
* @param scene 需要同步资源记录的场景
|
|
109
|
+
* @returns 无返回值
|
|
110
|
+
*/
|
|
111
|
+
trim(scene) {
|
|
112
|
+
scene.ensureLists();
|
|
113
|
+
const sceneResources = {
|
|
114
|
+
version: scene.version,
|
|
115
|
+
meshIds: /* @__PURE__ */ new Set(),
|
|
116
|
+
geometryIds: /* @__PURE__ */ new Set(),
|
|
117
|
+
materialIds: /* @__PURE__ */ new Set(),
|
|
118
|
+
textureIds: /* @__PURE__ */ new Set(),
|
|
119
|
+
pipelineKeys: /* @__PURE__ */ new Set()
|
|
120
|
+
};
|
|
121
|
+
for (const mesh of scene.drawList) sceneResources.meshIds.add(mesh.id);
|
|
122
|
+
for (const geometry of scene.geometryList) sceneResources.geometryIds.add(geometry.id);
|
|
123
|
+
for (const material of scene.materialList) sceneResources.materialIds.add(material.id);
|
|
124
|
+
for (const mesh of scene.drawList) if (mesh.data !== void 0 && mesh.material !== void 0) sceneResources.pipelineKeys.add(mesh.material.getPipelineKey(mesh.data.type));
|
|
125
|
+
for (const texture of scene.textureList) sceneResources.textureIds.add(texture.id);
|
|
126
|
+
this.pipeline.sceneResources.set(scene.id, sceneResources);
|
|
127
|
+
const usedResources = {
|
|
128
|
+
version: 0,
|
|
129
|
+
meshIds: /* @__PURE__ */ new Set(),
|
|
130
|
+
geometryIds: /* @__PURE__ */ new Set(),
|
|
131
|
+
materialIds: /* @__PURE__ */ new Set(),
|
|
132
|
+
textureIds: /* @__PURE__ */ new Set(),
|
|
133
|
+
pipelineKeys: /* @__PURE__ */ new Set()
|
|
134
|
+
};
|
|
135
|
+
for (const resources of this.pipeline.sceneResources.values()) {
|
|
136
|
+
for (const id of resources.meshIds) usedResources.meshIds.add(id);
|
|
137
|
+
for (const id of resources.geometryIds) usedResources.geometryIds.add(id);
|
|
138
|
+
for (const id of resources.materialIds) usedResources.materialIds.add(id);
|
|
139
|
+
for (const id of resources.textureIds) usedResources.textureIds.add(id);
|
|
140
|
+
for (const key of resources.pipelineKeys) usedResources.pipelineKeys.add(key);
|
|
141
|
+
}
|
|
142
|
+
for (const matrixBuffer of this.pipeline.buffers.meshMatrix.values()) if (!usedResources.meshIds.has(matrixBuffer.meshId)) this.destroyMesh(matrixBuffer.meshId);
|
|
143
|
+
for (const meshId of this.pipeline.buffers.meshDepth.keys()) if (!usedResources.meshIds.has(meshId)) this.destroyMesh(meshId);
|
|
144
|
+
for (const geometryId of this.pipeline.buffers.geometry.keys()) if (!usedResources.geometryIds.has(geometryId)) this.destroyGeometry(geometryId);
|
|
145
|
+
for (const meshId of this.pipeline.buffers.meshStyle.keys()) if (!usedResources.meshIds.has(meshId)) this.destroyMesh(meshId);
|
|
146
|
+
for (const [textureId, texture] of this.pipeline.textures) if (!usedResources.textureIds.has(textureId)) {
|
|
147
|
+
this.releaseTextureBindings(texture.view);
|
|
148
|
+
texture.texture.destroy();
|
|
149
|
+
this.pipeline.textures.delete(textureId);
|
|
150
|
+
}
|
|
151
|
+
for (const pipelineKey of this.pipeline.pipelineTemplates.keys()) if (!usedResources.pipelineKeys.has(pipelineKey)) this.pipeline.pipelineTemplates.delete(pipelineKey);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* 销毁当前 Render 持有的全部 WebGPU 资源和设备。
|
|
155
|
+
* @returns 无返回值
|
|
156
|
+
*/
|
|
157
|
+
destroyAll() {
|
|
158
|
+
const device = this.pipeline.device;
|
|
159
|
+
this.pipeline.context?.unconfigure();
|
|
160
|
+
for (const matrixBuffer of this.pipeline.buffers.meshMatrix.values()) matrixBuffer.buffer.destroy();
|
|
161
|
+
this.pipeline.buffers.meshMatrix.clear();
|
|
162
|
+
for (const depthBuffer of this.pipeline.buffers.meshDepth.values()) depthBuffer.buffer.destroy();
|
|
163
|
+
this.pipeline.depthTexture?.texture.destroy();
|
|
164
|
+
this.pipeline.depthTexture = void 0;
|
|
165
|
+
this.pipeline.buffers.meshDepth.clear();
|
|
166
|
+
for (const geometryBuffer of this.pipeline.buffers.geometry.values()) this.destroyGeometryBuffer(geometryBuffer);
|
|
167
|
+
for (const materialBuffer of this.pipeline.buffers.meshStyle.values()) materialBuffer.buffer.destroy();
|
|
168
|
+
for (const cameraBuffer of this.pipeline.buffers.cameraUniform) cameraBuffer.destroy();
|
|
169
|
+
for (const textureResource of this.pipeline.textures.values()) textureResource.texture.destroy();
|
|
170
|
+
this.pipeline.fallbackTexture?.texture.destroy();
|
|
171
|
+
this.pipeline.buffers.geometry.clear();
|
|
172
|
+
this.pipeline.buffers.meshStyle.clear();
|
|
173
|
+
this.pipeline.buffers.cameraUniform.length = 0;
|
|
174
|
+
this.pipeline.textures.clear();
|
|
175
|
+
this.pipeline.samplers.clear();
|
|
176
|
+
this.pipeline.pipelineTemplates.clear();
|
|
177
|
+
this.pipeline.sceneResources.clear();
|
|
178
|
+
this.pipeline.adapter = void 0;
|
|
179
|
+
this.pipeline.device = void 0;
|
|
180
|
+
this.pipeline.context = void 0;
|
|
181
|
+
this.pipeline.format = void 0;
|
|
182
|
+
this.pipeline.defaultBindGroupLayout = void 0;
|
|
183
|
+
this.pipeline.baseMaterialBindGroupLayout = void 0;
|
|
184
|
+
this.pipeline.fallbackTexture = void 0;
|
|
185
|
+
device?.destroy();
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* 销毁 Geometry 所有绘制模式已经创建的全部缓冲。
|
|
189
|
+
* @param geometryBuffer Geometry GPU 缓存集合
|
|
190
|
+
* @returns 无返回值
|
|
191
|
+
*/
|
|
192
|
+
destroyGeometryBuffer(geometryBuffer) {
|
|
193
|
+
for (const entry of this.pipeline.buffers.meshMatrix.values()) if (entry.bindGroup?.geometry === geometryBuffer.uniform) entry.bindGroup = void 0;
|
|
194
|
+
const DestroyPart = (part) => {
|
|
195
|
+
part?.vertex.destroy();
|
|
196
|
+
part?.normal.destroy();
|
|
197
|
+
part?.uv.destroy();
|
|
198
|
+
part?.index.destroy();
|
|
199
|
+
part?.miterScale?.destroy();
|
|
200
|
+
part?.position?.destroy();
|
|
201
|
+
part?.vertexType?.destroy();
|
|
202
|
+
};
|
|
203
|
+
DestroyPart(geometryBuffer.geometry);
|
|
204
|
+
DestroyPart(geometryBuffer.linePoints);
|
|
205
|
+
geometryBuffer.uniform.destroy();
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* 解除引用某个纹理视图的缓存绑定,不影响其他 Mesh。
|
|
209
|
+
* @param view 即将销毁的 GPU 纹理视图
|
|
210
|
+
*/
|
|
211
|
+
releaseTextureBindings(view) {
|
|
212
|
+
for (const entry of this.pipeline.buffers.meshStyle.values()) {
|
|
213
|
+
const binding = entry.bindGroup;
|
|
214
|
+
if (binding?.baseView === view || binding?.edgeView === view || binding?.pointsView === view) entry.bindGroup = void 0;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
//#endregion
|
|
219
|
+
export { DestroyManager as default };
|
|
220
|
+
|
|
221
|
+
//# sourceMappingURL=DestroyManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DestroyManager.js","names":[],"sources":["../../src/scripts/Render/DestroyManager.ts"],"sourcesContent":["import type { GeoData } from \"../Geometry\";\nimport type { Material2d } from \"../global-types\";\nimport type { MeshLike } from \"../Mesh\";\nimport type Scene from \"../Scene\";\nimport type { TextureResource } from \"../Texture/Layers\";\nimport type {\n GeometryBufferLike,\n GeometryBufferPartLike,\n PipelineLike,\n SceneResourcesLike,\n} from \"./types\";\n\ninterface DestroyManagerLike {\n destroyMesh(mesh: MeshLike | number): boolean;\n destroyTexture(texture: TextureResource | number): boolean;\n destroyMaterial(material: Material2d | number): boolean;\n destroyGeometry(geometry: GeoData | number): boolean;\n trim(scene: Scene): void;\n destroyAll(): void;\n}\n\n/**\n * 统一负责当前 Render 的 GPU 资源销毁与无引用缓存回收。\n * @class\n */\nclass DestroyManager implements DestroyManagerLike {\n private readonly pipeline: PipelineLike;\n\n /**\n * 创建销毁管理器。\n * @param pipeline 当前 Render 的共享管线资源\n */\n public constructor(pipeline: PipelineLike) {\n this.pipeline = pipeline;\n }\n\n /**\n * 销毁指定 Mesh 的模型矩阵缓冲及可取得的关联资源。\n * @param mesh Mesh 对象或全局 ID\n * @returns 是否销毁了任意资源\n */\n public destroyMesh(mesh: MeshLike | number): boolean {\n const meshId: number = typeof mesh === \"number\" ? mesh : mesh.id;\n const matrixBuffer = this.pipeline.buffers.meshMatrix.get(meshId);\n let destroyed: boolean = false;\n\n if (matrixBuffer !== undefined) {\n matrixBuffer.buffer.destroy();\n this.pipeline.buffers.meshMatrix.delete(meshId);\n destroyed = true;\n }\n\n const depthBuffer = this.pipeline.buffers.meshDepth.get(meshId);\n if (depthBuffer !== undefined) {\n depthBuffer.buffer.destroy();\n this.pipeline.buffers.meshDepth.delete(meshId);\n destroyed = true;\n }\n const styleBuffer = this.pipeline.buffers.meshStyle.get(meshId);\n if (styleBuffer !== undefined) {\n styleBuffer.buffer.destroy();\n this.pipeline.buffers.meshStyle.delete(meshId);\n destroyed = true;\n }\n\n if (typeof mesh !== \"number\") {\n for (const texture of mesh.textures) {\n if (texture !== undefined) destroyed = this.destroyTexture(texture) || destroyed;\n }\n if (mesh.data !== undefined) {\n destroyed = this.destroyGeometry(mesh.data) || destroyed;\n }\n if (mesh.material !== undefined) {\n destroyed = this.destroyMaterial(mesh.material) || destroyed;\n }\n }\n\n return destroyed;\n }\n\n /**\n * 销毁指定 Texture 的 GPUTexture 缓存。\n * @param texture Texture 对象或全局 ID\n * @returns 是否找到并销毁了对应资源\n */\n public destroyTexture(texture: TextureResource | number): boolean {\n const textureId: number = typeof texture === \"number\" ? texture : texture.id;\n let destroyed: boolean = false;\n for (const [id, resource] of this.pipeline.textures) {\n if (id !== textureId && !resource.sourceIds?.has(textureId)) continue;\n this.releaseTextureBindings(resource.view);\n resource.texture.destroy();\n this.pipeline.textures.delete(id);\n destroyed = true;\n }\n return destroyed;\n }\n\n /**\n * 销毁所有关联此 Material 的 Mesh 实例样式缓冲,并在可取得对象时销毁其基础、边框和点型贴图。\n * @param material Material 对象或全局 ID\n * @returns 是否销毁了任意资源\n */\n public destroyMaterial(material: Material2d | number): boolean {\n const materialId: number = typeof material === \"number\" ? material : material.id;\n let destroyed: boolean = false;\n for (const [meshId, styleBuffer] of this.pipeline.buffers.meshStyle) {\n if (styleBuffer.materialId !== materialId) continue;\n styleBuffer.buffer.destroy();\n this.pipeline.buffers.meshStyle.delete(meshId);\n destroyed = true;\n }\n\n if (typeof material !== \"number\") {\n const textureIds: Set<number> = new Set<number>();\n\n if (material.style.solid.texture !== undefined) {\n textureIds.add(material.style.solid.texture.id);\n destroyed = this.destroyTexture(material.style.solid.texture) || destroyed;\n }\n if (material.style.edge.texture !== undefined && !textureIds.has(material.style.edge.texture.id)) {\n textureIds.add(material.style.edge.texture.id);\n destroyed = this.destroyTexture(material.style.edge.texture) || destroyed;\n }\n if (material.style.points.texture !== undefined && !textureIds.has(material.style.points.texture.id)) {\n destroyed = this.destroyTexture(material.style.points.texture) || destroyed;\n }\n }\n\n return destroyed;\n }\n\n /**\n * 销毁指定 Geometry 的全部 GPUBuffer。\n * @param geometry Geometry 对象或全局 ID\n * @returns 是否找到并销毁了对应资源\n */\n public destroyGeometry(geometry: GeoData | number): boolean {\n const geometryId: number = typeof geometry === \"number\" ? geometry : geometry.id;\n const geometryBuffer: GeometryBufferLike | undefined = this.pipeline.buffers.geometry.get(geometryId);\n\n if (geometryBuffer === undefined) {\n return false;\n }\n\n this.destroyGeometryBuffer(geometryBuffer);\n this.pipeline.buffers.geometry.delete(geometryId);\n return true;\n }\n\n /**\n * 更新场景资源使用记录并回收所有场景均未引用的缓存。\n * @param scene 需要同步资源记录的场景\n * @returns 无返回值\n */\n public trim(scene: Scene): void {\n scene.ensureLists();\n const sceneResources: SceneResourcesLike = {\n version: scene.version,\n meshIds: new Set<number>(),\n geometryIds: new Set<number>(),\n materialIds: new Set<number>(),\n textureIds: new Set<number>(),\n pipelineKeys: new Set<string>(),\n };\n\n for (const mesh of scene.drawList) sceneResources.meshIds.add(mesh.id);\n for (const geometry of scene.geometryList) sceneResources.geometryIds.add(geometry.id);\n for (const material of scene.materialList) {\n sceneResources.materialIds.add(material.id);\n }\n for (const mesh of scene.drawList) {\n if (mesh.data !== undefined && mesh.material !== undefined) {\n sceneResources.pipelineKeys.add(mesh.material.getPipelineKey(mesh.data.type));\n }\n }\n for (const texture of scene.textureList) sceneResources.textureIds.add(texture.id);\n\n this.pipeline.sceneResources.set(scene.id, sceneResources);\n\n const usedResources: SceneResourcesLike = {\n version: 0,\n meshIds: new Set<number>(),\n geometryIds: new Set<number>(),\n materialIds: new Set<number>(),\n textureIds: new Set<number>(),\n pipelineKeys: new Set<string>(),\n };\n\n for (const resources of this.pipeline.sceneResources.values()) {\n for (const id of resources.meshIds) usedResources.meshIds.add(id);\n for (const id of resources.geometryIds) usedResources.geometryIds.add(id);\n for (const id of resources.materialIds) usedResources.materialIds.add(id);\n for (const id of resources.textureIds) usedResources.textureIds.add(id);\n for (const key of resources.pipelineKeys) usedResources.pipelineKeys.add(key);\n }\n\n for (const matrixBuffer of this.pipeline.buffers.meshMatrix.values()) {\n if (!usedResources.meshIds.has(matrixBuffer.meshId)) this.destroyMesh(matrixBuffer.meshId);\n }\n for (const meshId of this.pipeline.buffers.meshDepth.keys()) {\n if (!usedResources.meshIds.has(meshId)) this.destroyMesh(meshId);\n }\n for (const geometryId of this.pipeline.buffers.geometry.keys()) {\n if (!usedResources.geometryIds.has(geometryId)) this.destroyGeometry(geometryId);\n }\n for (const meshId of this.pipeline.buffers.meshStyle.keys()) {\n if (!usedResources.meshIds.has(meshId)) this.destroyMesh(meshId);\n }\n for (const [textureId, texture] of this.pipeline.textures) {\n // trim 只清理这个资源;源图单层缓存闲置不代表其他层组也闲置。\n if (!usedResources.textureIds.has(textureId)) {\n this.releaseTextureBindings(texture.view);\n texture.texture.destroy();\n this.pipeline.textures.delete(textureId);\n }\n }\n for (const pipelineKey of this.pipeline.pipelineTemplates.keys()) {\n if (!usedResources.pipelineKeys.has(pipelineKey)) {\n // GPURenderPipeline 没有 destroy(),删除引用后交由浏览器回收。\n this.pipeline.pipelineTemplates.delete(pipelineKey);\n }\n }\n }\n\n /**\n * 销毁当前 Render 持有的全部 WebGPU 资源和设备。\n * @returns 无返回值\n */\n public destroyAll(): void {\n const device: GPUDevice | undefined = this.pipeline.device;\n\n this.pipeline.context?.unconfigure();\n\n for (const matrixBuffer of this.pipeline.buffers.meshMatrix.values()) matrixBuffer.buffer.destroy();\n // 全量销毁先清绑定,后续逐个释放几何时无需再扫描这些 Mesh。\n this.pipeline.buffers.meshMatrix.clear();\n for (const depthBuffer of this.pipeline.buffers.meshDepth.values()) depthBuffer.buffer.destroy();\n this.pipeline.depthTexture?.texture.destroy();\n this.pipeline.depthTexture = undefined;\n this.pipeline.buffers.meshDepth.clear();\n for (const geometryBuffer of this.pipeline.buffers.geometry.values()) {\n this.destroyGeometryBuffer(geometryBuffer);\n }\n for (const materialBuffer of this.pipeline.buffers.meshStyle.values()) materialBuffer.buffer.destroy();\n for (const cameraBuffer of this.pipeline.buffers.cameraUniform) cameraBuffer.destroy();\n for (const textureResource of this.pipeline.textures.values()) textureResource.texture.destroy();\n\n this.pipeline.fallbackTexture?.texture.destroy();\n this.pipeline.buffers.geometry.clear();\n this.pipeline.buffers.meshStyle.clear();\n this.pipeline.buffers.cameraUniform.length = 0;\n this.pipeline.textures.clear();\n this.pipeline.samplers.clear();\n this.pipeline.pipelineTemplates.clear();\n this.pipeline.sceneResources.clear();\n this.pipeline.adapter = undefined;\n this.pipeline.device = undefined;\n this.pipeline.context = undefined;\n this.pipeline.format = undefined;\n this.pipeline.defaultBindGroupLayout = undefined;\n this.pipeline.baseMaterialBindGroupLayout = undefined;\n this.pipeline.fallbackTexture = undefined;\n\n device?.destroy();\n }\n\n /**\n * 销毁 Geometry 所有绘制模式已经创建的全部缓冲。\n * @param geometryBuffer Geometry GPU 缓存集合\n * @returns 无返回值\n */\n private destroyGeometryBuffer(geometryBuffer: GeometryBufferLike): void {\n // BindGroup 没有 destroy(),解除引用即可;避免保留已销毁几何的绑定。\n for (const entry of this.pipeline.buffers.meshMatrix.values()) {\n if (entry.bindGroup?.geometry === geometryBuffer.uniform) entry.bindGroup = undefined;\n }\n const DestroyPart = (part: GeometryBufferPartLike | undefined): void => {\n part?.vertex.destroy();\n part?.normal.destroy();\n part?.uv.destroy();\n part?.index.destroy();\n part?.miterScale?.destroy();\n part?.position?.destroy();\n part?.vertexType?.destroy();\n };\n\n DestroyPart(geometryBuffer.geometry);\n DestroyPart(geometryBuffer.linePoints);\n geometryBuffer.uniform.destroy();\n }\n\n /**\n * 解除引用某个纹理视图的缓存绑定,不影响其他 Mesh。\n * @param view 即将销毁的 GPU 纹理视图\n */\n private releaseTextureBindings(view: GPUTextureView): void {\n for (const entry of this.pipeline.buffers.meshStyle.values()) {\n const binding = entry.bindGroup;\n if (binding?.baseView === view || binding?.edgeView === view || binding?.pointsView === view) {\n entry.bindGroup = undefined;\n }\n }\n }\n}\n\nexport default DestroyManager;\nexport type { DestroyManagerLike };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type Camera from "../Camera";
|
|
2
|
+
import type { GeoData } from "../Geometry";
|
|
3
|
+
import type { Material2d } from "../global-types";
|
|
4
|
+
import type { MeshLike } from "../Mesh";
|
|
5
|
+
interface DevelopmentValidatorLike {
|
|
6
|
+
validateCamera(camera: Camera): void;
|
|
7
|
+
validateMaterial(material: Material2d): void;
|
|
8
|
+
validateGeometry(geometry: GeoData): void;
|
|
9
|
+
validateMesh(mesh: MeshLike): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 开发模式 GPUBuffer 数据与渲染配置校验器。
|
|
13
|
+
* 只报告 TypeScript 无法约束的运行时数据问题,并按对象和问题类型去重。
|
|
14
|
+
* @class
|
|
15
|
+
*/
|
|
16
|
+
declare class DevelopmentValidator implements DevelopmentValidatorLike {
|
|
17
|
+
private readonly reported;
|
|
18
|
+
/**
|
|
19
|
+
* 检查 Camera 是否能生成有效矩阵与 Uniform。
|
|
20
|
+
* @param camera 当前 Camera
|
|
21
|
+
* @returns 无返回值
|
|
22
|
+
*/
|
|
23
|
+
validateCamera(camera: Camera): void;
|
|
24
|
+
/**
|
|
25
|
+
* 检查材质样式数据和分区配置。
|
|
26
|
+
* @param material 当前材质
|
|
27
|
+
* @returns 无返回值
|
|
28
|
+
*/
|
|
29
|
+
validateMaterial(material: Material2d): void;
|
|
30
|
+
/**
|
|
31
|
+
* 检查 Geometry 各缓冲分区的长度、有限值和索引范围。
|
|
32
|
+
* @param geometry 当前 Geometry
|
|
33
|
+
* @returns 无返回值
|
|
34
|
+
*/
|
|
35
|
+
validateGeometry(geometry: GeoData): void;
|
|
36
|
+
/**
|
|
37
|
+
* 检查 Mesh 的 Geometry 与 Material 是否能组成目标边框绘制模式。
|
|
38
|
+
* @param mesh 当前 Mesh
|
|
39
|
+
* @returns 无返回值
|
|
40
|
+
*/
|
|
41
|
+
validateMesh(mesh: MeshLike): void;
|
|
42
|
+
/**
|
|
43
|
+
* 检查单个几何缓冲分区。
|
|
44
|
+
* @param geometryId Geometry ID
|
|
45
|
+
* @param name 缓冲分区名
|
|
46
|
+
* @param data CPU 几何数据
|
|
47
|
+
* @param primitiveSize 每个图元使用的索引数
|
|
48
|
+
* @param requireMiterScale 是否要求 miterScale
|
|
49
|
+
* @param source 日志附带对象
|
|
50
|
+
* @returns 无返回值
|
|
51
|
+
*/
|
|
52
|
+
private validatePart;
|
|
53
|
+
/**
|
|
54
|
+
* 输出一次开发模式警告。
|
|
55
|
+
* @param code 问题代码
|
|
56
|
+
* @param objectId 对象 ID
|
|
57
|
+
* @param message 问题说明
|
|
58
|
+
* @param source 关联对象
|
|
59
|
+
* @returns 无返回值
|
|
60
|
+
*/
|
|
61
|
+
private warn;
|
|
62
|
+
/**
|
|
63
|
+
* 输出一次开发模式错误。
|
|
64
|
+
* @param code 问题代码
|
|
65
|
+
* @param objectId 对象 ID
|
|
66
|
+
* @param message 问题说明
|
|
67
|
+
* @param source 关联对象
|
|
68
|
+
* @returns 无返回值
|
|
69
|
+
*/
|
|
70
|
+
private error;
|
|
71
|
+
}
|
|
72
|
+
export default DevelopmentValidator;
|
|
73
|
+
export type { DevelopmentValidatorLike };
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import IMesh from "../IMesh/index.js";
|
|
2
|
+
//#region src/scripts/Render/DevelopmentValidator.ts
|
|
3
|
+
/**
|
|
4
|
+
* 开发模式 GPUBuffer 数据与渲染配置校验器。
|
|
5
|
+
* 只报告 TypeScript 无法约束的运行时数据问题,并按对象和问题类型去重。
|
|
6
|
+
* @class
|
|
7
|
+
*/
|
|
8
|
+
var DevelopmentValidator = class {
|
|
9
|
+
reported = /* @__PURE__ */ new Set();
|
|
10
|
+
/**
|
|
11
|
+
* 检查 Camera 是否能生成有效矩阵与 Uniform。
|
|
12
|
+
* @param camera 当前 Camera
|
|
13
|
+
* @returns 无返回值
|
|
14
|
+
*/
|
|
15
|
+
validateCamera(camera) {
|
|
16
|
+
if (!Number.isFinite(camera.width) || camera.width <= 0) this.error("CAMERA_WIDTH", camera.id, "Camera width 必须是大于 0 的有限数。", camera);
|
|
17
|
+
if (!Number.isFinite(camera.height) || camera.height <= 0) this.error("CAMERA_HEIGHT", camera.id, "Camera height 必须是大于 0 的有限数。", camera);
|
|
18
|
+
if (!Number.isFinite(camera.zoom) || camera.zoom <= 0) this.error("CAMERA_ZOOM", camera.id, "Camera zoom 必须是大于 0 的有限数。", camera);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 检查材质样式数据和分区配置。
|
|
22
|
+
* @param material 当前材质
|
|
23
|
+
* @returns 无返回值
|
|
24
|
+
*/
|
|
25
|
+
validateMaterial(material) {
|
|
26
|
+
if (material.transparent && material.depthWrite) this.warn("TRANSPARENT_DEPTH_WRITE", material.id, "透明混合同时写入深度可能挡住后方透明片元;通常使用 depthTest=true、depthWrite=false。", material);
|
|
27
|
+
if (!material.depthTest && material.depthWrite) this.warn("DEPTH_WRITE_WITHOUT_TEST", material.id, "已关闭深度测试但仍写深度;它不会检查场景遮挡,通常 UI 两项都关闭。", material);
|
|
28
|
+
const { solid, wireframe, edge, points } = material.style;
|
|
29
|
+
for (const part of [
|
|
30
|
+
solid,
|
|
31
|
+
wireframe,
|
|
32
|
+
edge,
|
|
33
|
+
points
|
|
34
|
+
]) if (!Number.isFinite(part.opacity) || part.opacity < 0 || part.opacity > 1) this.error("STYLE_OPACITY_" + part.area, material.id, "分区透明度必须位于 0 到 1。", material);
|
|
35
|
+
for (const part of [
|
|
36
|
+
solid,
|
|
37
|
+
edge,
|
|
38
|
+
points
|
|
39
|
+
]) if (part.texture !== void 0 && !part.enabled) this.warn("UNUSED_TEXTURE_" + part.area, material.id, "分区已设置贴图,但 enabled 尚未开启。", material);
|
|
40
|
+
if (points.enabled && !points.vertices && !points.midpoints) this.warn("EMPTY_POINT_SELECTION", material.id, "关键点已开启,但未选择顶点或边中点;不会生成点型。", material);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* 检查 Geometry 各缓冲分区的长度、有限值和索引范围。
|
|
44
|
+
* @param geometry 当前 Geometry
|
|
45
|
+
* @returns 无返回值
|
|
46
|
+
*/
|
|
47
|
+
validateGeometry(geometry) {
|
|
48
|
+
if (geometry.geometry !== void 0) {
|
|
49
|
+
if (geometry.normal === void 0 || geometry.uv === void 0 || geometry.index === void 0 || geometry.vertexType === void 0 || geometry.position === void 0 || geometry.miterScale === void 0) this.error("GEOMETRY_MISSING", geometry.id, "合并三角面缺少 normal、uv、index、vertexType、position 或 miterScale。", geometry);
|
|
50
|
+
else {
|
|
51
|
+
const vertexCount = geometry.geometry.length / 2;
|
|
52
|
+
this.validatePart(geometry.id, "geometry", {
|
|
53
|
+
geometry: geometry.geometry,
|
|
54
|
+
normal: geometry.normal,
|
|
55
|
+
uv: geometry.uv,
|
|
56
|
+
index: geometry.index,
|
|
57
|
+
miterScale: geometry.miterScale
|
|
58
|
+
}, 3, true, geometry);
|
|
59
|
+
if (geometry.vertexType.length !== vertexCount || geometry.vertexType.some((value) => value !== 0 && value !== .5 && value !== 1)) this.error("VERTEX_TYPE", geometry.id, "vertexType 必须逐顶点对应,且只能为 0、0.5、1。", geometry);
|
|
60
|
+
if (geometry.position.length !== geometry.geometry.length || GetInvalidNumberIndex(geometry.position) !== -1) this.error("GEOMETRY_POSITION", geometry.id, "position 必须与 geometry 等长且全部为有限数。", geometry);
|
|
61
|
+
for (let offset = 0; offset < geometry.index.length; offset += 3) {
|
|
62
|
+
const type = geometry.vertexType[geometry.index[offset]];
|
|
63
|
+
if (geometry.vertexType[geometry.index[offset + 1]] !== type || geometry.vertexType[geometry.index[offset + 2]] !== type) {
|
|
64
|
+
this.error("TRIANGLE_VERTEX_TYPE", geometry.id, "一个三角面的三个顶点必须属于同一 vertexType。", geometry);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (geometry.linePoints !== void 0) this.validatePart(geometry.id, "linePoints", geometry.linePoints, 2, false, geometry);
|
|
71
|
+
if (geometry.style.wireframe.enabled && geometry.linePoints === void 0) this.error("WIREFRAME_DATA", geometry.id, "Geometry wireframe 已开启,但没有生成 linePoints。", geometry);
|
|
72
|
+
if (geometry.style.edge.uvRepeat !== 1 && !geometry.style.wireframe.enabled && !geometry.style.edge.enabled) this.warn("UNUSED_UV_REPEAT", geometry.id, "uvRepeat 只作用于边框,当前值不会被使用。", geometry);
|
|
73
|
+
if (geometry.uniformData.length !== 4 || GetInvalidNumberIndex(geometry.uniformData) !== -1) this.error("GEOMETRY_UNIFORM", geometry.id, "Geometry uniformData 必须包含 4 个有限数。", geometry);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 检查 Mesh 的 Geometry 与 Material 是否能组成目标边框绘制模式。
|
|
77
|
+
* @param mesh 当前 Mesh
|
|
78
|
+
* @returns 无返回值
|
|
79
|
+
*/
|
|
80
|
+
validateMesh(mesh) {
|
|
81
|
+
const geometry = mesh.data;
|
|
82
|
+
const material = mesh.material;
|
|
83
|
+
if (geometry === void 0 || material === void 0) {
|
|
84
|
+
this.error("MESH_RESOURCE", mesh.id, "Mesh 缺少 Geometry 或 Material。", mesh);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (geometry.style.solid.enabled && geometry.type !== "Rect2d" && geometry.type !== "Poly2D") this.error("UNSUPPORTED_SOLID_TYPE", mesh.id, "未提供该类型的实体面 Shader。", mesh);
|
|
88
|
+
if (mesh instanceof IMesh) {
|
|
89
|
+
if (geometry.style.wireframe.enabled && mesh.count > 1) this.warn("IMESH_NATIVE_LINES", mesh.id, "原生 line-list 使用逐实例顺序回退;只用三角面时才合并为一次绘制。", mesh);
|
|
90
|
+
for (const raw of mesh.raws.map.values()) {
|
|
91
|
+
if (geometry.type === "Poly2D" && raw.style.solid.borderWidth > 0) this.warn("POLY_SDF_BORDER", mesh.id, "Poly2D 不使用矩形 SDF 边框,请启用 edge 分区。", mesh);
|
|
92
|
+
if (geometry.type === "Poly2D" && (raw.style.join.type !== geometry.style.join.type || raw.style.join.seg !== geometry.style.join.seg)) this.warn("IMESH_JOIN_TEMPLATE", mesh.id, "连接类型和精度由 Geometry.style.join 决定,Raw 不生成独立拓扑。", mesh);
|
|
93
|
+
for (const area of [
|
|
94
|
+
"solid",
|
|
95
|
+
"wireframe",
|
|
96
|
+
"edge",
|
|
97
|
+
"points"
|
|
98
|
+
]) if (raw.style[area].enabled && !geometry.style[area].enabled) this.warn("IMESH_MISSING_" + area, mesh.id, "实例启用了模板未生成的 " + area + " 分区;请先配置 Geometry.style。", mesh);
|
|
99
|
+
for (const area of [
|
|
100
|
+
"solid",
|
|
101
|
+
"edge",
|
|
102
|
+
"points"
|
|
103
|
+
]) if (raw.style[area].addressModeU !== material.style[area].addressModeU || raw.style[area].addressModeV !== material.style[area].addressModeV) this.warn("IMESH_SAMPLER_" + area, mesh.id, "一次绘制共用 Material.style 的采样器,Raw.style 的寻址方式不单独生效。", mesh);
|
|
104
|
+
if (raw.style.edge.enabled && (raw.style.edge.width !== geometry.style.edge.width || raw.style.edge.uvRepeat !== geometry.style.edge.uvRepeat)) this.warn("IMESH_EDGE_TEMPLATE", mesh.id, "实例实体边框宽度和 UV Repeat 由共用 Geometry.style 生成,Raw 不重建独立几何。", mesh);
|
|
105
|
+
if (raw.style.points.enabled && (raw.style.points.radius !== geometry.style.points.radius || raw.style.points.segments !== geometry.style.points.segments || raw.style.points.vertices !== geometry.style.points.vertices || raw.style.points.midpoints !== geometry.style.points.midpoints || raw.style.points.minPointsLength !== geometry.style.points.minPointsLength || raw.style.points.minEdgePointsLength !== geometry.style.points.minEdgePointsLength)) this.warn("IMESH_POINTS_TEMPLATE", mesh.id, "关键点半径、段数、选择规则由共用 Geometry.style 决定。", mesh);
|
|
106
|
+
}
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (geometry.type === "Poly2D" && material.style.solid.borderWidth > 0) this.warn("POLY_SDF_BORDER", mesh.id, "Poly2D 不使用矩形 SDF 边框,请启用 edge 分区。", mesh);
|
|
110
|
+
if (geometry.type === "Poly2D" && (geometry.style.join.type !== material.style.join.type || geometry.style.join.seg !== material.style.join.seg)) this.warn("POLY_JOIN_STYLE", mesh.id, "连接拓扑由 Geometry.style.join 生成,建议几何与材质共享 Style。", mesh);
|
|
111
|
+
for (const area of [
|
|
112
|
+
"solid",
|
|
113
|
+
"wireframe",
|
|
114
|
+
"edge",
|
|
115
|
+
"points"
|
|
116
|
+
]) if (geometry.style[area].enabled !== material.style[area].enabled) this.warn("STYLE_ENABLED_" + area, mesh.id, "几何与材质的分区开关不同;建议引用同一个 Style。", mesh);
|
|
117
|
+
if (geometry.style !== material.style && geometry.style.edge.enabled && (geometry.style.edge.width !== material.style.edge.width || geometry.style.edge.borderAlign !== material.style.edge.borderAlign)) this.warn("STYLE_EDGE_PARAMETERS", mesh.id, "几何与材质的实体边框参数不同;几何宽度参与生成,建议共享 Style。", mesh);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 检查单个几何缓冲分区。
|
|
121
|
+
* @param geometryId Geometry ID
|
|
122
|
+
* @param name 缓冲分区名
|
|
123
|
+
* @param data CPU 几何数据
|
|
124
|
+
* @param primitiveSize 每个图元使用的索引数
|
|
125
|
+
* @param requireMiterScale 是否要求 miterScale
|
|
126
|
+
* @param source 日志附带对象
|
|
127
|
+
* @returns 无返回值
|
|
128
|
+
*/
|
|
129
|
+
validatePart(geometryId, name, data, primitiveSize, requireMiterScale, source) {
|
|
130
|
+
const vertexCount = data.geometry.length / 2;
|
|
131
|
+
if (data.geometry.length % 2 !== 0) this.error("GEOMETRY_VERTEX_" + name, geometryId, name + " 顶点数组长度必须是 2 的倍数。", source);
|
|
132
|
+
if (data.normal.length !== data.geometry.length) this.error("GEOMETRY_NORMAL_" + name, geometryId, name + " 法线数量必须与顶点数量一致。", source);
|
|
133
|
+
if (data.uv.length !== data.geometry.length) this.error("GEOMETRY_UV_" + name, geometryId, name + " UV 数量必须与顶点数量一致。", source);
|
|
134
|
+
if (data.index.length % primitiveSize !== 0) this.error("GEOMETRY_INDEX_COUNT_" + name, geometryId, name + " 索引数量与图元类型不匹配。", source);
|
|
135
|
+
if (data.geometry.length === 0 || data.index.length === 0) this.warn("EMPTY_GEOMETRY_" + name, geometryId, name + " 不包含可绘制图元。", source);
|
|
136
|
+
if (GetInvalidNumberIndex(data.geometry) !== -1 || GetInvalidNumberIndex(data.normal) !== -1 || GetInvalidNumberIndex(data.uv) !== -1) this.error("GEOMETRY_NUMBER_" + name, geometryId, name + " 包含 NaN 或 Infinity。", source);
|
|
137
|
+
for (const index of data.index) if (index >= vertexCount) {
|
|
138
|
+
this.error("GEOMETRY_INDEX_RANGE_" + name, geometryId, name + " 存在越界索引 " + String(index) + "。", source);
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
if (requireMiterScale && data.miterScale === void 0) this.error("GEOMETRY_MITER_MISSING_" + name, geometryId, name + " 缺少 miterScale。", source);
|
|
142
|
+
else if (data.miterScale !== void 0) {
|
|
143
|
+
if (data.miterScale.length !== vertexCount) this.error("GEOMETRY_MITER_COUNT_" + name, geometryId, name + " miterScale 数量必须与顶点数量一致。", source);
|
|
144
|
+
if (GetInvalidNumberIndex(data.miterScale) !== -1) this.error("GEOMETRY_MITER_NUMBER_" + name, geometryId, name + " miterScale 包含 NaN 或 Infinity。", source);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 输出一次开发模式警告。
|
|
149
|
+
* @param code 问题代码
|
|
150
|
+
* @param objectId 对象 ID
|
|
151
|
+
* @param message 问题说明
|
|
152
|
+
* @param source 关联对象
|
|
153
|
+
* @returns 无返回值
|
|
154
|
+
*/
|
|
155
|
+
warn(code, objectId, message, source) {
|
|
156
|
+
const key = "warn_" + code + "_" + String(objectId);
|
|
157
|
+
if (this.reported.has(key)) return;
|
|
158
|
+
this.reported.add(key);
|
|
159
|
+
console.warn("[BPLineJS:" + code + "] " + message, source);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* 输出一次开发模式错误。
|
|
163
|
+
* @param code 问题代码
|
|
164
|
+
* @param objectId 对象 ID
|
|
165
|
+
* @param message 问题说明
|
|
166
|
+
* @param source 关联对象
|
|
167
|
+
* @returns 无返回值
|
|
168
|
+
*/
|
|
169
|
+
error(code, objectId, message, source) {
|
|
170
|
+
const key = "error_" + code + "_" + String(objectId);
|
|
171
|
+
if (this.reported.has(key)) return;
|
|
172
|
+
this.reported.add(key);
|
|
173
|
+
console.error("[BPLineJS:" + code + "] " + message, source);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* 获取数组中首个非有限数索引。
|
|
178
|
+
* @param data 待检查数值数组
|
|
179
|
+
* @returns 非有限数索引,全部有效时返回 -1
|
|
180
|
+
*/
|
|
181
|
+
var GetInvalidNumberIndex = (data) => {
|
|
182
|
+
for (let index = 0; index < data.length; index += 1) if (!Number.isFinite(data[index])) return index;
|
|
183
|
+
return -1;
|
|
184
|
+
};
|
|
185
|
+
//#endregion
|
|
186
|
+
export { DevelopmentValidator as default };
|
|
187
|
+
|
|
188
|
+
//# sourceMappingURL=DevelopmentValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DevelopmentValidator.js","names":[],"sources":["../../src/scripts/Render/DevelopmentValidator.ts"],"sourcesContent":["import IMesh from \"../IMesh\";\nimport type Camera from \"../Camera\";\nimport type { GeoData, GeoPartDataLike } from \"../Geometry\";\nimport type { Material2d } from \"../global-types\";\nimport type { MeshLike } from \"../Mesh\";\n\ninterface DevelopmentValidatorLike {\n validateCamera(camera: Camera): void;\n validateMaterial(material: Material2d): void;\n validateGeometry(geometry: GeoData): void;\n validateMesh(mesh: MeshLike): void;\n}\n\n/**\n * 开发模式 GPUBuffer 数据与渲染配置校验器。\n * 只报告 TypeScript 无法约束的运行时数据问题,并按对象和问题类型去重。\n * @class\n */\nclass DevelopmentValidator implements DevelopmentValidatorLike {\n private readonly reported: Set<string> = new Set<string>();\n\n /**\n * 检查 Camera 是否能生成有效矩阵与 Uniform。\n * @param camera 当前 Camera\n * @returns 无返回值\n */\n public validateCamera(camera: Camera): void {\n if (!Number.isFinite(camera.width) || camera.width <= 0) {\n this.error(\"CAMERA_WIDTH\", camera.id, \"Camera width 必须是大于 0 的有限数。\", camera);\n }\n if (!Number.isFinite(camera.height) || camera.height <= 0) {\n this.error(\"CAMERA_HEIGHT\", camera.id, \"Camera height 必须是大于 0 的有限数。\", camera);\n }\n if (!Number.isFinite(camera.zoom) || camera.zoom <= 0) {\n this.error(\"CAMERA_ZOOM\", camera.id, \"Camera zoom 必须是大于 0 的有限数。\", camera);\n }\n }\n\n /**\n * 检查材质样式数据和分区配置。\n * @param material 当前材质\n * @returns 无返回值\n */\n public validateMaterial(material: Material2d): void {\n if (material.transparent && material.depthWrite) {\n this.warn(\"TRANSPARENT_DEPTH_WRITE\", material.id, \"透明混合同时写入深度可能挡住后方透明片元;通常使用 depthTest=true、depthWrite=false。\", material);\n }\n if (!material.depthTest && material.depthWrite) {\n this.warn(\"DEPTH_WRITE_WITHOUT_TEST\", material.id, \"已关闭深度测试但仍写深度;它不会检查场景遮挡,通常 UI 两项都关闭。\", material);\n }\n const { solid, wireframe, edge, points } = material.style;\n for (const part of [solid, wireframe, edge, points]) {\n if (!Number.isFinite(part.opacity) || part.opacity < 0 || part.opacity > 1) {\n this.error(\"STYLE_OPACITY_\" + part.area, material.id, \"分区透明度必须位于 0 到 1。\", material);\n }\n }\n for (const part of [solid, edge, points]) {\n if (part.texture !== undefined && !part.enabled) {\n this.warn(\"UNUSED_TEXTURE_\" + part.area, material.id, \"分区已设置贴图,但 enabled 尚未开启。\", material);\n }\n }\n if (points.enabled && !points.vertices && !points.midpoints) {\n this.warn(\"EMPTY_POINT_SELECTION\", material.id, \"关键点已开启,但未选择顶点或边中点;不会生成点型。\", material);\n }\n }\n\n /**\n * 检查 Geometry 各缓冲分区的长度、有限值和索引范围。\n * @param geometry 当前 Geometry\n * @returns 无返回值\n */\n public validateGeometry(geometry: GeoData): void {\n if (geometry.geometry !== undefined) {\n if (geometry.normal === undefined || geometry.uv === undefined || geometry.index === undefined\n || geometry.vertexType === undefined || geometry.position === undefined || geometry.miterScale === undefined) {\n this.error(\"GEOMETRY_MISSING\", geometry.id, \"合并三角面缺少 normal、uv、index、vertexType、position 或 miterScale。\", geometry);\n } else {\n const vertexCount: number = geometry.geometry.length / 2;\n this.validatePart(geometry.id, \"geometry\", {\n geometry: geometry.geometry, normal: geometry.normal, uv: geometry.uv,\n index: geometry.index, miterScale: geometry.miterScale,\n }, 3, true, geometry);\n if (geometry.vertexType.length !== vertexCount\n || geometry.vertexType.some((value: number): boolean => value !== 0 && value !== 0.5 && value !== 1)) {\n this.error(\"VERTEX_TYPE\", geometry.id, \"vertexType 必须逐顶点对应,且只能为 0、0.5、1。\", geometry);\n }\n if (geometry.position.length !== geometry.geometry.length || GetInvalidNumberIndex(geometry.position) !== -1) {\n this.error(\"GEOMETRY_POSITION\", geometry.id, \"position 必须与 geometry 等长且全部为有限数。\", geometry);\n }\n for (let offset: number = 0; offset < geometry.index.length; offset += 3) {\n const type: number = geometry.vertexType[geometry.index[offset]];\n if (geometry.vertexType[geometry.index[offset + 1]] !== type || geometry.vertexType[geometry.index[offset + 2]] !== type) {\n this.error(\"TRIANGLE_VERTEX_TYPE\", geometry.id, \"一个三角面的三个顶点必须属于同一 vertexType。\", geometry);\n break;\n }\n }\n }\n }\n if (geometry.linePoints !== undefined) {\n this.validatePart(geometry.id, \"linePoints\", geometry.linePoints, 2, false, geometry);\n }\n if (geometry.style.wireframe.enabled && geometry.linePoints === undefined) {\n this.error(\"WIREFRAME_DATA\", geometry.id, \"Geometry wireframe 已开启,但没有生成 linePoints。\", geometry);\n }\n if (geometry.style.edge.uvRepeat !== 1 && !geometry.style.wireframe.enabled && !geometry.style.edge.enabled) {\n this.warn(\"UNUSED_UV_REPEAT\", geometry.id, \"uvRepeat 只作用于边框,当前值不会被使用。\", geometry);\n }\n if (geometry.uniformData.length !== 4 || GetInvalidNumberIndex(geometry.uniformData) !== -1) {\n this.error(\"GEOMETRY_UNIFORM\", geometry.id, \"Geometry uniformData 必须包含 4 个有限数。\", geometry);\n }\n }\n\n /**\n * 检查 Mesh 的 Geometry 与 Material 是否能组成目标边框绘制模式。\n * @param mesh 当前 Mesh\n * @returns 无返回值\n */\n public validateMesh(mesh: MeshLike): void {\n const geometry = mesh.data;\n const material = mesh.material;\n\n if (geometry === undefined || material === undefined) {\n this.error(\"MESH_RESOURCE\", mesh.id, \"Mesh 缺少 Geometry 或 Material。\", mesh);\n return;\n }\n\n if (geometry.style.solid.enabled && geometry.type !== \"Rect2d\" && geometry.type !== \"Poly2D\") {\n this.error(\"UNSUPPORTED_SOLID_TYPE\", mesh.id, \"未提供该类型的实体面 Shader。\", mesh);\n }\n if (mesh instanceof IMesh) {\n if (geometry.style.wireframe.enabled && mesh.count > 1) {\n this.warn(\"IMESH_NATIVE_LINES\", mesh.id, \"原生 line-list 使用逐实例顺序回退;只用三角面时才合并为一次绘制。\", mesh);\n }\n for (const raw of mesh.raws.map.values()) {\n if (geometry.type === \"Poly2D\" && raw.style.solid.borderWidth > 0) {\n this.warn(\"POLY_SDF_BORDER\", mesh.id, \"Poly2D 不使用矩形 SDF 边框,请启用 edge 分区。\", mesh);\n }\n if (geometry.type === \"Poly2D\" && (raw.style.join.type !== geometry.style.join.type || raw.style.join.seg !== geometry.style.join.seg)) {\n this.warn(\"IMESH_JOIN_TEMPLATE\", mesh.id, \"连接类型和精度由 Geometry.style.join 决定,Raw 不生成独立拓扑。\", mesh);\n }\n for (const area of [\"solid\", \"wireframe\", \"edge\", \"points\"] as const) {\n if (raw.style[area].enabled && !geometry.style[area].enabled) {\n this.warn(\"IMESH_MISSING_\" + area, mesh.id, \"实例启用了模板未生成的 \" + area + \" 分区;请先配置 Geometry.style。\", mesh);\n }\n }\n for (const area of [\"solid\", \"edge\", \"points\"] as const) {\n if (raw.style[area].addressModeU !== material.style[area].addressModeU\n || raw.style[area].addressModeV !== material.style[area].addressModeV) {\n this.warn(\"IMESH_SAMPLER_\" + area, mesh.id, \"一次绘制共用 Material.style 的采样器,Raw.style 的寻址方式不单独生效。\", mesh);\n }\n }\n if (raw.style.edge.enabled && (raw.style.edge.width !== geometry.style.edge.width\n || raw.style.edge.uvRepeat !== geometry.style.edge.uvRepeat)) {\n this.warn(\"IMESH_EDGE_TEMPLATE\", mesh.id, \"实例实体边框宽度和 UV Repeat 由共用 Geometry.style 生成,Raw 不重建独立几何。\", mesh);\n }\n if (raw.style.points.enabled && (raw.style.points.radius !== geometry.style.points.radius\n || raw.style.points.segments !== geometry.style.points.segments\n || raw.style.points.vertices !== geometry.style.points.vertices\n || raw.style.points.midpoints !== geometry.style.points.midpoints\n || raw.style.points.minPointsLength !== geometry.style.points.minPointsLength\n || raw.style.points.minEdgePointsLength !== geometry.style.points.minEdgePointsLength)) {\n this.warn(\"IMESH_POINTS_TEMPLATE\", mesh.id, \"关键点半径、段数、选择规则由共用 Geometry.style 决定。\", mesh);\n }\n }\n return;\n }\n if (geometry.type === \"Poly2D\" && material.style.solid.borderWidth > 0) {\n this.warn(\"POLY_SDF_BORDER\", mesh.id, \"Poly2D 不使用矩形 SDF 边框,请启用 edge 分区。\", mesh);\n }\n if (geometry.type === \"Poly2D\" && (geometry.style.join.type !== material.style.join.type || geometry.style.join.seg !== material.style.join.seg)) {\n this.warn(\"POLY_JOIN_STYLE\", mesh.id, \"连接拓扑由 Geometry.style.join 生成,建议几何与材质共享 Style。\", mesh);\n }\n for (const area of [\"solid\", \"wireframe\", \"edge\", \"points\"] as const) {\n if (geometry.style[area].enabled !== material.style[area].enabled) {\n this.warn(\"STYLE_ENABLED_\" + area, mesh.id, \"几何与材质的分区开关不同;建议引用同一个 Style。\", mesh);\n }\n }\n if (geometry.style !== material.style && geometry.style.edge.enabled\n && (geometry.style.edge.width !== material.style.edge.width\n || geometry.style.edge.borderAlign !== material.style.edge.borderAlign)) {\n this.warn(\"STYLE_EDGE_PARAMETERS\", mesh.id, \"几何与材质的实体边框参数不同;几何宽度参与生成,建议共享 Style。\", mesh);\n }\n }\n\n /**\n * 检查单个几何缓冲分区。\n * @param geometryId Geometry ID\n * @param name 缓冲分区名\n * @param data CPU 几何数据\n * @param primitiveSize 每个图元使用的索引数\n * @param requireMiterScale 是否要求 miterScale\n * @param source 日志附带对象\n * @returns 无返回值\n */\n private validatePart(\n geometryId: number,\n name: string,\n data: GeoPartDataLike,\n primitiveSize: 2 | 3,\n requireMiterScale: boolean,\n source: object,\n ): void {\n const vertexCount: number = data.geometry.length / 2;\n\n if (data.geometry.length % 2 !== 0) {\n this.error(\"GEOMETRY_VERTEX_\" + name, geometryId, name + \" 顶点数组长度必须是 2 的倍数。\", source);\n }\n if (data.normal.length !== data.geometry.length) {\n this.error(\"GEOMETRY_NORMAL_\" + name, geometryId, name + \" 法线数量必须与顶点数量一致。\", source);\n }\n if (data.uv.length !== data.geometry.length) {\n this.error(\"GEOMETRY_UV_\" + name, geometryId, name + \" UV 数量必须与顶点数量一致。\", source);\n }\n if (data.index.length % primitiveSize !== 0) {\n this.error(\"GEOMETRY_INDEX_COUNT_\" + name, geometryId, name + \" 索引数量与图元类型不匹配。\", source);\n }\n if (data.geometry.length === 0 || data.index.length === 0) {\n this.warn(\"EMPTY_GEOMETRY_\" + name, geometryId, name + \" 不包含可绘制图元。\", source);\n }\n if (\n GetInvalidNumberIndex(data.geometry) !== -1\n || GetInvalidNumberIndex(data.normal) !== -1\n || GetInvalidNumberIndex(data.uv) !== -1\n ) {\n this.error(\"GEOMETRY_NUMBER_\" + name, geometryId, name + \" 包含 NaN 或 Infinity。\", source);\n }\n\n for (const index of data.index) {\n if (index >= vertexCount) {\n this.error(\"GEOMETRY_INDEX_RANGE_\" + name, geometryId, name + \" 存在越界索引 \" + String(index) + \"。\", source);\n break;\n }\n }\n\n if (requireMiterScale && data.miterScale === undefined) {\n this.error(\"GEOMETRY_MITER_MISSING_\" + name, geometryId, name + \" 缺少 miterScale。\", source);\n } else if (data.miterScale !== undefined) {\n if (data.miterScale.length !== vertexCount) {\n this.error(\"GEOMETRY_MITER_COUNT_\" + name, geometryId, name + \" miterScale 数量必须与顶点数量一致。\", source);\n }\n if (GetInvalidNumberIndex(data.miterScale) !== -1) {\n this.error(\"GEOMETRY_MITER_NUMBER_\" + name, geometryId, name + \" miterScale 包含 NaN 或 Infinity。\", source);\n }\n }\n }\n\n /**\n * 输出一次开发模式警告。\n * @param code 问题代码\n * @param objectId 对象 ID\n * @param message 问题说明\n * @param source 关联对象\n * @returns 无返回值\n */\n private warn(code: string, objectId: number, message: string, source: object): void {\n const key: string = \"warn_\" + code + \"_\" + String(objectId);\n\n if (this.reported.has(key)) {\n return;\n }\n\n this.reported.add(key);\n console.warn(\"[BPLineJS:\" + code + \"] \" + message, source);\n }\n\n /**\n * 输出一次开发模式错误。\n * @param code 问题代码\n * @param objectId 对象 ID\n * @param message 问题说明\n * @param source 关联对象\n * @returns 无返回值\n */\n private error(code: string, objectId: number, message: string, source: object): void {\n const key: string = \"error_\" + code + \"_\" + String(objectId);\n\n if (this.reported.has(key)) {\n return;\n }\n\n this.reported.add(key);\n console.error(\"[BPLineJS:\" + code + \"] \" + message, source);\n }\n}\n\n/**\n * 获取数组中首个非有限数索引。\n * @param data 待检查数值数组\n * @returns 非有限数索引,全部有效时返回 -1\n */\nconst GetInvalidNumberIndex = (data: ArrayLike<number>): number => {\n for (let index = 0; index < data.length; index += 1) {\n if (!Number.isFinite(data[index])) {\n return index;\n }\n }\n\n return -1;\n};\n\nexport default DevelopmentValidator;\nexport type { DevelopmentValidatorLike };\n"],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type Scene from "../Scene";
|
|
2
|
+
import SamplerManager from "./SamplerManager";
|
|
3
|
+
import type { PipelineLike } from "./types";
|
|
4
|
+
interface DrawCallManagerLike {
|
|
5
|
+
prepare(width: number, height: number): void;
|
|
6
|
+
draw(scene: Scene, backgroundColor: GPUColorDict, alphaMode: GPUCanvasAlphaMode): void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 负责编码 BindGroup、DrawCall 并向 GPUQueue 提交命令。
|
|
10
|
+
* @class
|
|
11
|
+
*/
|
|
12
|
+
declare class DrawCallManager implements DrawCallManagerLike {
|
|
13
|
+
private readonly pipeline;
|
|
14
|
+
private readonly samplerManager;
|
|
15
|
+
private readonly depthManager;
|
|
16
|
+
/**
|
|
17
|
+
* 创建 DrawCall 管理器。
|
|
18
|
+
* @param pipeline 当前 Render 的共享管线资源
|
|
19
|
+
* @param samplerManager Sampler 管理器
|
|
20
|
+
*/
|
|
21
|
+
constructor(pipeline: PipelineLike, samplerManager: SamplerManager);
|
|
22
|
+
/**
|
|
23
|
+
* warmup 只创建深度附件,不提交绘制。
|
|
24
|
+
* @param width 画布物理像素宽度
|
|
25
|
+
* @param height 画布物理像素高度
|
|
26
|
+
*/
|
|
27
|
+
prepare(width: number, height: number): void;
|
|
28
|
+
/**
|
|
29
|
+
* 编码并提交当前场景的基础绘制命令。
|
|
30
|
+
* @param scene 场景对象
|
|
31
|
+
* @param backgroundColor 清空画布使用的 RGBA 颜色
|
|
32
|
+
* @param alphaMode Canvas Alpha 合成方式
|
|
33
|
+
* @returns 无返回值
|
|
34
|
+
*/
|
|
35
|
+
draw(scene: Scene, backgroundColor: GPUColorDict, alphaMode: GPUCanvasAlphaMode): void;
|
|
36
|
+
/**
|
|
37
|
+
* 编码单个 Mesh 的资源绑定与索引绘制命令。
|
|
38
|
+
* @param device 当前 WebGPU 设备
|
|
39
|
+
* @param renderPass 当前 RenderPass
|
|
40
|
+
* @param mesh 当前 Mesh
|
|
41
|
+
* @param viewBuffer 相机视图矩阵缓冲
|
|
42
|
+
* @param orthogonalBuffer 相机投影矩阵缓冲
|
|
43
|
+
* @param renderCameraBuffer Render 与 Camera 公共参数缓冲
|
|
44
|
+
* @returns 无返回值
|
|
45
|
+
*/
|
|
46
|
+
private drawMesh;
|
|
47
|
+
/**
|
|
48
|
+
* 一次绑定 Mesh 实例样式 Storage 与三种几何的贴图,Sampler 各自独立。
|
|
49
|
+
* @param device 当前 WebGPU 设备
|
|
50
|
+
* @param mesh 当前 Mesh,提供独立实例样式缓冲
|
|
51
|
+
* @param material 当前材质
|
|
52
|
+
* @param pipelineTemplate 当前几何类型对应的 Pipeline 模板
|
|
53
|
+
* @returns 材质 BindGroup,必要资源未就绪时返回 undefined
|
|
54
|
+
*/
|
|
55
|
+
private createMaterialBindGroup;
|
|
56
|
+
}
|
|
57
|
+
export default DrawCallManager;
|
|
58
|
+
export type { DrawCallManagerLike };
|