Skip to content

Commit

Permalink
Smaller PostEffect refactor and simplification, WebGPU support (#4996)
Browse files Browse the repository at this point in the history
Co-authored-by: Martin Valigursky <mvaligursky@snapchat.com>
  • Loading branch information
mvaligursky and Martin Valigursky committed Jan 25, 2023
1 parent 6aa4e5a commit e2b3ecb
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 152 deletions.
86 changes: 36 additions & 50 deletions scripts/posteffects/posteffect-outline.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,55 +13,41 @@
function OutlineEffect(graphicsDevice, thickness) {
pc.PostEffect.call(this, graphicsDevice);

this.shader = new pc.Shader(graphicsDevice, {
attributes: {
aPosition: pc.SEMANTIC_POSITION
},
vshader: [
"attribute vec2 aPosition;",
"",
"varying vec2 vUv0;",
"",
"void main(void)",
"{",
" gl_Position = vec4(aPosition, 0.0, 1.0);",
" vUv0 = (aPosition.xy + 1.0) * 0.5;",
"}"
].join("\n"),
fshader: [
"precision " + graphicsDevice.precision + " float;",
"",
"#define THICKNESS " + (thickness ? thickness.toFixed(0) : 1),
"uniform float uWidth;",
"uniform float uHeight;",
"uniform vec4 uOutlineCol;",
"uniform sampler2D uColorBuffer;",
"uniform sampler2D uOutlineTex;",
"",
"varying vec2 vUv0;",
"",
"void main(void)",
"{",
" vec4 texel1 = texture2D(uColorBuffer, vUv0);",
" float sample0 = texture2D(uOutlineTex, vUv0).a;",
" float outline = 0.0;",
" if (sample0==0.0)",
" {",
" for (int x=-THICKNESS;x<=THICKNESS;x++)",
" {",
" for (int y=-THICKNESS;y<=THICKNESS;y++)",
" { ",
" float sample=texture2D(uOutlineTex, vUv0+vec2(float(x)/uWidth, float(y)/uHeight)).a;",
" if (sample>0.0)",
" {",
" outline=1.0;",
" }",
" }",
" } ",
" }",
" gl_FragColor = mix(texel1, uOutlineCol, outline * uOutlineCol.a);",
"}"
].join("\n")
var fshader = [
"#define THICKNESS " + (thickness ? thickness.toFixed(0) : 1),
"uniform float uWidth;",
"uniform float uHeight;",
"uniform vec4 uOutlineCol;",
"uniform sampler2D uColorBuffer;",
"uniform sampler2D uOutlineTex;",
"",
"varying vec2 vUv0;",
"",
"void main(void)",
"{",
" vec4 texel1 = texture2D(uColorBuffer, vUv0);",
" float sample0 = texture2D(uOutlineTex, vUv0).a;",
" float outline = 0.0;",
" if (sample0==0.0)",
" {",
" for (int x=-THICKNESS;x<=THICKNESS;x++)",
" {",
" for (int y=-THICKNESS;y<=THICKNESS;y++)",
" { ",
" float tex=texture2D(uOutlineTex, vUv0+vec2(float(x)/uWidth, float(y)/uHeight)).a;",
" if (tex>0.0)",
" {",
" outline=1.0;",
" }",
" }",
" } ",
" }",
" gl_FragColor = mix(texel1, uOutlineCol, outline * uOutlineCol.a);",
"}"
].join("\n");

this.shader = pc.createShaderFromCode(graphicsDevice, pc.PostEffect.quadVertexShader, fshader, 'OutlineShader', {
aPosition: pc.SEMANTIC_POSITION
});

// Uniforms
Expand Down Expand Up @@ -89,7 +75,7 @@ Object.assign(OutlineEffect.prototype, {
scope.resolve("uOutlineCol").setValue(this._colorData);
scope.resolve("uColorBuffer").setValue(inputTarget.colorBuffer);
scope.resolve("uOutlineTex").setValue(this.texture);
pc.drawFullscreenQuad(device, outputTarget, this.vertexBuffer, this.shader, rect);
this.drawQuad(outputTarget, this.shader, rect);
}
});

Expand Down
19 changes: 18 additions & 1 deletion src/deprecated/deprecated.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { drawQuadWithShader } from '../scene/graphics/quad-render-utils.js';
import { shaderChunks } from '../scene/shader-lib/chunks/chunks.js';
import { GraphicsDevice } from '../platform/graphics/graphics-device.js';
import { IndexBuffer } from '../platform/graphics/index-buffer.js';
import { drawFullscreenQuad, PostEffect } from '../scene/graphics/post-effect.js';
import { PostEffect } from '../scene/graphics/post-effect.js';
import { PostEffectQueue } from '../framework/components/camera/post-effect-queue.js';
import { ProgramLibrary } from '../scene/shader-lib/program-library.js';
import { getProgramLibrary, setProgramLibrary } from '../scene/shader-lib/get-program-library.js';
Expand Down Expand Up @@ -436,6 +436,23 @@ export const gfx = {
VertexIterator: VertexIterator
};

const _viewport = new Vec4();

export function drawFullscreenQuad(device, target, vertexBuffer, shader, rect) {

Debug.deprecated(`pc.drawFullscreenQuad is deprecated. When used as part of PostEffect, use PostEffect#drawQuad instead.`);

// convert rect in normalized space to viewport in pixel space
let viewport;
if (rect) {
const w = target ? target.width : device.width;
const h = target ? target.height : device.height;
viewport = _viewport.set(rect.x * w, rect.y * h, rect.z * w, rect.w * h);
}

drawQuadWithShader(device, target, shader, viewport);
}

export const posteffect = {
createFullscreenQuad: (device) => {
return device.quadVertexBuffer;
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export { Skeleton } from './scene/animation/skeleton.js';

// SCENE / GRAPHICS
export { EnvLighting } from './scene/graphics/env-lighting.js';
export { PostEffect, drawFullscreenQuad } from './scene/graphics/post-effect.js';
export { PostEffect } from './scene/graphics/post-effect.js';
export { shFromCubemap } from './scene/graphics/prefilter-cubemap.js';
export { reprojectTexture } from './scene/graphics/reproject-texture.js';

Expand Down
138 changes: 38 additions & 100 deletions src/scene/graphics/post-effect.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { CULLFACE_NONE, PRIMITIVE_TRISTRIP } from '../../platform/graphics/constants.js';
import { Vec4 } from '../../core/math/vec4.js';
import { drawQuadWithShader } from './quad-render-utils.js';

// Primitive for drawFullscreenQuad
const primitive = {
type: PRIMITIVE_TRISTRIP,
base: 0,
count: 4,
indexed: false
};
const _viewport = new Vec4();

/**
* Base class for all post effects. Post effects take a a render target as input apply effects to
Expand All @@ -28,21 +23,6 @@ class PostEffect {
*/
this.device = graphicsDevice;

/**
* The shader definition for the fullscreen quad. Needs to be set by the custom post effect
* (default is null). Used when calling {@link drawFullscreenQuad}.
*
* @type {import('../../platform/graphics/shader.js').Shader|null}
*/
this.shader = null;

/**
* The vertex buffer for the fullscreen quad. Used when calling {@link drawFullscreenQuad}.
*
* @type {import('../../platform/graphics/vertex-buffer.js').VertexBuffer}
*/
this.vertexBuffer = graphicsDevice.quadVertexBuffer;

/**
* The property that should to be set to `true` (by the custom post effect) if a depth map
* is necessary (default is false).
Expand All @@ -52,6 +32,20 @@ class PostEffect {
this.needsDepthBuffer = false;
}

/**
* A simple vertx shader used to render a quad, which requires 'vec2 aPosition' in the vertex
* buffer, and generates uv coordinates vUv0 for use in the fragment shader.
*/
static quadVertexShader = `
attribute vec2 aPosition;
varying vec2 vUv0;
void main(void)
{
gl_Position = vec4(aPosition, 0.0, 1.0);
vUv0 = getImageEffectUV((aPosition.xy + 1.0) * 0.5);
}
`;

/**
* Render the post effect using the specified inputTarget to the specified outputTarget.
*
Expand All @@ -64,84 +58,28 @@ class PostEffect {
*/
render(inputTarget, outputTarget, rect) {
}
}

/**
* Draw a screen-space rectangle in a render target. Primarily meant to be used in custom post
* effects based on {@link PostEffect}.
*
* @param {import('../../platform/graphics/graphics-device.js').GraphicsDevice} device - The
* graphics device of the application.
* @param {import('../../platform/graphics/render-target.js').RenderTarget} target - The output
* render target.
* @param {import('../../platform/graphics/vertex-buffer.js').VertexBuffer} vertexBuffer - The vertex buffer for the rectangle mesh. When calling from
* a custom post effect, pass the field {@link PostEffect#vertexBuffer}.
* @param {import('../../platform/graphics/shader.js').Shader} shader - The shader to be used for
* drawing the rectangle. When calling from a custom post effect, pass the field
* {@link PostEffect#shader}.
* @param {import('../../core/math/vec4.js').Vec4} [rect] - The normalized screen-space position
* (rect.x, rect.y) and size (rect.z, rect.w) of the rectangle. Default is [0, 0, 1, 1].
*/
function drawFullscreenQuad(device, target, vertexBuffer, shader, rect) {
const oldRt = device.getRenderTarget();
device.setRenderTarget(target);
device.updateBegin();

let w = target ? target.width : device.width;
let h = target ? target.height : device.height;
let x = 0;
let y = 0;

if (rect) {
x = rect.x * w;
y = rect.y * h;
w *= rect.z;
h *= rect.w;
/**
* Draw a screen-space rectangle in a render target, using a specified shader.
*
* @param {import('../../platform/graphics/render-target.js').RenderTarget} target - The output
* render target.
* @param {import('../../platform/graphics/shader.js').Shader} shader - The shader to be used for
* drawing the rectangle.
* @param {import('../../core/math/vec4.js').Vec4} [rect] - The normalized screen-space position
* (rect.x, rect.y) and size (rect.z, rect.w) of the rectangle. Default is [0, 0, 1, 1].
*/
drawQuad(target, shader, rect) {
let viewport;
if (rect) {
// convert rect in normalized space to viewport in pixel space
const w = target ? target.width : this.device.width;
const h = target ? target.height : this.device.height;
viewport = _viewport.set(rect.x * w, rect.y * h, rect.z * w, rect.w * h);
}

drawQuadWithShader(this.device, target, shader, viewport);
}

const oldVx = device.vx;
const oldVy = device.vy;
const oldVw = device.vw;
const oldVh = device.vh;
device.setViewport(x, y, w, h);
const oldSx = device.sx;
const oldSy = device.sy;
const oldSw = device.sw;
const oldSh = device.sh;
device.setScissor(x, y, w, h);

const oldBlending = device.getBlending();
const oldDepthTest = device.getDepthTest();
const oldDepthWrite = device.getDepthWrite();
const oldCullMode = device.getCullMode();
const oldWR = device.writeRed;
const oldWG = device.writeGreen;
const oldWB = device.writeBlue;
const oldWA = device.writeAlpha;
device.setBlending(false);
device.setDepthTest(false);
device.setDepthWrite(false);
device.setCullMode(CULLFACE_NONE);
device.setColorWrite(true, true, true, true);

device.setVertexBuffer(vertexBuffer, 0);
device.setShader(shader);

device.draw(primitive);

device.setBlending(oldBlending);
device.setDepthTest(oldDepthTest);
device.setDepthWrite(oldDepthWrite);
device.setCullMode(oldCullMode);
device.setColorWrite(oldWR, oldWG, oldWB, oldWA);

device.updateEnd();

device.setRenderTarget(oldRt);
device.updateBegin();

device.setViewport(oldVx, oldVy, oldVw, oldVh);
device.setScissor(oldSx, oldSy, oldSw, oldSh);
}

export { drawFullscreenQuad, PostEffect };
export { PostEffect };

0 comments on commit e2b3ecb

Please sign in to comment.