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")
}
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

export const makeFBO2 = (gl, o)but you callmakeFBO2in the following way:makeFBO2(object, world.GL.gl )? (2) Can you make sure that when one of theworld.FBOS[fbindex].FBis bound to the frame buffer, it's not simultaneously bound to a texture and got sampled (like hereworld.GL.gl.bindTexture(world.GL.gl.TEXTURE_2D, object.FBO.FB.texture);)? $\endgroup$