0
$\begingroup$

I wanna implement shadows example from webgl2fundamentals

also i a aware of framebuffer principe a have already working implementation of mirror projection.

Ignore VS extra vars .

I have trouble with shadows examples...

I always get black collor or error logs :

GL_INVALID_OPERATION: Feedback loop formed between Framebuffer and active Texture.

My scene have two cubes. One floor and myTextCube1 on top.

I added flag object.shadows.FBO_IN_DRAW_PASS.

This is most important code from draw function: DRAWER:

 ...

if(object.FBO && object.shadows.FBO_IN_DRAW_PASS == true) {
    // test FBO
    let textureMatrix = m4.identity();
    textureMatrix = m4.translate(textureMatrix, 0.5, 0.5, 0.5);
    textureMatrix = m4.scale(textureMatrix, 0.5, 0.5, 0.5);
    textureMatrix = m4.multiply(textureMatrix, 
                     object.shadows.lightProjectionMatrix);

    const lightWorldMatrix = m4.lookAt(
        [ object.shadows.lightPosition[0],
          object.shadows.lightPosition[1],
          object.shadows.lightPosition[2]
        ],
        [object.shadows.lightTarget[0] ,
         object.shadows.lightTarget[1] , 
         object.shadows.lightTarget[2]  
        ], // target
        [object.shadows.orientation[0], object.shadows.orientation[1], object.shadows.orientation[2]], // up
            );
    textureMatrix = m4.multiply(textureMatrix, 
              m4.inverse(lightWorldMatrix));
    const mat = m4.multiply(lightWorldMatrix, 
              m4.inverse(object.shadows.lightProjectionMatrix));
    // draw to the depth texture
    world.GL.gl.uniform1i(object.shaderProgram.u_projectedTexture, false, 0);
            world.GL.gl.uniformMatrix4fv(object.shaderProgram.u_textureMatrix, false, textureMatrix);
            world.GL.gl.uniform3fv(object.shaderProgram.lightWorldPositionLocation, object.shadows.lightPosition);
    
            world.GL.gl.uniformMatrix4fv(object.shaderProgram.u_world, false,
                m4.translate(object.position.worldLocation[0],
                    object.position.worldLocation[1],
                    object.position.worldLocation[2])
            );
            // world.GL.gl.uniformMatrix4fv(object.shaderProgram.u_world, false, mat);
            world.GL.gl.uniform3fv(object.shaderProgram.u_reverseLightDirection, lightWorldMatrix.slice(8, 11));
            world.GL.gl.uniform1f(object.shaderProgram.u_bias, object.shadows.bias);

            //  console.log('LOG FBO TEXT ACTIVATE')
            world.GL.gl.activeTexture(world.GL.gl.TEXTURE0);
            world.GL.gl.bindTexture(world.GL.gl.TEXTURE_2D, object.FBO.deepTexture);
            world.GL.gl.uniform1i(object.shaderProgram.u_projectedTexture, 0);

        } else {
      // console.log('normal tex')
            for(var t = 0;t < object.textures.length;t++) {
                if(object.custom.gl_texture == null) {
                    world.GL.gl.activeTexture(world.GL.gl['TEXTURE' + t]);
                    world.GL.gl.bindTexture(world.GL.gl.TEXTURE_2D, object.textures[t]);
                    world.GL.gl.pixelStorei(world.GL.gl.UNPACK_FLIP_Y_WEBGL, false);
                    if(object.texParams.MIPMAP == false) {
                        world.GL.gl.texParameteri(world.GL.gl.TEXTURE_2D, world.GL.gl.TEXTURE_WRAP_S, object.texParams.TEXTURE_WRAP_S | world.GL.gl.REPEAT);
                        world.GL.gl.texParameteri(world.GL.gl.TEXTURE_2D, world.GL.gl.TEXTURE_WRAP_T, object.texParams.TEXTURE_WRAP_T | world.GL.gl.REPEAT);
                        // -- Allocate storage for the texture
                        // world.GL.gl.texStorage2D(world.GL.gl.TEXTURE_2D, 1, world.GL.gl.RGB8, 512, 512);
                        // world.GL.gl.texSubImage2D(world.GL.gl.TEXTURE_2D, 0, 0, 0,512, 512, world.GL.gl.RGB, world.GL.gl.UNSIGNED_BYTE, object.textures[t]);
                    } else {
                        world.GL.gl.texParameteri(world.GL.gl.TEXTURE_2D, world.GL.gl.TEXTURE_MAG_FILTER, object.texParams.TEXTURE_MAG_FILTER | world.GL.gl.LINEAR);
                        world.GL.gl.texParameteri(world.GL.gl.TEXTURE_2D, world.GL.gl.TEXTURE_MIN_FILTER, object.texParams.TEXTURE_MIN_FILTER | world.GL.gl.LINEAR);
                        world.GL.gl.generateMipmap(world.GL.gl.TEXTURE_2D);
                    }

                    if(world.GL.extTFAnisotropic && object.texParams.ANISOTROPIC == true) {
                        world.GL.gl.texParameterf(world.GL.gl.TEXTURE_2D,
                            world.GL.extTFAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT,
                            world.GL.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
                    }
                    world.GL.gl.uniform1i(object.shaderProgram.samplerUniform, t);
                    world.GL.gl.uniform1i(object.shaderProgram.u_projectedTexture, 0);
                } else {
                    object.custom.gl_texture(object, t);
                }
            }
        }
 ...
     
export const makeFBO2 = (gl, o) => {
    if(typeof o === 'undefined') {
        var o = {width: 512,    height: 512};
    }
    var error = function() {console.log('Error in creating FBO!'); return null;}
    var gl = world.GL.gl;
    const depthTexture = gl.createTexture();
    const depthTextureSize = 512;
    gl.bindTexture(gl.TEXTURE_2D, depthTexture);
    gl.texImage2D(
        gl.TEXTURE_2D,      // target
        0,                  // mip level
        gl.DEPTH_COMPONENT32F, // internal format
        depthTextureSize,   // width
        depthTextureSize,   // height
        0,                  // border
        gl.DEPTH_COMPONENT, // format
        gl.FLOAT,           // type
        null);              // data
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

    const depthFramebuffer = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, depthFramebuffer);
    gl.framebufferTexture2D(
        gl.FRAMEBUFFER,       // target
        gl.DEPTH_ATTACHMENT,  // attachment point
        gl.TEXTURE_2D,        // texture target
        depthTexture,         // texture
        0);                   // mip level

    return [depthFramebuffer, depthTexture];
}

And also importan part of code is render: RENDER


 
 
        world.GL.gl.bindFramebuffer(world.GL.gl.FRAMEBUFFER, world.FBOS[fbindex].FB);

        world.GL.gl.viewport(0, 0, 512, 512);
        world.GL.gl.clearColor(0.0, 1.0, 0.4, 1.0);
        world.GL.gl.clear(world.GL.gl.COLOR_BUFFER_BIT | world.GL.gl.DEPTH_BUFFER_BIT);
        world.GL.gl.enable(world.GL.gl.DEPTH_TEST);
        world.GL.gl.enable(world.GL.gl.CULL_FACE);
        world.GL.gl.disable(world.GL.gl.BLEND);

    // - draw all `non fbo` and `no blend`
    if(
                
                (world.contentList[looper].visible === true &&
                !world.contentList[looper].FBO &&
                world.contentList[looper].glBlend.blendEnabled == false) 
                 ||
                 (world.contentList[looper].visible === true &&
                    world.contentList[looper].shadows.FBO_IN_DRAW_PASS == false &&
                    world.contentList[looper].glBlend.blendEnabled == false)
            ) {

                    world.GL.gl.useProgram(world.contentList[looper].shaderProgram);
                    world.drawCube(world.contentList[looper], 'noray');
                    world.contentList[looper].shadows.FBO_IN_DRAW_PASS = true;


}



    world.GL.gl.bindFramebuffer(world.GL.gl.FRAMEBUFFER, null);



    // All but no blend

        world.GL.gl.useProgram(world.contentList[looper].shaderProgram);
                world.contentList[looper].shadows.FBO_IN_DRAW_PASS = true;
                world.drawCube(world.contentList[looper]);
                world.animate(world.contentList[looper]);
                world.contentList[looper].shadows.FBO_IN_DRAW_PASS = false;







END OF REDER FUNC


App.operation.CameraPerspective = function() {
    this.GL.gl.viewport(0, 0, canvas.width, canvas.height);
    this.GL.gl.clear(this.GL.gl.COLOR_BUFFER_BIT | this.GL.gl.DEPTH_BUFFER_BIT);
    mat4.perspective(this.pMatrix, degToRad(App.camera.viewAngle), this.GL.gl.viewportWidth / this.GL.gl.viewportHeight, App.camera.nearViewpoint, App.camera.farViewpoint);
}

And after all shaders part:

export function generateSpotLightShadowDefinitions() {
    return `// inject generateSpotLightShadowDefinitions
    uniform sampler2D u_projectedTexture;
    uniform sampler2D u_texture;
    in vec2 v_texcoord;
    uniform float u_bias;
    in vec4 v_projectedTexcoord;
    in vec3 v_surfaceToLight;
    in vec3 v_surfaceToView;
    uniform vec4 u_color;
    uniform float u_shininess;
    uniform vec3 u_lightDirection;
    uniform float u_innerLimit;
    uniform float u_outerLimit;
    uniform mat4 u_projection;
    uniform mat4 u_view;
    uniform mat4 u_world;
    uniform mat4 u_textureMatrix;
    uniform vec3 u_reverseLightDirection;
    `;
}

export function generateSpotLightShadowMain() {
    return `
    vec3 normal = normalize(v_normal);
    float light = dot(normal, u_reverseLightDirection);
    vec3 projectedTexcoord = v_projectedTexcoord.xyz / v_projectedTexcoord.w;
    float currentDepth = projectedTexcoord.z + u_bias;

    bool inRange =
            projectedTexcoord.x >= 0.0 &&
            projectedTexcoord.x <= 1.0 &&
            projectedTexcoord.y >= 0.0 &&
            projectedTexcoord.y <= 1.0;
    float projectedDepth = texture(u_projectedTexture, projectedTexcoord.xy).r;
    float shadowLight = (inRange && projectedDepth <= currentDepth) ? 0.0 : 1.0;
    vec4 texColor = texture(u_texture, v_texcoord) * vec4(1, 1, 1, 1);
    outColor = vec4(texColor.rgb * light * shadowLight , texColor.a);
    `;
}

VS GLSL:

export function getInitVSCubeTexLight() {
  const f = `#version 300 es
  in vec3 aVertexPosition;
  in vec3 aVertexNormal;
  in vec2 aTextureCoord;
  uniform mat4 uMVMatrix;
  uniform mat4 uPMatrix;
  uniform mat3 uNMatrix;
  uniform vec3 uAmbientColor;
  uniform vec3 uLightingDirection;
  uniform vec3 uDirectionalColor;
  uniform bool uUseLighting;
  out vec2 vTextureCoord;
  out vec3 vLightWeighting;
  out vec3 meVertexPosition;
  uniform vec3 u_lightWorldPosition;
  out vec3 v_normal;
  out vec3 v_surfaceToLight;
  out vec3 v_surfaceToView;
  out mat4 uMVMatrixINTER;
  out mat3 uNMatrixINTER;
  out mat4 uPMatrixINNTER;
  in vec4 specularColor;
  out vec4 vColor;
  out vec3 vNormal;
  out vec4 vPosition;
  out float vDist;
  uniform mat4 u_textureMatrix;
  out vec2 v_texcoord;
  out vec4 v_projectedTexcoord;
  uniform mat4 u_world;

  void main(void) {
    meVertexPosition = aVertexPosition;
    uMVMatrixINTER = uMVMatrix;
    uNMatrixINTER = uNMatrix;
    uPMatrixINNTER = uPMatrix;
    vColor = specularColor;
    vNormal = normalize(mat3(u_world) * vec3(aVertexNormal)); 
    vPosition =  uMVMatrix * vec4(aVertexPosition, 1.0);
    vDist = gl_Position.w;
    v_normal = uNMatrix  *  vec3(aVertexNormal);
    vec3 surfaceWorldPosition = (uNMatrix * aVertexPosition).xyz;
    v_surfaceToLight = u_lightWorldPosition - surfaceWorldPosition;
    v_surfaceToView = (uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0)).xyz - surfaceWorldPosition;
    vec4 worldPosition =     vec4((uNMatrix * aVertexPosition).xyz, 1.0);
    v_texcoord = aTextureCoord;
   v_projectedTexcoord = u_textureMatrix * worldPosition;
    gl_Position   = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    vTextureCoord = aTextureCoord;
    if (!uUseLighting) {
      vLightWeighting = vec3(1.0, 1.0, 1.0);
    } else {
      vec3 transformedNormal          = uNMatrix * aVertexNormal;
      float directionalLightWeighting = max(dot(transformedNormal, uLightingDirection), 0.0);
      vLightWeighting                 = uAmbientColor + uDirectionalColor * directionalLightWeighting;
    }
  }`;
    scriptManager.LOAD(f, "cubeLightTex-shader-vs", "x-shader/x-vertex", "shaders")
}

enter image description here

Any suggestion? Looks like every cube for itself cast shadow no between cast...

If you wanna live demos of my library you can explore it here.

UPDATE:

I found at https://www.youtube.com/watch?v=0Xk96uN3Ceo&ab_channel=SketchpunkLabs on 24:00 minute

drawBuffers(gl.NONE)
readBuffer(gl.NONE)

I must try this lines...

Source code : github

FULL RENDER

$\endgroup$
3
  • 1
    $\begingroup$ Your question is too long; try to identify and reduce unnecessary details. I have two questions about your code: (1) why is export const makeFBO2 = (gl, o) but you call makeFBO2 in the following way: makeFBO2(object, world.GL.gl )? (2) Can you make sure that when one of the world.FBOS[fbindex].FB is bound to the frame buffer, it's not simultaneously bound to a texture and got sampled (like here world.GL.gl.bindTexture(world.GL.gl.TEXTURE_2D, object.FBO.FB.texture);)? $\endgroup$ Commented Dec 31, 2024 at 2:57
  • $\begingroup$ You are right - i will fix & update question i still have trouble... $\endgroup$ Commented Dec 31, 2024 at 9:34
  • $\begingroup$ @Enigmatisms I updated Q. Only most importan code is here. Thnks for help! $\endgroup$ Commented Dec 31, 2024 at 11:44

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.