Compute shader - bind all texture's mip maps - opengl

is it possible (in OpenGL compute shader) to bind for example 3 mip maps of the same image as image2D structure?
Right now i have something like this in my compute shader:
layout (binding = 0, rgba16) uniform writeonly image2D textureMipMapLevel0;
layout (binding = 1, rgba16) uniform writeonly image2D textureMipMapLevel1;
layout (binding = 2, rgba16) uniform writeonly image2D textureMipMapLevel2;
And then:
if(z == 0)
{
imageStore(textureMipMapLevel0, iTextureCoords, vec4(1.0, 0.0, 0.0, 1.0));
}
else if(z == 1)
{
imageStore(textureMipMapLevel1, iTextureCoords, vec4(0.0, 1.0, 0.0, 1.0));
]
else
{
imageStore(textureMipMapLevel2, iTextureCoords, vec4(0.0, 0.0, 1.0, 1.0));
}
Is there any function like: getTextureByTextureUnit or something like this to use my z value instead of multiply if and else blocks? Every single time when I chaneg number of mip maps i have to generate completly diffrent shader program...

Related

How to get the color of the texture of the current fragment in glsl?

The problem
I'm trying to make shaders for my game. In the fragment shaders, I don't want to set the color of the fragment but add to it. How do I do so? I'm new to this, so sorry for any mistakes.
The code
varying vec3 vN;
varying vec3 v;
varying vec4 color;
#define MAX_LIGHTS 1
void main (void)
{
vec3 N = normalize(vN);
vec4 finalColor = vec4(0.0, 0.0, 0.0, 0.0);
for (int i=0;i<MAX_LIGHTS;i++)
{
vec3 L = normalize(gl_LightSource[i].position.xyz - v);
vec3 E = normalize(-v); // we are in Eye Coordinates, so EyePos is (0,0,0)
vec3 R = normalize(-reflect(L,N));
vec4 Iamb = gl_LightSource[i].ambient;
vec4 Idiff = gl_LightSource[i].diffuse * max(dot(N,L), 0.0);
Idiff = clamp(Idiff, 0.0, 1.0);
vec4 Ispec = gl_LightSource[i].specular * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
Ispec = clamp(Ispec, 0.0, 1.0);
finalColor += Iamb + Idiff + Ispec;
}
gl_FragColor = color * finalColor ;
}
Thanks in advance!
You can not get the color of the fragment you're writing to. In simple scenarios (like yours) what you can do is to enable blending and set the blending functions to achieve additive blending.
For more complex logic you'd create a framebuffer object, attach a texture to it, render your input(e.g. scene) to that texture, then switch to and render with another framebuffer(or the default "screen" one), this way you can sample your scene from the texture and add the lighting on top. Read how to do this in detail on WebGLFundamentals.com

OpenGL shadow mapping - shadow map texture doesn't get sampled at all?

I'm currently working on an OpenGL project and I'm trying to get shadow mapping to work properly. I could get to a point where the shadow map gets rendered into a texture, but it doesn't seem to get applied to the scenery when rendered. Here's the most important bits of my code:
The shadow map vertex shader, basically a simple pass through shader (also does some additional stuff like normals, but that shouldn't distract you); it basically just transforms the vertices so they're seen from the perspective of the light (it's a directional light but since we need to assume a position, it's basically a point far away):
#version 430 core
layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec3 v_texture;
layout(location = 3) in vec4 v_color;
out vec3 f_texture;
out vec3 f_normal;
out vec4 f_color;
uniform mat4 modelMatrix;
uniform mat4 depthViewMatrix;
uniform mat4 depthProjectionMatrix;
// Shadow map vertex shader.
void main() {
mat4 mvp = depthProjectionMatrix * depthViewMatrix * modelMatrix;
gl_Position = mvp * vec4(v_position, 1.0);
// Passing attributes on to the fragment shader
f_texture = v_texture;
f_normal = (transpose(inverse(modelMatrix)) * vec4(v_normal, 1.0)).xyz;
f_color = v_color;
}
The shadow map fragment shader that writes the depth value to a texture:
#version 430 core
layout(location = 0) out float fragmentDepth;
in vec3 f_texture;
in vec3 f_normal;
in vec4 f_color;
uniform vec3 lightDirection;
uniform sampler2DArray texSampler;
// Shadow map fragment shader.
void main() {
fragmentDepth = gl_FragCoord.z;
}
The vertex shader that actually renders the scene, but also calculates the position of the current vertex from the lights point of view (shadowCoord) to compare against the depth texture; it also applies a bias matrix, since the coordinates aren't in the correct [0, 1] interval for sampling:
#version 430 core
layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec3 v_texture;
layout(location = 3) in vec4 v_color;
out vec3 f_texture;
out vec3 f_normal;
out vec4 f_color;
out vec3 f_shadowCoord;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 depthViewMatrix;
uniform mat4 depthProjectionMatrix;
// Simple vertex shader.
void main() {
mat4 mvp = projectionMatrix * viewMatrix * modelMatrix;
gl_Position = mvp * vec4(v_position, 1.0);
// This bias matrix adjusts the projection of a given vertex on a texture to be within 0 and 1 for proper sampling
mat4 depthBias = mat4(0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0);
mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * modelMatrix;
mat4 biasedDMVP = depthBias * depthMVP;
// Passing attributes on to the fragment shader
f_shadowCoord = (biasedDMVP * vec4(v_position, 1.0)).xyz;
f_texture = v_texture;
f_normal = (transpose(inverse(modelMatrix)) * vec4(v_normal, 1.0)).xyz;
f_color = v_color;
}
The fragment shader that applies textures from a texture array and receives the depth texture (uniform sampler2D shadowMap) and checks if a fragment is behind something:
#version 430 core
in vec3 f_texture;
in vec3 f_normal;
in vec4 f_color;
in vec3 f_shadowCoord;
out vec4 color;
uniform vec3 lightDirection;
uniform sampler2D shadowMap;
uniform sampler2DArray tileTextureArray;
// Very basic fragment shader.
void main() {
float visibility = 1.0;
if (texture(shadowMap, f_shadowCoord.xy).z < f_shadowCoord.z) {
visibility = 0.5;
}
color = texture(tileTextureArray, f_texture) * visibility;
}
And finally: the function that renders multiple chunks to generate the shadow map and then renders the scene with the shadow map applied:
// Generating the shadow map
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
m_shadowShader->bind();
glViewport(0, 0, 1024, 1024);
glDisable(GL_CULL_FACE);
glm::vec3 lightDir = glm::vec3(1.0f, -0.5f, 1.0f);
glm::vec3 sunPosition = FPSCamera::getPosition() - lightDir * 64.0f;
glm::mat4 depthViewMatrix = glm::lookAt(sunPosition, FPSCamera::getPosition(), glm::vec3(0, 1, 0));
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-100.0f, 100.0f, -100.0f, 100.0f, 0.1f, 800.0f);
m_shadowShader->setUniformMatrix("depthViewMatrix", depthViewMatrix);
m_shadowShader->setUniformMatrix("depthProjectionMatrix", depthProjectionMatrix);
for (Chunk *chunk : m_chunks) {
m_shadowShader->setUniformMatrix("modelMatrix", chunk->getModelMatrix());
chunk->drawElements();
}
m_shadowShader->unbind();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Normal draw call
m_chunkShader->bind();
glEnable(GL_CULL_FACE);
glViewport(0, 0, Window::getWidth(), Window::getHeight());
glm::mat4 viewMatrix = FPSCamera::getViewMatrix();
glm::mat4 projectionMatrix = FPSCamera::getProjectionMatrix();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glActiveTexture(GL_TEXTURE1);
m_textures->bind();
m_chunkShader->setUniformMatrix("depthViewMatrix", depthViewMatrix);
m_chunkShader->setUniformMatrix("depthProjectionMatrix", depthProjectionMatrix);
m_chunkShader->setUniformMatrix("viewMatrix", viewMatrix);
m_chunkShader->setUniformMatrix("projectionMatrix", projectionMatrix);
m_chunkShader->setUniformVec3("lightDirection", lightDir);
m_chunkShader->setUniformInteger("shadowMap", 0);
m_chunkShader->setUniformInteger("tileTextureArray", 1);
for (Chunk *chunk : m_chunks) {
m_chunkShader->setUniformMatrix("modelMatrix", chunk->getModelMatrix());
chunk->drawElements();
}
Most of the code should be self-explanatory, I'm binding a FBO with a texture attached, we do a normal rendering call into the framebuffer, it gets rendered into a texture and then I'm trying to pass it into the shader for normal rendering. I've tested whether the texture gets properly generated and it does: See the generated shadow map here
However, when rendering the scene, all I see is this.
No shadows applied, visibility is 1.0 everywhere. I also use a debug context which works properly and logs errors when there are any, but it seems to be completely fine, no warnings or errors, so I'm the one doing something terribly wrong here. I'm on OpenGL 4.3 by the way.
Hopefully one of you can help me out on this, I've never got shadow maps to work before, this is the closest I've ever come, lol. Thanks in advance.
Commonly a mat4 OpenGL transformation matrix looks like this:
( X-axis.x, X-axis.y, X-axis.z, 0 )
( Y-axis.x, Y-axis.y, Y-axis.z, 0 )
( Z-axis.x, Z-axis.y, Z-axis.z, 0 )
( trans.x, trans.y, trans.z, 1 )
So your depthBias matrix, which you use to convert from normalized device coordinates (in ranage [-1, 1]) to texture coordinates (in range [0, 1]), should look like this:
mat4 depthBias = mat4(0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0);
or this:
mat4 depthBias = mat4(
vec4( 0.5, 0.0, 0.0, 0.0 ),
vec4( 0.0, 0.5, 0.0, 0.0 ),
vec4( 0.0, 0.0, 0.5, 0.0 ),
vec4( 0.5, 0.5, 0.5, 1.0 ) );
After you have transformed a vertex position by the model matrix, the view matrix and the projection matrix, the vertex position is in clip space (homogeneous coordinates). You have to convert from clip space to normalized device coordinates (cartesian coordinates in range [-1, 1]). This can be done by dividing, by the w component of the homogeneous coordinate:
mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * modelMatrix;
vec4 clipPos = depthMVP * vec4(v_position, 1.0);
vec4 ndcPos = vec4(clipPos.xyz / clipPos.w, 1.0);
f_shadowCoord = (depthBias * ndcPos).xyz;
A depth texture has one channel only. If you read data from the depth texture, then the data is contained in the x (or r) component of the vector.
Adapt the fragment shader code like this:
if ( texture(shadowMap, f_shadowCoord.xy).x < f_shadowCoord.z)
visibility = 0.5;
The Image Format specification of Khronos group says:
Image formats do not have to store each component. When the shader
samples such a texture, it will still resolve to a 4-value RGBA
vector. The components not stored by the image format are filled in
automatically. Zeros are used if R, G, or B is missing, while a
missing Alpha always resolves to 1.
see further:
Data Type (GLSL)
GLSL Programming/Vector and Matrix Operations
Transform the modelMatrix
How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?
OpenGL Shadow map problems
Addition to the solution:
This is an important part of the solution, but there was another step needed to properly render the shadow map. The second mistake was using the wrong component of the texture to compare against f_shadowCoord.z: it should've been
texture(shadowMap, f_shadowCoord.xy).r
instead of
texture(shadowMap, f_shadowCoord.xy).z

Strange GLSL behavior

I'm trying to implement tonemap correction in my own graphic engine and I'm using, as reference, the excellent demo from asylum2010 (https://github.com/asylum2010/Asylum_Tutorials)
Now look: this is an adaptation of the shader taken from the aforesaid demo:
#version 150
uniform sampler2D sampler0;
uniform vec2 texelSize;
uniform int prevLevel;
in vec2 tex;
out vec4 my_FragColor0;
void main()
{
const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721);
vec4 sample = texture(sampler0, tex + vec2(-0.5, -0.5) * texelSize);
float dt = dot(sample.rgb, LUMINANCE_VECTOR);
if (sample.r > 0.99 && sample.g > 0.99 && sample.b > 0.99)
{
if (dt > 0.9998)
{
if (log(0.0001 + dt) < 1.0) // <== NOTICE THIS!
my_FragColor0 = vec4(0.1, 0.0, 0.0, 1.0);
else
my_FragColor0 = vec4(1.0, 0.0, 0.0, 1.0);
}
else
my_FragColor0 = vec4(0.0, 0.0, 0.0, 1.0);
}
else
my_FragColor0 = vec4(0.0, 0.0, 0.0, 1.0);
}
and this is the shader I wrote:
#version 150
uniform sampler2D ColorMap;
uniform vec2 TexelSize;
uniform int PreviousLevel;
in vec2 fragmentUV;
out vec4 fragment;
void main()
{
const vec3 LUMINANCE_VECTOR = vec3(0.2125, 0.7154, 0.0721);
vec4 sample = texture(ColorMap, fragmentUV + vec2(-0.5, -0.5) * TexelSize);
float dt = dot(sample.rgb, LUMINANCE_VECTOR);
if (sample.r > 0.99 && sample.g > 0.99 && sample.b > 0.99)
{
if (dt > 0.9998)
{
if (log(0.0001 + dt) < 1.0) // <== NOTICE THIS!
fragment = vec4(0.1, 0.0, 0.0, 1.0);
else
fragment = vec4(1.0, 0.0, 0.0, 1.0);
}
else
fragment = vec4(0.0, 0.0, 0.0, 1.0);
}
else
fragment = vec4(0.0, 0.0, 0.0, 1.0);
}
You may notice that, except for the variable names, the code is exactly the same.
Now when I run the first shader on its own engine, it outputs a full red color for almost white pixels of the passed sampler is almost white (r, g and b > 0.99), meaning the result of the log calculation is greater than 1.0
When I run my own shader (of course passing the same sample and with the same texel size), it outputs a dark red, meaning the log result is lower than 1.0.
It looks to me that the result of the second shader is correct but this is not the point. The point is: how coult the result be different?
Ok for the ones interested I finally found the issue.
The error is actually the dot product. I was passing as ColorMap a texture with internal format GL_RGBA while it is supposed to be a floating point texture in order to store values higher than 1.
Also I would like to know the reason of the downvote I received. Knowing the reason will help me to avoid any mistake I possibly made posting the question.

How to avoid black lines between triangles on modern GPUs?

I am building a parametric 3d modeler with obj export.
I am really puzzled.
I have changed my GPU last night and now, there are cracks between the vertices, I can see what is behind. My old card was an Nvidia GTX275 and the one, NVIDIA GTX960. I didn't change anything in the code, shader or otherwise. I use only flat colors (not textures).
On the image below, the black lines that cut the pentagon into triangle shouldn't be there.
It seems to be purely an OpenGL problem as when I export the model and look in Blender, the faces are contiguous and there is no duplicate vertices.
the shader code is quite simple :
_VERTEX2 = """
#version 330
#extension GL_ARB_explicit_uniform_location : enable
layout(location = 0 ) in vec3 position;
layout(location = 1 ) in vec4 color;
layout(location = 2 ) in vec3 normal;
varying vec4 baseColor;
// uniform mat4 proj;
layout(location = 0) uniform mat4 view;
layout(location = 4) uniform mat4 proj;
varying vec3 fragVertexEc;
void main(void) {
gl_Position = proj * view * vec4(position, 1.0);
fragVertexEc = (view * vec4(position, 1.0)).xyz;
baseColor = color;
}
"""
_FRAGMENT2 = """
#version 330
#extension GL_OES_standard_derivatives : enable
varying vec3 fragVertexEc;
varying vec4 baseColor;
const vec3 lightPosEc = vec3(0,0,10);
const vec3 lightColor = vec3(1.0,1.0,1.0);
void main()
{
vec3 X = dFdx(fragVertexEc);
vec3 Y = dFdy(fragVertexEc);
vec3 normal=normalize(cross(X,Y));
vec3 lightDirection = normalize(lightPosEc - fragVertexEc);
float light = max(0.0, dot(lightDirection, normal));
gl_FragColor = vec4(normal, 1.0);
gl_FragColor = vec4(baseColor.xyz * light, baseColor.w);
}
"""
the rendering code is also quite simple :
def draw(self, view_transform, proj, transform):
self.shader.use()
gl_wrap.glBindVertexArray(self.vao)
try:
self.vbo.bind()
view_transform = view_transform * transform
GL.glUniformMatrix4fv(0, 1, False, (ctypes.c_float*16)(*view_transform.toList()))
GL.glUniformMatrix4fv(4, 1, False, (ctypes.c_float*16)(*proj.toList()))
GL.glEnableVertexAttribArray(self.shader.attrib['position'])
GL.glEnableVertexAttribArray(self.shader.attrib['color'])
GL.glEnableVertexAttribArray(self.shader.attrib['normal'])
STRIDE = 40
GL.glVertexAttribPointer(
self.shader.attrib['position'], len(Vector._fields), GL.GL_FLOAT,
False, STRIDE, self.vbo)
GL.glVertexAttribPointer(
self.shader.attrib['color'], len(Color._fields), GL.GL_FLOAT,
False, STRIDE, self.vbo+12)
GL.glVertexAttribPointer(
self.shader.attrib['normal'], len(Vector._fields), GL.GL_FLOAT,
False, STRIDE, self.vbo+28)
GL.glDrawElements(
GL.GL_TRIANGLES,
len(self.glindices),
self.index_type,
self.glindices)
finally:
self.vbo.unbind()
gl_wrap.glBindVertexArray(0)
self.shader.unuse()
A simple quad has the following data sent to OpenGL :
vertices ( flat array of pos+rgba+normal) :
[5.0, -3.061616997868383e-16, 5.0, 0.898, 0.0, 0.0, 1.0, 0.0, 1.0, 6.123233995736766e-17,
-5.0, 3.061616997868383e-16, -5.0, 0.898, 0.0, 0.0, 1.0, 0.0, 1.0, 6.123233995736766e-17,
-5.0, -3.061616997868383e-16, 5.0, 0.898, 0.0, 0.0, 1.0, 0.0, 1.0, 6.123233995736766e-17,
5.0, 3.061616997868383e-16, -5.0, 0.898, 0.0, 0.0, 1.0, 0.0, 1.0, 6.123233995736766e-17]
indices :: [0, 1, 2, 0, 3, 1]
ok, got it !
the strange display is due to glEnabled(GL_POLYGON_SMOOTH).
I had completely forgotten about it as my old card wasn't doing anything with this setting. It wasn't visible at least.
But the new one has the correct behaviour : it tries to anti-alias each triangle independently, hence the black lines.
Many thanks to #Jerem who helped me cover the other possibilities.

pixel perfect texture mapping with modern OpenGL

After deciding to try programming in modern OpenGL, I've left behind the fixed function pipeline and I'm not entirely sure about getting the same functionality I had before.
I'm trying to texture map quads with pixel perfect size, matching the texture size. For example, a 128x128 texture maps to a quad 128x128 in size.
This is my vertex shader.
#version 110
uniform float xpos;
uniform float ypos;
uniform float tw; // texture width in pixels
uniform float th; // texture height in pixels
attribute vec4 position;
varying vec2 texcoord;
void main()
{
mat4 projectionMatrix = mat4( 2.0/600.0, 0.0, 0.0, -1.0,
0.0, 2.0/800.0, 0.0, -1.0,
0.0, 0.0, -1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
gl_Position = position * projectionMatrix;
texcoord = (gl_Position.xy);
}
This is my fragment shader:
#version 110
uniform float fade_factor;
uniform sampler2D textures[1];
varying vec2 texcoord;
void main()
{
gl_FragColor = texture2D(textures[0], texcoord);
}
My vertex data is as such, where w and h are the width and height of the texture.
[
0, 0,
w, 0,
w, h,
0, h
]
I load a 128x128 texture and with these shaders I see the image repeated 4 times: http://i.stack.imgur.com/UY7Ts.jpg
Can anyone offer advice on the correct way to be able to translate and scale given the tw th, xpos, xpos uniforms?
There's a problem with this:
mat4 projectionMatrix = mat4( 2.0/600.0, 0.0, 0.0, -1.0,
0.0, 2.0/800.0, 0.0, -1.0,
0.0, 0.0, -1.0, 0.0,
0.0, 0.0, 0.0, 1.0);
gl_Position = position * projectionMatrix;
Transformation matices are right associative, i.e. you should multiply the opposite order. Also you normally don't specify a projection matrix in the shader, you pass it as a uniform. OpenGL provides you ready to use uniforms for projection and modelview. In OpenGL-3 core you can reuse the uniform names to stay compatible.
// predefined by OpenGL version < 3 core:
#if __VERSION__ < 400
uniform mat4 gl_ProjectionMatrix;
uniform mat4 gl_ModelviewMatrx;
uniform mat4 gl_ModelviewProjectionMatrix; // premultiplied gl_ProjectionMatrix * gl_ModelviewMatrix
uniform mat4 gl_ModelviewInverseTranspose; // needed for transformin normals
attribute vec4 gl_Vertex;
varying vec4 gl_TexCoord[];
#endif
void main()
{
gl_Position = gl_ModelviewProjectionMatrix * gl_Vertex;
}
Next you must understand that texture coordinates don't address texture pixels (texels), but that the texture should be understood as a interpolating function with the given sampling points; texture coordinates 0 or 1 don't hit the texel's centers, but lie exactly between the wraparound, thus blurring. As long as your quad on screen size exactly matches the texture dimensions this is fine. But as soon as you want to show just a subimage things get interesting (I leave it as an exercise to the reader to figure out the exact mapping; hint: You'll have the terms 0.5/dimension and (dimension - 1)/dimension in the solution)