V7 issue with custom points shader (THREE.ShaderMaterial) and default THREE.SpriteMaterial
Description of the bug
When enabling gbuffer normals in the render pipeline, custom Points (implemented with THREE.ShaderMaterial) and default THREE.SpriteMaterial objects fail to render and become invisible.
To reproduce
Enable NORMAL pass to a scene that contains a SpriteMaterial or Points using ShaderMaterial. Everything renders properly except the sprite or points.
Workaround
Adding the following to the SpriteMaterial onBeforeCompile or directly to the custom Points fragment shader make the sprites or points render properly:
// Variable declarations
layout(location = 1) out vec3 gBufferNormal;
// In main
gBufferNormal = normalize(vWorldNormal);
Expected behavior
I made a custom effect to add SSAO to the RenderPipeline which requires the GBuffer NORMAL pass to be enabled, and everything works as expected, except the Points and SpriteMaterials don't render.
Screenshots
Screenshot is with GBuffer.NORMAL enabled and white outlines are without this.input.gBuffer.add(GBuffer.NORMAL) enabled in the effect (and without the noted GLSL fix above).
Library versions used
- Three: 0.176.0
- Post Processing: 7.0.0-beta.11
Desktop
- OS: Windows
- Browser: Chrome 137.0.7151.104
- Graphics hardware: NVIDIA
Thanks for the report! I'll take a closer look at this when I get a chance.
I've added an improvement for this in v7.0.0-beta.12 which should add the output declarations to all materials. I wasn't able to test this extensively yet though.
Can you try using the following code to see if that works?
// instead of this
//gBufferNormal = normalize(vWorldNormal);
// try this:
vec3 normal = normalize(vWorldNormal);
#include <pp_default_output_fragment>
I just updated to the new beta 12 and updated the sprite and particles with the noted code, and it isn't throwing errors for just those materials. However, it looks like nearly all materials are not seeing the normal vector var anymore and are throwing 'normal' : undeclared identifier until the console overloads with too many WebGL errors on this line:
out_Normal=vec4(normal,1.0);
Thanks for checking 👍
it looks like nearly all materials are not seeing the normal vector var anymore
Only non-PBR materials like PointsMaterial should be affected.
These materials don't define any of the variables that are expected to be present in PBR materials. It should be possible to fix this by adding default variables to those materials... I'll work on a fix.
Sorry for the delay!
This bug should now be fixed in v7.0.0-beta.13. Please let me know if there is still an issue.
[!IMPORTANT] The snippet
#include <pp_default_output_fragment>is no longer needed and should be removed from user code.
Almost forgot: if you want to sample normals from the G-Buffer in a custom material, you'll need the following shader chunks because the normals are encoded:
// These shader chunks are already included in the context of an effect shader.
#include <pp_normal_codec_pars_fragment>
#include <pp_normal_utils_pars_fragment>
Then use readNormal(normalBuffer, uv) to get the decoded normal.
Awesome, I believe most of this works, there's a few small style things that appear visually different, but I'm guessing it's mostly the upgraded blend algorithms, so I'll just need to adjust for that.
However, there's a major error that's preventing multiple canvases from running at all.
Essentially I have 2 separate workers, 1 for the primary scene and another for portrait canvas cards (using scissored viewports). With the upgrade I can disable either one of these from rendering (just by commenting out the this._mainPipelineRenderer.render(this._delta)) method and then the other canvas renders perfectly.
The error I'm getting when both are enabled to render: WebGL: INVALID_VALUE: clearBufferfv: invalid array size / srcOffset
I tried removing all custom render passes and just having the basics, and I still get the issue. Using beta v.11 worked, but this upgrade is throwing the error now. I can do more research on my side if you need any more details, just wanted to note this now and see if it's something obvious!
Oh, I also had to upgrade from threejs 0.176.0 to 0.179.0.
there's a few small style things that appear visually different, but I'm guessing it's mostly the upgraded blend algorithms, so I'll just need to adjust for that.
Interesting, can you provide some example for this? Could be a regression.
The error I'm getting when both are enabled to render: WebGL: INVALID_VALUE: clearBufferfv: invalid array size / srcOffset
That's strange. Are you modifying ClearPass.clearValues anywhere or are you changing the G-Buffer texture configs in GeometryPass somehow?
I'll try to reproduce the bug locally in a bit.
also had to upgrade from threejs 0.176.0 to 0.179.0.
Yeah, sorry about that. There was a change in three that would've required ugly workarounds to ensure backward-compatibility and I didn't want to start with that in the beta. When the full release is out, back-compat with the six most recent versions of three will be guaranteed.
I just adjusted my scene manager to include only the bare-bones following passes and basic tone mapping effect - and the WebGL error doesn't trigger now (so I'll try to narrow down which custom pass is creating it). However, this is no longer clipping the portait canvas with the stencil, I'll keep working through this and see if I can sort it out. But wanted to give this quick update.
const clear = new ClearPass();
thisPassData.clearPass = clear;
const geometryPassA = new GeometryPass(sceneA, cameraA, {
samples: 0,
stencilBuffer: sceneType === SCENE_TYPES.portraits ? true : false,
depthBuffer: true,
frameBufferType: THREE.HalfFloatType
});
thisPassData.geometryPass = geometryPassA;
if (sceneType === SCENE_TYPES.portraits) {
clear.scissor.enabled = true;
clear.viewport.enabled = true;
geometryPassA.scissor.enabled = true;
geometryPassA.viewport.enabled = true;
}
renderPipeline.add(clear);
renderPipeline.add(geometryPassA);
const toneMapping = new ToneMappingEffect({ toneMapping: this._effectParams.toneMapping });
renderPipeline.add(new EffectPass(toneMapping));
Ok, so I've somewhat narrowed down the WebGL: INVALID_VALUE: clearBufferfv: invalid array size / srcOffset
If I have an extended effect with this.input.gBuffer.add(GBuffer.NORMAL); enabled after a depthCopy pass then the error starts throwing.
const clear = new ClearPass();
thisPassData.clearPass = clear;
const geometryPassA = new GeometryPass(sceneA, cameraA, {
samples: 0,
stencilBuffer: sceneType === SCENE_TYPES.portraits ? true : false,
depthBuffer: true,
frameBufferType: THREE.HalfFloatType
});
thisPassData.geometryPass = geometryPassA;
if (sceneType === SCENE_TYPES.portraits) {
clear.scissor.enabled = true;
clear.viewport.enabled = true;
geometryPassA.scissor.enabled = true;
geometryPassA.viewport.enabled = true;
}
renderPipeline.add(clear);
renderPipeline.add(geometryPassA);
// depth copy pass - in the real game I need a custom pass to inject depth into specific materials that require depth data
const depthPass = new DepthCopyPass();
renderPipeline.add(depthPass);
// effect that does nothing but return scene color and add gbuffer.normal
renderPipeline.add(new EffectPass(new TestBasicEffect()));
The TestBasicEffect code:
import { Effect, GBuffer } from 'postprocessing';
const testFrag = `
vec4 mainImage(const in vec4 inputColor, const in vec2 uv, const in GData gData) {
vec4 outputColor = inputColor;
return outputColor;
}
`;
export class TestBasicEffect extends Effect {
constructor(params) {
super('TestBasicEffect');
this.fragmentShader = testFrag;
//this.input.gBuffer.add(GBuffer.DEPTH);
this.input.gBuffer.add(GBuffer.NORMAL);
}
}
It only appears that GBuffer.NORMAL triggers this, if I flip to this.input.gBuffer.add(GBuffer.DEPTH); instead of normal then the error isn't thrown.
And now that I've narrowed it down, this happens regardless of the number of canvases rendering and it doesn't actually prevent the canvas from rendering, everything actually "looks" fine, but this error just triggers infinitely.
So to recap, I think the scissor clipping issue noted above is a separate problem from this webGL error. As the canvas just doesn't clip regardless whether this error is triggered or not.
Thank you for investigating 👍
So far, I've been unable to reproduce the error. A pipeline with ClearPass → GeometryPass → DepthCopyPass → EffectPass with a single effect that uses GBuffer.NORMAL renders just fine on my end (with and without scissor/viewport enabled).
What values does your clearPass.clearValues contain? Please also check what your G-Buffer config looks like:
console.log(clearPass.clearValues.gBuffer.entries());
console.log(geoPass.gBufferConfig.textureConfigs.entries());
You can copy the data by expanding the logged object and right-clicking its [[Entries]]:
Ugh, the portraits weren't clipping properly because the new version requires alpha: true in the GeometryPass which I missed! Everything's rendering correctly now, but I'm still seeing that WebGL error despite the visual output being fine. Since you're not encountering this in isolated local testing, it's likely something specific to my setup - this project has grown quite large and there's probably a minor conflict somewhere that I need to track down. If nothing jumps out from the entries below, I'll debug it further on my end. If it's not just an issue with my environment, I can open a new issue if I can't resolve it.
And for the slight style differences, I really think it's just the blends, and it might even be related to the new THREE version, if I discover anything else on that I can ping back.
The clearPass entries:
[
{
"key": "Normal",
"value": [
0,
0
]
},
{
"key": "ORM",
"value": [
1,
0,
0,
1
]
},
{
"key": "Emission",
"value": [
0,
0,
0,
1
]
}
]
And the gBufferConfig entries:
[
{
"key": "Color",
"value": {
"minFilter": 1006,
"magFilter": 1006,
"type": 1016,
"format": 1022,
"internalFormat": "R11F_G11F_B10F",
"isColorBuffer": true
}
},
{
"key": "Normal",
"value": {
"minFilter": 1003,
"magFilter": 1003,
"type": 1016,
"format": 1030
}
},
{
"key": "ORM",
"value": {
"minFilter": 1003,
"magFilter": 1003,
"type": 1009,
"format": 1023
}
},
{
"key": "Emission",
"value": {
"minFilter": 1006,
"magFilter": 1006,
"type": 1016,
"format": 1023
}
}
]
Ugh, the portraits weren't clipping properly because the new version requires alpha: true in the GeometryPass which I missed! Everything's rendering correctly now
Ouch, yeah that's a bit of a pitfall. Glad it's rendering correctly though.
Those values also look fine - nothing that jumps out to me from what I've seen.
If it's not just an issue with my environment, I can open a new issue if I can't resolve it.
Ok, sounds good 👌.
WebGL: INVALID_VALUE: clearBufferfv: invalid array size / srcOffset
@japhiaolson I've figured out what causes this - the bug only occurs when the G-Buffer has a normal buffer attachment and the scene does not have a texture background.
A fix will be included in the next release.
@japhiaolson Fixed clearing in v7.0.0-beta.14
@vanruesc Just updated and the errors are gone - everything is working perfectly!