Hey,
In my project, I’ve set up an extra camera that renders to a separate texture I intend to use as a mask. I set this up much like in this example project: PlayCanvas Examples
However, I am in need of further processing this “mask texture”, preferably through multiple render passes. I tried reproducing this example project: PlayCanvas Examples
→ And it works wonderfully! Right until I try to apply the render passes to a different camera than the main. Then I just get lots of “ASSERT FAILED:” error messages and incomplete rendering.
I made an example project here: Test project
Note that if you disable the main camera before runtime (so that the second “mask camera” that are created in the script becomes the new main camera that renders to screen, everything works as expected. The code managing the render passes are in the render-pass.js
script, a copy of which follows below.
There’s not a lot of official documentation yet on how set up render passes, so I’m somewhat at a loss… Anyone familiar with how to set up render passes on different cameras than the main camera?
var RenderPass = pc.createScript('renderPass');
// A simple render pass that renders a quad with a shader. The shader tints the source texture.
class RenderPassTint extends pc.RenderPassShaderQuad {
constructor(device, sourceTexture) {
super(device);
this.sourceTexture = sourceTexture;
this.tint = pc.Color.WHITE.clone();
this.shader = this.createQuadShader('TintShader', `
uniform sampler2D sourceTexture;
uniform vec3 tint;
varying vec2 uv0;
void main() {
vec4 color = texture2D(sourceTexture, uv0);
gl_FragColor = vec4(color.rgb * tint, color.a);
}`
);
}
execute() {
this.device.scope.resolve('sourceTexture').setValue(this.sourceTexture);
this.device.scope.resolve('tint').setValue([this.tint.r, this.tint.g, this.tint.b]);
super.execute();
}
}
// initialize code called once per entity
RenderPass.prototype.initialize = function() {
let app = this.app;
let device = app.graphicsDevice;
// the scene gets rendered to a texture first
const texture = new pc.Texture(device, {
name: 'RTTexture',
width: 128,
height: 128,
format: pc.PIXELFORMAT_RGBA8,
mipmaps: false,
minFilter: pc.FILTER_LINEAR,
magFilter: pc.FILTER_LINEAR,
addressU: pc.ADDRESS_CLAMP_TO_EDGE,
addressV: pc.ADDRESS_CLAMP_TO_EDGE
});
const rt = new pc.RenderTarget({
colorBuffer: texture,
depth: false
});
// layers used in rendering
const worldLayer = app.scene.layers.getLayerByName("World");
const uiLayer = app.scene.layers.getLayerById(pc.LAYERID_UI);
//Create camera
const cameraEntity = new pc.Entity('camerEntity');
cameraEntity.addComponent("camera", {
clearColorBuffer: false,
layers: [worldLayer.id, uiLayer.id],
renderTarget: rt,
priority: -1
});
this.entity.addChild(cameraEntity);
// use the render pass to render the world and ui layers to the created texture
const renderPass = new pc.RenderPassForward(app.graphicsDevice, app.scene.layers, app.scene, app.renderer); // <-- Should use pc.RenderPassColorGrab() instead??
console.log('render info', app.graphicsDevice, app.scene.layers, app.scene, app.renderer)
// this render pass resizes the texture to match the size of are on the scene we render to
renderPass.init(rt);
renderPass.addLayer(cameraEntity.camera, worldLayer, false);
renderPass.addLayer(cameraEntity.camera, uiLayer, true);
// tint pass uses the scene rendered to a texture, and applies a tint to it
const tintPass = new RenderPassTint(app.graphicsDevice, texture);
// rendering goes directly to the front-buffer
tintPass.init(null);
// assign those two passes to the camera to be used instead of its default rendering
cameraEntity.camera.renderPasses = [renderPass, tintPass];
// update things every frame
let angle = 3;
app.on("update", function (/** @type {number} */dt) {
angle += dt;
// tint color
tintPass.tint.lerp(pc.Color.YELLOW, pc.Color.CYAN, Math.sin(angle * 0.5) * 0.5 + 0.5);
// draw texture
app.drawTexture(-0.6, -0.6, 0.6, 0.6, texture);
});
};