Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/extras/renderers/outline-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BlendState } from '../../platform/graphics/blend-state.js';
import {
ADDRESS_CLAMP_TO_EDGE, BLENDEQUATION_ADD, BLENDMODE_ONE_MINUS_SRC_ALPHA, BLENDMODE_SRC_ALPHA,
CULLFACE_NONE,
FILTER_LINEAR, FILTER_LINEAR_MIPMAP_LINEAR, PIXELFORMAT_SRGBA8,
FILTER_LINEAR, FILTER_LINEAR_MIPMAP_LINEAR, FRONTFACE_CCW, PIXELFORMAT_SRGBA8,
SEMANTIC_POSITION
} from '../../platform/graphics/constants.js';
import { DepthState } from '../../platform/graphics/depth-state.js';
Expand Down Expand Up @@ -316,6 +316,7 @@ class OutlineRenderer {

device.setDepthState(DepthState.NODEPTH);
device.setCullMode(CULLFACE_NONE);
device.setFrontFace(FRONTFACE_CCW);
device.setBlendState(this.blendState);
this.quadRenderer.render();
}
Expand Down
18 changes: 18 additions & 0 deletions src/platform/graphics/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,24 @@ export const CULLFACE_FRONT = 2;
*/
export const CULLFACE_FRONTANDBACK = 3;

/**
* The counter-clock-wise winding. Specifies whether polygons are front- or back-facing by setting a winding orientation.
*
* The counter-clock-wise winding. Specifies whether polygons are front- or back-facing by setting a winding orientation.
*
* @category Graphics
*/
export const FRONTFACE_CCW = 0;

/**
* The clock-wise winding. Specifies whether polygons are front- or back-facing by setting a winding orientation.
*
* @category Graphics
*
* @category Graphics
*/
export const FRONTFACE_CW = 1;

/**
* Point sample filtering.
*
Expand Down
17 changes: 16 additions & 1 deletion src/platform/graphics/graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import {
INDEXFORMAT_UINT16,
PRIMITIVE_POINTS, PRIMITIVE_TRIFAN, SEMANTIC_POSITION, TYPE_FLOAT32, PIXELFORMAT_111110F, PIXELFORMAT_RGBA16F, PIXELFORMAT_RGBA32F,
DISPLAYFORMAT_LDR,
semanticToLocation
semanticToLocation,
FRONTFACE_CCW
} from './constants.js';
import { BlendState } from './blend-state.js';
import { DepthState } from './depth-state.js';
Expand Down Expand Up @@ -754,6 +755,7 @@ class GraphicsDevice extends EventHandler {
this.blendState = new BlendState();
this.depthState = new DepthState();
this.cullMode = CULLFACE_BACK;
this.frontFace = FRONTFACE_CCW;

// Cached viewport and scissor dimensions
this.vx = this.vy = this.vw = this.vh = 0;
Expand Down Expand Up @@ -821,6 +823,19 @@ class GraphicsDevice extends EventHandler {
Debug.assert(false);
}

/**
* Controls whether polygons are front- or back-facing by setting a winding
* orientation. The default frontFace is {@link FRONTFACE_CCW}.
*
* @param {number} frontFace - The front face to set. Can be:
*
* - {@link FRONTFACE_CW}
* - {@link FRONTFACE_CCW}
*/
setFrontFace(frontFace) {
Debug.assert(false);
}

/**
* Sets the specified render target on the device. If null is passed as a parameter, the back
* buffer becomes the current target for all rendering operations.
Expand Down
3 changes: 3 additions & 0 deletions src/platform/graphics/null/null-graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ class NullGraphicsDevice extends GraphicsDevice {
setCullMode(cullMode) {
}

setFrontFace(frontFace) {
}

setAlphaToCoverage(state) {
}

Expand Down
13 changes: 13 additions & 0 deletions src/platform/graphics/webgl/webgl-graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,11 @@ class WebglGraphicsDevice extends GraphicsDevice {
gl.FRONT_AND_BACK
];

this.glFrontFace = [
gl.CCW,
gl.CW
];

this.glFilter = [
gl.NEAREST,
gl.LINEAR,
Expand Down Expand Up @@ -2511,6 +2516,14 @@ class WebglGraphicsDevice extends GraphicsDevice {
}
}

setFrontFace(frontFace) {
if (this.frontFace !== frontFace) {
const mode = this.glFrontFace[frontFace];
this.gl.frontFace(mode);
this.frontFace = frontFace;
}
}

/**
* Sets the active shader to be used during subsequent draw calls.
*
Expand Down
4 changes: 3 additions & 1 deletion src/platform/graphics/webgpu/webgpu-clear-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
CULLFACE_NONE,
PRIMITIVE_TRISTRIP, SHADERLANGUAGE_WGSL,
UNIFORMTYPE_FLOAT, UNIFORMTYPE_VEC4, BINDGROUP_MESH, CLEARFLAG_COLOR, CLEARFLAG_DEPTH, CLEARFLAG_STENCIL,
BINDGROUP_MESH_UB
BINDGROUP_MESH_UB,
FRONTFACE_CCW
} from '../constants.js';
import { Shader } from '../shader.js';
import { DynamicBindGroup } from '../bind-group.js';
Expand Down Expand Up @@ -138,6 +139,7 @@ class WebgpuClearRenderer {
uniformBuffer.endUpdate();

device.setCullMode(CULLFACE_NONE);
device.setFrontFace(FRONTFACE_CCW);

// render 4 vertices without vertex buffer
device.setShader(this.shader);
Expand Down
6 changes: 5 additions & 1 deletion src/platform/graphics/webgpu/webgpu-graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ class WebgpuGraphicsDevice extends GraphicsDevice {
// render pipeline
pipeline = this.renderPipeline.get(primitive, vb0?.format, vb1?.format, indexBuffer?.format, this.shader, this.renderTarget,
this.bindGroupFormats, this.blendState, this.depthState, this.cullMode,
this.stencilEnabled, this.stencilFront, this.stencilBack);
this.stencilEnabled, this.stencilFront, this.stencilBack, this.frontFace);
Debug.assert(pipeline);

if (this.pipeline !== pipeline) {
Expand Down Expand Up @@ -850,6 +850,10 @@ class WebgpuGraphicsDevice extends GraphicsDevice {
this.cullMode = cullMode;
}

setFrontFace(frontFace) {
this.frontFace = frontFace;
}

setAlphaToCoverage(state) {
}

Expand Down
17 changes: 12 additions & 5 deletions src/platform/graphics/webgpu/webgpu-render-pipeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ const _cullModes = [
'front' // CULLFACE_FRONT
];

const _frontFace = [
'ccw', // FRONTFACE_CCW
'cw' // FRONTFACE_CW
];

const _stencilOps = [
'keep', // STENCILOP_KEEP
'zero', // STENCILOP_ZERO
Expand Down Expand Up @@ -107,7 +112,7 @@ class CacheEntry {
}

class WebgpuRenderPipeline extends WebgpuPipeline {
lookupHashes = new Uint32Array(14);
lookupHashes = new Uint32Array(15);

constructor(device) {
super(device);
Expand Down Expand Up @@ -141,11 +146,12 @@ class WebgpuRenderPipeline extends WebgpuPipeline {
* @param {boolean} stencilEnabled - Whether stencil is enabled.
* @param {StencilParameters} stencilFront - The stencil state for front faces.
* @param {StencilParameters} stencilBack - The stencil state for back faces.
* @param {number} frontFace - The front face.
* @returns {GPURenderPipeline} Returns the render pipeline.
* @private
*/
get(primitive, vertexFormat0, vertexFormat1, ibFormat, shader, renderTarget, bindGroupFormats, blendState,
depthState, cullMode, stencilEnabled, stencilFront, stencilBack) {
depthState, cullMode, stencilEnabled, stencilFront, stencilBack, frontFace) {

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

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

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

// add to cache
if (cacheEntries) {
Expand Down Expand Up @@ -313,7 +320,7 @@ class WebgpuRenderPipeline extends WebgpuPipeline {
}

create(primitiveTopology, ibFormat, shader, renderTarget, pipelineLayout, blendState, depthState, vertexBufferLayout,
cullMode, stencilEnabled, stencilFront, stencilBack) {
cullMode, stencilEnabled, stencilFront, stencilBack, frontFace) {

const wgpu = this.device.wgpu;

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

primitive: {
topology: primitiveTopology,
frontFace: 'ccw',
frontFace: _frontFace[frontFace],
cullMode: _cullModes[cullMode]
},

Expand Down
2 changes: 2 additions & 0 deletions src/scene/graphics/quad-render.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const _dynamicBindGroup = new DynamicBindGroup();
* you should set up the following states as needed, otherwise previously set states will be used:
* - Blend state via {@link GraphicsDevice#setBlendState}
* - Cull mode via {@link GraphicsDevice#setCullMode}
* - FrontFace via {@link GraphicsDevice#setFrontFace}
* - Depth state via {@link GraphicsDevice#setDepthState}
* - Stencil state via {@link GraphicsDevice#setStencilState}
*
Expand All @@ -46,6 +47,7 @@ const _dynamicBindGroup = new DynamicBindGroup();
* // Set up render states before rendering
* app.graphicsDevice.setBlendState(BlendState.NOBLEND);
* app.graphicsDevice.setCullMode(CULLFACE_NONE);
* app.graphicsDevice.setFrontFace(FRONTFACE_CCW);
* app.graphicsDevice.setDepthState(DepthState.NODEPTH);
* app.graphicsDevice.setStencilState(null, null);
*
Expand Down
3 changes: 2 additions & 1 deletion src/scene/graphics/render-pass-quad.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CULLFACE_NONE } from '../../platform/graphics/constants.js';
import { CULLFACE_NONE, FRONTFACE_CCW } from '../../platform/graphics/constants.js';
import { DebugGraphics } from '../../platform/graphics/debug-graphics.js';
import { DepthState } from '../../platform/graphics/depth-state.js';
import { RenderPass } from '../../platform/graphics/render-pass.js';
Expand All @@ -20,6 +20,7 @@ class RenderPassQuad extends RenderPass {
DebugGraphics.pushGpuMarker(device, `${this.name}:${this.quad.shader.name}`);

device.setCullMode(CULLFACE_NONE);
device.setFrontFace(FRONTFACE_CCW);
device.setDepthState(DepthState.NODEPTH);
device.setStencilState(null, null);

Expand Down
8 changes: 7 additions & 1 deletion src/scene/graphics/render-pass-shader-quad.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { QuadRender } from './quad-render.js';
import { BlendState } from '../../platform/graphics/blend-state.js';
import { CULLFACE_NONE } from '../../platform/graphics/constants.js';
import { CULLFACE_NONE, FRONTFACE_CCW } from '../../platform/graphics/constants.js';
import { DepthState } from '../../platform/graphics/depth-state.js';
import { RenderPass } from '../../platform/graphics/render-pass.js';

Expand Down Expand Up @@ -33,6 +33,11 @@ class RenderPassShaderQuad extends RenderPass {
*/
cullMode = CULLFACE_NONE;

/**
* The front face to use when rendering the quad. Defaults to {@link FRONTFACE_CCW}.
*/
frontFace = FRONTFACE_CCW;

/**
* A blend state to use when rendering the quad. Defaults to {@link BlendState.NOBLEND}.
*
Expand Down Expand Up @@ -106,6 +111,7 @@ class RenderPassShaderQuad extends RenderPass {
const device = this.device;
device.setBlendState(this.blendState);
device.setCullMode(this.cullMode);
device.setFrontFace(this.frontFace);
device.setDepthState(this.depthState);
device.setStencilState(this.stencilFront, this.stencilBack);

Expand Down
3 changes: 2 additions & 1 deletion src/scene/gsplat-unified/gsplat-work-buffer-render-pass.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { RenderPass } from '../../platform/graphics/render-pass.js';
import { DebugGraphics } from '../../platform/graphics/debug-graphics.js';
import { BlendState } from '../../platform/graphics/blend-state.js';
import { DepthState } from '../../platform/graphics/depth-state.js';
import { CULLFACE_NONE } from '../../platform/graphics/constants.js';
import { CULLFACE_NONE, FRONTFACE_CCW } from '../../platform/graphics/constants.js';

/**
* @import { GSplatInfo } from './gsplat-info.js'
Expand Down Expand Up @@ -105,6 +105,7 @@ class GSplatWorkBufferRenderPass extends RenderPass {
// Set up render state
device.setBlendState(BlendState.NOBLEND);
device.setCullMode(CULLFACE_NONE);
device.setFrontFace(FRONTFACE_CCW);
device.setDepthState(DepthState.NODEPTH);
device.setStencilState();

Expand Down
2 changes: 2 additions & 0 deletions src/scene/gsplat/gsplat-resolve-sh.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Mat4 } from '../../core/math/mat4.js';
import { BlendState } from '../../platform/graphics/blend-state.js';
import {
CULLFACE_NONE,
FRONTFACE_CCW,
PIXELFORMAT_RGBA8,
SEMANTIC_POSITION
} from '../../platform/graphics/constants.js';
Expand Down Expand Up @@ -290,6 +291,7 @@ class GSplatResolveSH {
});

device.setCullMode(CULLFACE_NONE);
device.setFrontFace(FRONTFACE_CCW);
device.setDepthState(DepthState.NODEPTH);
device.setStencilState(null, null);
device.setBlendState(BlendState.NOBLEND);
Expand Down
17 changes: 16 additions & 1 deletion src/scene/materials/material.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
BLENDEQUATION_ADD, BLENDEQUATION_REVERSE_SUBTRACT,
BLENDEQUATION_MIN, BLENDEQUATION_MAX,
CULLFACE_BACK,
SHADERLANGUAGE_GLSL
SHADERLANGUAGE_GLSL,
FRONTFACE_CCW
} from '../../platform/graphics/constants.js';
import { BlendState } from '../../platform/graphics/blend-state.js';
import { DepthState } from '../../platform/graphics/depth-state.js';
Expand Down Expand Up @@ -167,6 +168,19 @@ class Material {
*/
cull = CULLFACE_BACK;

/**
* Controls whether polygons are front- or back-facing by setting a winding
* orientation. Can be:
*
* - {@link FRONTFACE_CW}: The clock-wise winding.
* - {@link FRONTFACE_CCW}: The counter-clock-wise winding.
*
* Defaults to {@link FRONTFACE_CCW}.
*
* @type {number}
*/
frontFace = FRONTFACE_CCW;

/**
* Stencil parameters for front faces (default is null).
*
Expand Down Expand Up @@ -637,6 +651,7 @@ class Material {
this._depthState.copy(source._depthState);

this.cull = source.cull;
this.frontFace = source.frontFace;

this.stencilFront = source.stencilFront?.clone();
if (source.stencilBack) {
Expand Down
3 changes: 2 additions & 1 deletion src/scene/particle-system/gpu-updater.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Mat3 } from '../../core/math/mat3.js';
import { Mat4 } from '../../core/math/mat4.js';
import { Vec3 } from '../../core/math/vec3.js';

import { CULLFACE_NONE } from '../../platform/graphics/constants.js';
import { CULLFACE_NONE, FRONTFACE_CCW } from '../../platform/graphics/constants.js';
import { DebugGraphics } from '../../platform/graphics/debug-graphics.js';
import { BlendState } from '../../platform/graphics/blend-state.js';
import { DepthState } from '../../platform/graphics/depth-state.js';
Expand Down Expand Up @@ -96,6 +96,7 @@ class ParticleGPUUpdater {
device.setBlendState(BlendState.NOBLEND);
device.setDepthState(DepthState.NODEPTH);
device.setCullMode(CULLFACE_NONE);
device.setFrontFace(FRONTFACE_CCW);

this.randomize();

Expand Down
1 change: 1 addition & 0 deletions src/scene/renderer/forward-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,7 @@ class ForwardRenderer extends Renderer {
DebugGraphics.pushGpuMarker(device, `Node: ${drawCall.node.name}, Material: ${material.name}`);

this.setupCullMode(camera._cullFaces, flipFactor, drawCall);
this.setupFrontFace(drawCall);

const stencilFront = drawCall.stencilFront ?? material.stencilFront;
const stencilBack = drawCall.stencilBack ?? material.stencilBack;
Expand Down
3 changes: 2 additions & 1 deletion src/scene/renderer/render-pass-cookie-renderer.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Debug } from '../../core/debug.js';
import { Vec4 } from '../../core/math/vec4.js';
import { Mat4 } from '../../core/math/mat4.js';
import { CULLFACE_NONE, SEMANTIC_POSITION } from '../../platform/graphics/constants.js';
import { CULLFACE_NONE, FRONTFACE_CCW, SEMANTIC_POSITION } from '../../platform/graphics/constants.js';
import { DebugGraphics } from '../../platform/graphics/debug-graphics.js';
import { LIGHTTYPE_DIRECTIONAL, LIGHTTYPE_OMNI } from '../constants.js';
import { ShaderUtils } from '../shader-lib/shader-utils.js';
Expand Down Expand Up @@ -165,6 +165,7 @@ class RenderPassCookieRenderer extends RenderPass {
const device = this.device;
device.setBlendState(BlendState.NOBLEND);
device.setCullMode(CULLFACE_NONE);
device.setFrontFace(FRONTFACE_CCW);
device.setDepthState(DepthState.NODEPTH);
device.setStencilState();

Expand Down
Loading