Skip to content

Commit 6c7bd12

Browse files
AlexAPPiCopilotmvaligursky
authored
Add frontFace support to render pipeline (#8447) (#8448)
* Add frontFace method support (#8447) * Changed the order to conform to WebGPU specifications. * Fix lint * Delete mode from name * Remove default value in functions with private API * Remove comment * Add setupFrontFace method to renderer * Fix: 'FRONTFACE_CCW' is defined but never used * Bly setupFrontFace * Update src/platform/graphics/constants.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/platform/graphics/constants.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/platform/graphics/graphics-device.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/scene/materials/material.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/platform/graphics/constants.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update src/scene/materials/material.js Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add frontFace test * Add flipFactor for setupFontFace * Backward compatibility * lint * Ok * Change setup logic * Change setup logic --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Martin Valigursky <59932779+mvaligursky@users.noreply.github.com>
1 parent dd49aa4 commit 6c7bd12

20 files changed

+143
-31
lines changed

src/extras/renderers/outline-renderer.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { BlendState } from '../../platform/graphics/blend-state.js';
44
import {
55
ADDRESS_CLAMP_TO_EDGE, BLENDEQUATION_ADD, BLENDMODE_ONE_MINUS_SRC_ALPHA, BLENDMODE_SRC_ALPHA,
66
CULLFACE_NONE,
7-
FILTER_LINEAR, FILTER_LINEAR_MIPMAP_LINEAR, PIXELFORMAT_SRGBA8,
7+
FILTER_LINEAR, FILTER_LINEAR_MIPMAP_LINEAR, FRONTFACE_CCW, PIXELFORMAT_SRGBA8,
88
SEMANTIC_POSITION
99
} from '../../platform/graphics/constants.js';
1010
import { DepthState } from '../../platform/graphics/depth-state.js';
@@ -316,6 +316,7 @@ class OutlineRenderer {
316316

317317
device.setDepthState(DepthState.NODEPTH);
318318
device.setCullMode(CULLFACE_NONE);
319+
device.setFrontFace(FRONTFACE_CCW);
319320
device.setBlendState(this.blendState);
320321
this.quadRenderer.render();
321322
}

src/platform/graphics/constants.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,20 @@ export const CULLFACE_FRONT = 2;
344344
*/
345345
export const CULLFACE_FRONTANDBACK = 3;
346346

347+
/**
348+
* The counterclockwise winding. Specifies whether polygons are front- or back-facing by setting a winding orientation.
349+
*
350+
* @category Graphics
351+
*/
352+
export const FRONTFACE_CCW = 0;
353+
354+
/**
355+
* The clockwise winding. Specifies whether polygons are front- or back-facing by setting a winding orientation.
356+
*
357+
* @category Graphics
358+
*/
359+
export const FRONTFACE_CW = 1;
360+
347361
/**
348362
* Point sample filtering.
349363
*

src/platform/graphics/graphics-device.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ import {
1414
INDEXFORMAT_UINT16,
1515
PRIMITIVE_POINTS, PRIMITIVE_TRIFAN, SEMANTIC_POSITION, TYPE_FLOAT32, PIXELFORMAT_111110F, PIXELFORMAT_RGBA16F, PIXELFORMAT_RGBA32F,
1616
DISPLAYFORMAT_LDR,
17-
semanticToLocation
17+
semanticToLocation,
18+
FRONTFACE_CCW
1819
} from './constants.js';
1920
import { BlendState } from './blend-state.js';
2021
import { DepthState } from './depth-state.js';
@@ -772,6 +773,7 @@ class GraphicsDevice extends EventHandler {
772773
this.blendState = new BlendState();
773774
this.depthState = new DepthState();
774775
this.cullMode = CULLFACE_BACK;
776+
this.frontFace = FRONTFACE_CCW;
775777

776778
// Cached viewport and scissor dimensions
777779
this.vx = this.vy = this.vw = this.vh = 0;
@@ -839,6 +841,19 @@ class GraphicsDevice extends EventHandler {
839841
Debug.assert(false);
840842
}
841843

844+
/**
845+
* Controls whether polygons are front- or back-facing by setting a winding
846+
* orientation. The default frontFace is {@link FRONTFACE_CCW}.
847+
*
848+
* @param {number} frontFace - The front face to set. Can be:
849+
*
850+
* - {@link FRONTFACE_CW}
851+
* - {@link FRONTFACE_CCW}
852+
*/
853+
setFrontFace(frontFace) {
854+
Debug.assert(false);
855+
}
856+
842857
/**
843858
* Sets the specified render target on the device. If null is passed as a parameter, the back
844859
* buffer becomes the current target for all rendering operations.

src/platform/graphics/null/null-graphics-device.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ class NullGraphicsDevice extends GraphicsDevice {
126126
setCullMode(cullMode) {
127127
}
128128

129+
setFrontFace(frontFace) {
130+
}
131+
129132
setAlphaToCoverage(state) {
130133
}
131134

src/platform/graphics/webgl/webgl-graphics-device.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,11 @@ class WebglGraphicsDevice extends GraphicsDevice {
335335
gl.FRONT_AND_BACK
336336
];
337337

338+
this.glFrontFace = [
339+
gl.CCW,
340+
gl.CW
341+
];
342+
338343
this.glFilter = [
339344
gl.NEAREST,
340345
gl.LINEAR,
@@ -2512,6 +2517,14 @@ class WebglGraphicsDevice extends GraphicsDevice {
25122517
}
25132518
}
25142519

2520+
setFrontFace(frontFace) {
2521+
if (this.frontFace !== frontFace) {
2522+
const mode = this.glFrontFace[frontFace];
2523+
this.gl.frontFace(mode);
2524+
this.frontFace = frontFace;
2525+
}
2526+
}
2527+
25152528
/**
25162529
* Sets the active shader to be used during subsequent draw calls.
25172530
*

src/platform/graphics/webgpu/webgpu-clear-renderer.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import {
55
CULLFACE_NONE,
66
PRIMITIVE_TRISTRIP, SHADERLANGUAGE_WGSL,
77
UNIFORMTYPE_FLOAT, UNIFORMTYPE_VEC4, BINDGROUP_MESH, CLEARFLAG_COLOR, CLEARFLAG_DEPTH, CLEARFLAG_STENCIL,
8-
BINDGROUP_MESH_UB
8+
BINDGROUP_MESH_UB,
9+
FRONTFACE_CCW
910
} from '../constants.js';
1011
import { Shader } from '../shader.js';
1112
import { DynamicBindGroup } from '../bind-group.js';
@@ -138,6 +139,7 @@ class WebgpuClearRenderer {
138139
uniformBuffer.endUpdate();
139140

140141
device.setCullMode(CULLFACE_NONE);
142+
device.setFrontFace(FRONTFACE_CCW);
141143

142144
// render 4 vertices without vertex buffer
143145
device.setShader(this.shader);

src/platform/graphics/webgpu/webgpu-graphics-device.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ class WebgpuGraphicsDevice extends GraphicsDevice {
740740
// render pipeline
741741
pipeline = this.renderPipeline.get(primitive, vb0?.format, vb1?.format, indexBuffer?.format, this.shader, this.renderTarget,
742742
this.bindGroupFormats, this.blendState, this.depthState, this.cullMode,
743-
this.stencilEnabled, this.stencilFront, this.stencilBack);
743+
this.stencilEnabled, this.stencilFront, this.stencilBack, this.frontFace);
744744
Debug.assert(pipeline);
745745

746746
if (this.pipeline !== pipeline) {
@@ -859,6 +859,10 @@ class WebgpuGraphicsDevice extends GraphicsDevice {
859859
this.cullMode = cullMode;
860860
}
861861

862+
setFrontFace(frontFace) {
863+
this.frontFace = frontFace;
864+
}
865+
862866
setAlphaToCoverage(state) {
863867
}
864868

src/platform/graphics/webgpu/webgpu-render-pipeline.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ const _cullModes = [
7272
'front' // CULLFACE_FRONT
7373
];
7474

75+
const _frontFace = [
76+
'ccw', // FRONTFACE_CCW
77+
'cw' // FRONTFACE_CW
78+
];
79+
7580
const _stencilOps = [
7681
'keep', // STENCILOP_KEEP
7782
'zero', // STENCILOP_ZERO
@@ -107,7 +112,7 @@ class CacheEntry {
107112
}
108113

109114
class WebgpuRenderPipeline extends WebgpuPipeline {
110-
lookupHashes = new Uint32Array(14);
115+
lookupHashes = new Uint32Array(15);
111116

112117
constructor(device) {
113118
super(device);
@@ -141,11 +146,12 @@ class WebgpuRenderPipeline extends WebgpuPipeline {
141146
* @param {boolean} stencilEnabled - Whether stencil is enabled.
142147
* @param {StencilParameters} stencilFront - The stencil state for front faces.
143148
* @param {StencilParameters} stencilBack - The stencil state for back faces.
149+
* @param {number} frontFace - The front face.
144150
* @returns {GPURenderPipeline} Returns the render pipeline.
145151
* @private
146152
*/
147153
get(primitive, vertexFormat0, vertexFormat1, ibFormat, shader, renderTarget, bindGroupFormats, blendState,
148-
depthState, cullMode, stencilEnabled, stencilFront, stencilBack) {
154+
depthState, cullMode, stencilEnabled, stencilFront, stencilBack, frontFace) {
149155

150156
Debug.assert(bindGroupFormats.length <= 3);
151157

@@ -177,6 +183,7 @@ class WebgpuRenderPipeline extends WebgpuPipeline {
177183
lookupHashes[11] = stencilEnabled ? stencilFront.key : 0;
178184
lookupHashes[12] = stencilEnabled ? stencilBack.key : 0;
179185
lookupHashes[13] = ibFormat ?? 0;
186+
lookupHashes[14] = frontFace;
180187
const hash = hash32Fnv1a(lookupHashes);
181188

182189
// cached pipeline
@@ -206,7 +213,7 @@ class WebgpuRenderPipeline extends WebgpuPipeline {
206213
const cacheEntry = new CacheEntry();
207214
cacheEntry.hashes = new Uint32Array(lookupHashes);
208215
cacheEntry.pipeline = this.create(primitiveTopology, ibFormat, shader, renderTarget, pipelineLayout, blendState,
209-
depthState, vertexBufferLayout, cullMode, stencilEnabled, stencilFront, stencilBack);
216+
depthState, vertexBufferLayout, cullMode, stencilEnabled, stencilFront, stencilBack, frontFace);
210217

211218
// add to cache
212219
if (cacheEntries) {
@@ -313,7 +320,7 @@ class WebgpuRenderPipeline extends WebgpuPipeline {
313320
}
314321

315322
create(primitiveTopology, ibFormat, shader, renderTarget, pipelineLayout, blendState, depthState, vertexBufferLayout,
316-
cullMode, stencilEnabled, stencilFront, stencilBack) {
323+
cullMode, stencilEnabled, stencilFront, stencilBack, frontFace) {
317324

318325
const wgpu = this.device.wgpu;
319326

@@ -330,7 +337,7 @@ class WebgpuRenderPipeline extends WebgpuPipeline {
330337

331338
primitive: {
332339
topology: primitiveTopology,
333-
frontFace: 'ccw',
340+
frontFace: _frontFace[frontFace],
334341
cullMode: _cullModes[cullMode]
335342
},
336343

src/scene/graphics/quad-render.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const _dynamicBindGroup = new DynamicBindGroup();
2929
* you should set up the following states as needed, otherwise previously set states will be used:
3030
* - Blend state via {@link GraphicsDevice#setBlendState}
3131
* - Cull mode via {@link GraphicsDevice#setCullMode}
32+
* - FrontFace via {@link GraphicsDevice#setFrontFace}
3233
* - Depth state via {@link GraphicsDevice#setDepthState}
3334
* - Stencil state via {@link GraphicsDevice#setStencilState}
3435
*
@@ -46,6 +47,7 @@ const _dynamicBindGroup = new DynamicBindGroup();
4647
* // Set up render states before rendering
4748
* app.graphicsDevice.setBlendState(BlendState.NOBLEND);
4849
* app.graphicsDevice.setCullMode(CULLFACE_NONE);
50+
* app.graphicsDevice.setFrontFace(FRONTFACE_CCW);
4951
* app.graphicsDevice.setDepthState(DepthState.NODEPTH);
5052
* app.graphicsDevice.setStencilState(null, null);
5153
*

src/scene/graphics/render-pass-quad.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CULLFACE_NONE } from '../../platform/graphics/constants.js';
1+
import { CULLFACE_NONE, FRONTFACE_CCW } from '../../platform/graphics/constants.js';
22
import { DebugGraphics } from '../../platform/graphics/debug-graphics.js';
33
import { DepthState } from '../../platform/graphics/depth-state.js';
44
import { RenderPass } from '../../platform/graphics/render-pass.js';
@@ -20,6 +20,7 @@ class RenderPassQuad extends RenderPass {
2020
DebugGraphics.pushGpuMarker(device, `${this.name}:${this.quad.shader.name}`);
2121

2222
device.setCullMode(CULLFACE_NONE);
23+
device.setFrontFace(FRONTFACE_CCW);
2324
device.setDepthState(DepthState.NODEPTH);
2425
device.setStencilState(null, null);
2526

0 commit comments

Comments
 (0)