OmarShehata / webgl-outlines

Implementation of a post process outline shader in ThreeJS & PlayCanvas.
MIT License
360 stars 39 forks source link

Shader code can't be recognized #5

Closed GothParrot closed 1 year ago

GothParrot commented 1 year ago

Hi Omar, thanks so much for putting this out there!!! Wonderful work. I tried to reproduce it in my own project, but am getting this error on both firefox and Chrome. My browsers support webGL 1 and 2:

THREE.WebGLProgram: Shader Error 0 - VALIDATE_STATUS false

Program Info Log: Must have a compiled fragment shader attached:
SHADER_INFO_LOG:
ERROR: 0:145: '0.0' : syntax error

FRAGMENT

ERROR: 0:145: '0.0' : syntax error

[three.module.js:18957](webpack:///node_modules/three/build/three.module.js)
    WebGLProgram three.module.js:18957
    acquireProgram three.module.js:19656
    getProgram three.module.js:27381
    setProgram three.module.js:27586
    renderBufferDirect three.module.js:26710
    renderObject three.module.js:27318
    renderObjects three.module.js:27287
    renderScene three.module.js:27209
    render three.module.js:27029
    render Pass.js:62
    render CustomOutlinePass.js:83
    render EffectComposer.js:141
    update Renderer.js:85
    update Experience.js:68
    Experience Experience.js:54
    trigger EventEmitter.js:138
    trigger EventEmitter.js:136
    tick Time.js:28
    Time Time.js:17
    (Async: FrameRequestCallback)
    Time Time.js:15
    Experience Experience.js:36
    <anonymous> script.js:5
    <anonymous> bundle.eadd6e7c63194188.js:67059
    <anonymous> bundle.eadd6e7c63194188.js:67061

It seems like the fragment shader can't be recognized? I simply copied the CustomOutlinePass.js.

Below is what my renderer code looks like. If I comment out the last line, this.composer.render(); and use the original renderer, the rendering works.

import * as THREE from 'three'
import Experience from './Experience.js'
import { EffectComposer } from "three/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "three/examples/jsm/postprocessing/RenderPass.js";
import { ShaderPass } from "three/examples/jsm/postprocessing/ShaderPass.js";
import { FXAAShader } from "three/examples/jsm/shaders/FXAAShader.js";
import { CustomOutlinePass } from "./Utils/Shading/CustomOutlinePass.js";

export default class Renderer
{
    constructor()
    {
        this.experience = new Experience()
        this.canvas = this.experience.canvas
        this.sizes = this.experience.sizes
        this.scene = this.experience.scene
        this.camera = this.experience.camera

        this.setInstance()
    }

    setInstance()
    {
        this.instance = new THREE.WebGLRenderer({
            canvas: this.canvas,
            antialias: true
        })
        this.instance.physicallyCorrectLights = true
        this.instance.outputEncoding = THREE.sRGBEncoding
        this.instance.toneMapping = THREE.CineonToneMapping
        this.instance.toneMappingExposure = 1.75
        this.instance.shadowMap.enabled = true
        this.instance.shadowMap.type = THREE.PCFSoftShadowMap
        this.instance.setClearColor('#211d20')
        this.instance.setSize(this.sizes.width, this.sizes.height)
        this.instance.setPixelRatio(Math.min(this.sizes.pixelRatio, 2))

        // Set up post processing
        // Create a render target that holds a depthTexture so we can use it in the outline pass
        // See: https://threejs.org/docs/index.html#api/en/renderers/WebGLRenderTarget.depthBuffer
        const depthTexture = new THREE.DepthTexture();
        this.renderTarget = new THREE.WebGLRenderTarget(
            this.sizes.width,
            this.sizes.height,
        {
            depthTexture: depthTexture,
            depthBuffer: true,
        }
        );

        // Initial render pass.
        this.composer = new EffectComposer(this.instance, this.renderTarget);
        const pass = new RenderPass(this.scene, this.camera.instance);
        this.composer.addPass(pass);

        // Outline pass.
        this.customOutline = new CustomOutlinePass(
            new THREE.Vector2(this.sizes.width, this.sizes.height),
            this.scene,
            this.camera.instance
        );
        this.composer.addPass(this.customOutline);

        // Antialias pass.
        this.effectFXAA = new ShaderPass(FXAAShader);
        this.effectFXAA.uniforms["resolution"].value.set(
        1 / this.sizes.width,
        1 / this.sizes.height
        );
        this.composer.addPass(this.effectFXAA);
    }

    resize()
    {
        this.instance.setSize(this.sizes.width, this.sizes.height)
        this.instance.setPixelRatio(Math.min(this.sizes.pixelRatio, 2))
        // this.composer.setSize(window.innerWidth, window.innerHeight);
        // this.effectFXAA.setSize(window.innerWidth, window.innerHeight);
        // this.customOutline.setSize(window.innerWidth, window.innerHeight);
    }

    update()
    {
        // this.instance.render(this.scene, this.camera.instance)
        this.composer.render();
    }
}
OmarShehata commented 1 year ago

Thanks for reporting @GothParrot ! This is super strange. I'm not sure why the shade would be failing to compile like this. I believe this is the shader that's failing:

https://github.com/OmarShehata/webgl-outlines/blob/main/threejs/src/CustomOutlinePass.js#L99

Does the crash happen for you when opening this demo: https://omarshehata.github.io/csb-l01dp/ ?

If so, I would try debugging the shader to figure out where the crash is coming from (removing parts of it until it starts to work).

If it is NOT crashing, I suspect the issue perhaps is how the shader code is being loaded in your project? maybe add a console.log(this.fragmentShader) in this line: https://github.com/OmarShehata/webgl-outlines/blob/main/threejs/src/CustomOutlinePass.js#L207

or just replace the big fragment shader with a simple one to confirm whether or not it is the cause of the crash.

OmarShehata commented 1 year ago

Closing for now but if you still have issues/are able to reproduce etc feel free to follow up!

eatdesignlove commented 1 year ago

Hi, @OmarShehata ! Thank you for your awesome project! I am trying to implement the customOutlinePass in my project (the project is based on "@react-three/fiber").

But I ran into the same problem.(https://github.com/OmarShehata/webgl-outlines/issues/5) I wrote a checklist and checked that it is working well, but I do not know the cause of the bug.

So I attach the test project. Could you please check the issue on the project? I really want to use your outline solution.

outline-r3f.zip

OmarShehata commented 1 year ago

@eatdesignlove thank you for sharing your project! It was super helpful in figuring this out.

So there are two issues in your file:

  1. You have an extra comma on line 207 in CustomOutlinePass.js:
            '   } else {,',

This must be changed to:

            '   } else {',
  1. The shader does not like the saturate() function for some reason. I can get it to work by renaming it to saturateValue( and updating the places where it is called in this file.
OmarShehata commented 1 year ago

I pushed an update here that does the saturate() rename so it should work for you/others in the future who run into this:

https://github.com/OmarShehata/webgl-outlines/commit/42e210346abdb2dab78de20df9dffc369297340f

eatdesignlove commented 1 year ago

WOW, @OmarShehata !!!! Your quick response was really helpful. 🙏

The first problem was that I thought the cause of the problem might be template literals, so I tried to convert it to an array, but there was a typo. Thanks to that, I found it and fixed it!

The second problem also worked properly as you said, by changing it to saturateValue. Thanks to that, I was able to confirm the desired result.

Now I can apply it to my real project 🔥 I was almost lost for about 3 days because of this.😇 I am very happy now. Thank you so much!!!