@animech-public/playcanvas
Version:
PlayCanvas WebGL game engine
139 lines (121 loc) • 5.24 kB
JavaScript
import { DebugHelper, Debug } from '../../../core/debug.js';
import { BindGroupFormat, BindUniformBufferFormat } from '../bind-group-format.js';
import { UniformBufferFormat, UniformFormat } from '../uniform-buffer-format.js';
import { BlendState } from '../blend-state.js';
import { SHADERLANGUAGE_WGSL, UNIFORMTYPE_VEC4, UNIFORMTYPE_FLOAT, UNIFORM_BUFFER_DEFAULT_SLOT_NAME, SHADERSTAGE_VERTEX, SHADERSTAGE_FRAGMENT, CLEARFLAG_COLOR, CLEARFLAG_DEPTH, CLEARFLAG_STENCIL, CULLFACE_NONE, BINDGROUP_MESH, PRIMITIVE_TRISTRIP } from '../constants.js';
import { Shader } from '../shader.js';
import { BindGroup } from '../bind-group.js';
import { UniformBuffer } from '../uniform-buffer.js';
import { DebugGraphics } from '../debug-graphics.js';
import { DepthState } from '../depth-state.js';
const primitive = {
type: PRIMITIVE_TRISTRIP,
base: 0,
count: 4,
indexed: false
};
/**
* A WebGPU helper class implementing a viewport clear operation. When rendering to a texture,
* the whole surface can be cleared using loadOp, but if only a viewport needs to be cleared, or if
* it needs to be cleared later during the rendering, this need to be archieved by rendering a quad.
* This class renders a full-screen quad, and expects the viewport / scissor to be set up to clip
* it to only required area.
*
* @ignore
*/
class WebgpuClearRenderer {
constructor(device) {
// shader that can write out color and depth values
const code = `
struct ub_mesh {
color : vec4f,
depth: f32
}
var<uniform> ubMesh : ub_mesh;
var<private> pos : array<vec2f, 4> = array<vec2f, 4>(
vec2(-1.0, 1.0), vec2(1.0, 1.0),
vec2(-1.0, -1.0), vec2(1.0, -1.0)
);
struct VertexOutput {
position : vec4f
}
fn vertexMain( vertexIndex : u32) -> VertexOutput {
var output : VertexOutput;
output.position = vec4(pos[vertexIndex], ubMesh.depth, 1.0);
return output;
}
fn fragmentMain() -> vec4f {
return ubMesh.color;
}
`;
this.shader = new Shader(device, {
name: 'WebGPUClearRendererShader',
shaderLanguage: SHADERLANGUAGE_WGSL,
vshader: code,
fshader: code
});
// uniforms
this.uniformBuffer = new UniformBuffer(device, new UniformBufferFormat(device, [new UniformFormat('color', UNIFORMTYPE_VEC4), new UniformFormat('depth', UNIFORMTYPE_FLOAT)]), false);
// format of the bind group
const bindGroupFormat = new BindGroupFormat(device, [new BindUniformBufferFormat(UNIFORM_BUFFER_DEFAULT_SLOT_NAME, SHADERSTAGE_VERTEX | SHADERSTAGE_FRAGMENT)]);
// bind group
this.bindGroup = new BindGroup(device, bindGroupFormat, this.uniformBuffer);
DebugHelper.setName(this.bindGroup, `ClearRenderer-BindGroup_${this.bindGroup.id}`);
// uniform data
this.colorData = new Float32Array(4);
this.colorId = device.scope.resolve('color');
this.depthId = device.scope.resolve('depth');
}
destroy() {
this.shader.destroy();
this.shader = null;
this.uniformBuffer.destroy();
this.uniformBuffer = null;
this.bindGroup.destroy();
this.bindGroup = null;
}
clear(device, renderTarget, options, defaultOptions) {
var _options$flags;
options = options || defaultOptions;
const flags = (_options$flags = options.flags) != null ? _options$flags : defaultOptions.flags;
if (flags !== 0) {
DebugGraphics.pushGpuMarker(device, 'CLEAR-RENDERER');
// setup clear color
if (flags & CLEARFLAG_COLOR && (renderTarget.colorBuffer || renderTarget.impl.assignedColorTexture)) {
var _options$color;
const color = (_options$color = options.color) != null ? _options$color : defaultOptions.color;
this.colorData.set(color);
device.setBlendState(BlendState.NOBLEND);
} else {
device.setBlendState(BlendState.NOWRITE);
}
this.colorId.setValue(this.colorData);
// setup depth clear
if (flags & CLEARFLAG_DEPTH && renderTarget.depth) {
var _options$depth;
const depth = (_options$depth = options.depth) != null ? _options$depth : defaultOptions.depth;
this.depthId.setValue(depth);
device.setDepthState(DepthState.WRITEDEPTH);
} else {
this.depthId.setValue(1);
device.setDepthState(DepthState.NODEPTH);
}
// setup stencil clear
if (flags & CLEARFLAG_STENCIL && renderTarget.stencil) {
Debug.warnOnce('ClearRenderer does not support stencil clear at the moment');
}
device.setCullMode(CULLFACE_NONE);
// render 4 vertices without vertex buffer
device.setShader(this.shader);
const bindGroup = this.bindGroup;
bindGroup.defaultUniformBuffer.update();
bindGroup.update();
device.setBindGroup(BINDGROUP_MESH, bindGroup);
device.draw(primitive);
DebugGraphics.popGpuMarker(device);
}
}
}
export { WebgpuClearRenderer };