I have an array of sampler2D that looks like so:
uniform sampler2D u_Textures[2];. I want to be able to render more textures(in this case 2) in the same drawcall. In my fragment shader, if I set the color output value to somethiung like red, it does show me 2 red squares witch leads me to belive I did something wrong when binding the textures.
My code:
Texture tex1("Texture/lin.png");
tex1.Bind(0);
Texture tex2("Texture/font8.png");
tex2.Bind(1);
auto loc = glGetUniformLocation(sh.getRendererID(), "u_Textures");
GLint samplers[2] = { 0, 1 };
glUniform1iv(loc, 2, samplers);
void Texture::Bind(unsigned int slot) const {
glActiveTexture(slot + GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_RendererID);
}
And this is my fragment shader:
#version 450 core
layout(location = 0) out vec4 color;
in vec2 v_TexCoord;
in float v_texIndex;
uniform sampler2D u_Textures[2];
void main()
{
int index = int(v_texIndex);
vec4 texColor = texture(u_Textures[index], v_TexCoord);
if (texColor.a == 0.0) {
// this line fills the a = 0.0f pixels with the color red
color = vec4(1.0f, 0.0f, 0.0f, 1.0f);
}
else color = texColor;
}
Also, it only draws the tex2 texture on the screen.
This is my verticie attributes:
float pos[24 * 2] = {
// position xy z texture coordinate, texture index
-2.0f, -1.5f, 0.0f, 0.0f, 0.0f, 0.0f,
-1.5f, -1.5f, 0.0f, 1.0f, 0.0f, 0.0f,
-1.5f, -2.0f, 0.0f, 1.0f, 1.0f, 0.0f, // right side bottom
-2.0f, -2.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f,
1.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
1.5f, 1.5f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 1.5f, 0.0f, 0.0f, 1.0f, 1.0f
};
No matter how I chenge the texture index, it only draws 1 of those 2 textures.
You cannot use a fragment shader input variable to index an array of texture samplers. You have to use a sampler2DArray (GL_TEXTURE_2D_ARRAY) instead of an array of sampler2D (GL_TEXTURE_2D).
int index = int(v_texIndex);
vec4 texColor = texture(u_Textures[index], v_TexCoord);
is undefined behavior because v_texIndex is a fragment shader input variable and therefore not a dynamically uniform expression. See GLSL 4.60 Specification - 4.1.7. Opaque Types
[...] Texture-combined sampler types are opaque types, [...]. When aggregated into arrays within a shader, they can only be indexed with a dynamically uniform integral expression, otherwise results are undefined.
Example using sampler2DArray:
#version 450 core
layout(location = 0) out vec4 color;
in vec2 v_TexCoord;
in float v_texIndex;
uniform sampler2DArray u_Textures;
void main()
{
color = texture(u_Textures, vec3(v_TexCoord.xy, v_texIndex));
}
texture is overloaded for all sampler types. The texture coordinates and texture layer need not to dynamically uniform, but the index into a sampler array has to be dynamically uniform.
To be clear, the problem isn't with the array of sampler (the problem is not sampler2D u_Textures[2];). The problem is the indexing. The problem is that v_texIndex is not dynamically uniform (the problem is in float v_texIndex;). It works when the index is dynamically uniform (e.g. uniform float v_texIndex; will work). Also the specification just says that the result is undefined. So there may be some systems where it works.
Related
after I've set up the (orthogonal) projection matrix for my simple 2d game, nothing renders on the screen. I am using cglm (glm but in c) and compared the results of cglm with the normal glm ortho projection implementation that renders well, and the results of the projection matrix match. Here is my render loop:
void RenderSprite(const struct Sprite *sprite) {
struct Shader *shader = GetSpriteShader(sprite);
UseShader(shader);
/* cglm starts here */
mat4 proj;
glm_ortho(0.0f, 800.0f, 600.0f, 0.0f, -1.0f, 1.0f, proj); /* screen width: 800, height: 600 */
mat4 model;
glm_mat4_identity(model); /* an identity model matrix - does nothing */
/* cglm ends here */
SetShaderUniformMat4(shader, "u_Projection", proj); /* set the relevant uniforms */
SetShaderUniformMat4(shader, "u_Model", model);
/* finally, bind the VAO and call the draw call (note that I am not using batch rendering - I am using just a simple plain rendering system) */
glBindVertexArray(ezGetSpriteVAO(sprite));
glDrawElements(GL_TRIANGLES, ezGetSpriteIndexCount(sprite), GL_UNSIGNED_INT, 0);
}
However, this results in a blank screen - nothing renders. I believe I've did everything in order - but the problem is nothing renders.
For anyone interested, here is my vertex shader:
#version 330 core
layout (location = 0) in vec3 pos;
layout (location = 1) in vec2 uv;
uniform mat4 u_Model;
uniform mat4 u_Projection;
void main() {
gl_Position = u_Projection * u_Model * vec4(pos, 1.0f);
}
And here is my fragment shader:
#version 330 core
out vec4 color;
void main() {
color = vec4(1.0f);
}
As far as I am aware, cglm matrices are ordered column-major, which OpenGL wants.
Any help would be appreciated.
Thanks in advance.
EDIT
The sprite coordinates are (in this case it is the vertex data, I guess):
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 0.5f, 0.0f
EDIT 2
After #BDL's comment, I have adjusted the vertex data as following:
float vertices[] = {
/* Position UV */
5.0f, 5.0f, 0.0f, 0.0f, 0.0f,// bottom left
10.0f, 5.0f, 0.0f, 1.0f, 0.0f, // bottom right
10.0f, 10.0f, 0.0f, 1.0f, 1.0f, // top right
5.0f, 10.0f, 0.0f, 0.0f, 1.0f // top left
};
But, I can't see anything on the screen - nothing is being rendered at this point.
As #BDL and others have suggested, here is my final render loop that works like a charm right now:
(posting as a reference)
void RenderSprite(const struct Sprite *sprite) {
ASSERT(sprite, "[ERROR]: Can't render a sprite which is NULL\n");
struct Shader *shader = GetSpriteShader(sprite);
UseShader(shader);
mat4 proj;
glm_ortho(0.0f, 800.0f, 600.0f, 0.0f, -1.0f, 1.0f, proj);
mat4 model, view;
glm_mat4_identity(model);
glm_mat4_identity(view);
SetShaderUniformMat4(shader, "u_Projection", proj);
SetShaderUniformMat4(shader, "u_Model", model);
SetShaderUniformMat4(shader, "u_View", view);
glBindVertexArray(GetSpriteVAO(sprite));
glDrawElements(GL_TRIANGLES, GetSpriteIndexCount(sprite), GL_UNSIGNED_INT, 0);
}
And here are my coordinates:
float vertices[] = {
/* Position UV */
350.0f, 350.0f, 0.0f, 0.0f, 0.0f,// bottom left
450.0f, 350.0f, 0.0f, 1.0f, 0.0f, // bottom right
450.0f, 250.0f, 0.0f, 1.0f, 1.0f, // top right
350.0f, 250.0f, 0.0f, 0.0f, 1.0f // top left
};
Also here are my shaders:
const char *default_vs = "#version 330 core\n"
"layout (location = 0) in vec3 pos;\n"
"layout (location = 1) in vec2 uv;\n"
"uniform mat4 u_Model;\n"
"uniform mat4 u_Projection;\n"
"uniform mat4 u_View;\n"
"void main() {\n"
" gl_Position = u_Projection * u_View * u_Model * vec4(pos, 1.0f);\n"
"}";
const char *default_fs = "#version 330 core\n"
"out vec4 color;\n"
"void main() {\n"
" color = vec4(1.0f);\n"
"}";
Hope this helps anyone that is having the same problem!
So I have an AtlasTexture that contains all the tiles I need to draw a tile map.
Right now I pass the AtlasTexture through a uniform, and the idea is to change the texture coordinate to select just the portion I need from the atlas.
The issue is that I can only specify on the fragment shader to cut the texture from the zero origin, is it possible to specify an offsetX to tell to the shader where I want to start drawing?
float vertices[] = {
// aPosition // aTextureCoordinate
0.0f, 0.0f, 0.0f, 0.0f,
100.0f, 0.0f, 1.0f, 0.0f,
0.0f, 100.0f, 0.0f, 1.0f,
100.0f, 100.0f, 1.0f, 1.0f,
};
uint32_t indices[] = {0, 1, 2, 2, 3, 1};
Vertex shader
#version 330 core
layout(location = 0) in vec2 aPosition;
layout(location = 1) in vec2 aTextureCoordinate;
out vec2 textureCoordinate;
void main() {
gl_Position = vec4( aPosition.x, aPosition.y, 1.0f, 1.0f);
textureCoordinate = vec2(
aTextureCoordinate.x / 3.0f, // This selects the first tile in the uAtlasTexture
aTextureCoordinate.y
);
}
Fragment shader
#version 330 core
in vec2 textureCoordinate;
uniform sampler2D uAtlasTexture; // Has 3 tiles
out vec4 color;
void main() {
color = texture(uAtlasTexture, textureCoordinate);
}
Use an Uniform variable for the offset. `vec2(1.0/3.0 + aTextureCoordinate.x / 3.0f, aTextureCoordinate.y); "selects2 the 2nd tile. Use a uniform instead of 1.0/3.0:
#version 330 core
layout(location = 0) in vec2 aPosition;
layout(location = 1) in vec2 aTextureCoordinate;
out vec2 textureCoordinate;
uniform float textureOffsetX;
void main() {
gl_Position = vec4( aPosition.x, aPosition.y, 1.0f, 1.0f);
textureCoordinate = vec2(
textureOffsetX + aTextureCoordinate.x / 3.0f,
aTextureCoordinate.y
);
}
I've read several articles here at stackoverflow and in some books. But I can't find the error in my code. I have an deferred renderer and saved albedo, depth and normals (including spec) inside the g-buffer. Moreover created an shadow map from a light source from top of the scene.
It looks like this:
Albedo (R8G8B8A8):
Normal (R8G8B8A8):
Linear Depth (F32):
Shadow map from light source (linear depth) (500 meter above camera):
Ok. My shader code of the deferred with shadow mapping look like this:
I have uploaded row major matrices.
Vertex Shader:
layout(row_major) uniform UVSViewMatrix
{
mat4 m_ScreenMatrix;
};
layout(location = 0) in vec3 VertexPosition;
smooth out vec2 PSTexCoord;
void main()
{
vec4 Position = vec4(VertexPosition.xyz, 1.0f);
PSTexCoord = Position.xy;
gl_Position = Position * m_ScreenMatrix;
}
Fragment Shader:
#version 410
// -----------------------------------------------------------------------------
// Input from engine
// -----------------------------------------------------------------------------
layout(row_major) uniform UPSCameraProperties
{
mat4 m_ProjectionMatrix;
mat4 m_CameraView;
vec3 m_CameraPosition;
vec3 m_CameraDirection;
};
layout(row_major) uniform UPSLightProperties
{
mat4 m_LightProjection;
mat4 m_LightView;
vec4 m_LightPosition;
vec4 m_LightAmbientIntensity;
vec4 m_LightDiffuseIntensity;
vec4 m_LightSpecularIntensity;
};
uniform sampler2D PSTextureAlbedo;
uniform sampler2D PSTextureNormalSpecular;
uniform sampler2D PSTextureDepth;
uniform sampler2D PSTextureShadowMap;
// -----------------------------------------------------------------------------
// Input from vertex shader
// ----------------------------------------------------------------- ------------
smooth in vec2 PSTexCoord;
// -----------------------------------------------------------------------------
// Output to systembuffer
// -----------------------------------------------------------------------------
layout (location = 0) out vec4 PSOutput;
// -----------------------------------------------------------------------------
// Functions
// -----------------------------------------------------------------------------
vec3 GetViewSpacePositionFromDepth(float _Depth, vec2 _ScreenPosition, mat4 _InvertedProjectionMatrix)
{
// -----------------------------------------------------------------------------
// Information from:
// http://mynameismjp.wordpress.com/2009/03/10/reconstructing-position-from-depth/
// -----------------------------------------------------------------------------
vec4 ScreenPosition;
ScreenPosition.x = _ScreenPosition.x * 2.0f - 1.0f;
ScreenPosition.y = _ScreenPosition.y * 2.0f - 1.0f;
ScreenPosition.z = _Depth * 2.0f - 1.0f;
ScreenPosition.w = 1.0f;
// -----------------------------------------------------------------------------
// Transform by the inverse projection matrix
// -----------------------------------------------------------------------------
vec4 VSPosition = ScreenPosition * _InvertedProjectionMatrix;
// -----------------------------------------------------------------------------
// Divide by w to get the view-space position
// -----------------------------------------------------------------------------
return (VSPosition.xyz / VSPosition.w);
}
// -----------------------------------------------------------------------------
float GetShadowAtPosition(vec3 _WSPosition)
{
// -----------------------------------------------------------------------------
// Set worls space coord into light projection by multiply with light
// view and projection matrix;
// -----------------------------------------------------------------------------
vec4 LSPosition = vec4(_WSPosition, 1.0f) * m_LightView * m_LightProjection;
// -----------------------------------------------------------------------------
// Divide xyz by w to get the position in light view's clip space.
// -----------------------------------------------------------------------------
LSPosition.xyz /= LSPosition.w;
// -----------------------------------------------------------------------------
// Get uv texcoords for this position
// -----------------------------------------------------------------------------
vec3 ShadowCoord = LSPosition.xyz * 0.5f + 0.5f;
// -----------------------------------------------------------------------------
// Get final depth at this texcoord and compare it with the real
// position z value (do a manual depth test)
// -----------------------------------------------------------------------------
float DepthValue = texture( PSTextureShadowMap, vec2(ShadowCoord.x, ShadowCoord.y) ).r;
float Shadow = 1.0f;
if (ShadowCoord.z > DepthValue)
{
Shadow = 0.3f;
}
return Shadow;
}
// -----------------------------------------------------------------------------
// Main
// -----------------------------------------------------------------------------
void main()
{
// -----------------------------------------------------------------------------
// Get informations from g-buffer
// -----------------------------------------------------------------------------
vec2 TexCoord = vec2(PSTexCoord.s, 1.0f - PSTexCoord.t);
vec4 AlbedoColor = texture(PSTextureAlbedo , TexCoord);
vec4 NormalSpec = texture(PSTextureNormalSpecular, TexCoord);
float Depth = texture(PSTextureDepth , TexCoord).r;
vec3 VSPosition = GetViewSpacePositionFromDepth(Depth, TexCoord, inverse(m_ProjectionMatrix));
vec3 Normal = normalize(NormalSpec.xyz);
float SpecularExponent = NormalSpec.w;
vec4 WSPosition = vec4(VSPosition, 1.0f) * inverse(m_CameraView);
// -----------------------------------------------------------------------------
// Compute lighting (Light Accumulation)
// -----------------------------------------------------------------------------
vec3 CameraPosition = m_CameraPosition.xyz;
vec3 LightPosition = m_LightPosition.xyz;
vec3 EyeDirection = WSPosition.xyz - CameraPosition;
vec3 LightDirection = normalize(LightPosition - WSPosition.xyz);
vec3 LightReflection = normalize(-reflect(LightDirection, Normal));
vec4 AmbientColor = m_LightAmbientIntensity;
vec4 DiffuseColor = clamp(m_LightDiffuseIntensity * max(dot(Normal, LightDirection), 0.0f), 0.0f, 1.0f);
vec4 SpecularColor = clamp(m_LightSpecularIntensity * pow(max(dot(LightReflection, EyeDirection), 0.0f), SpecularExponent), 0.0f, 1.0f);
float Shadow = GetShadowAtPosition(WSPosition.xyz);
// -----------------------------------------------------------------------------
// Final result
// -----------------------------------------------------------------------------
PSOutput = vec4((AlbedoColor * (AmbientColor + DiffuseColor) * Shadow).xyz, 1.0f);
}
At the end my result look like this:
Did anyone can see my mistake?
Some measurement results:
ShadowCoord.xy is always 0.5, 0.5
ShadowCoord.z seams to be 1.0f
Here are some variable values:
LightProjection
(
1.29903805f, 0.0f, 0.0, 0.0f,
0.0f, 1.73205066f, 0.0f, 0.0f,
0.0f, 0.0f, -1.00024426f, -1.0f,
0.0f, 0.0f, -1.00024426f, 0.0f
);
LightView
(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, -1500.0f, 1.0f
);
CameraProjection
(
1.29903805f, 0.0f, 0.0f, 0.0f,
0.0f, 1.73205066f, 0.0f, 0.0f,
0.0f, 0.0f, -1.00024426f, -1.0f,
0.0f, 0.0f, -1.00024426f, 0.0f
);
CameraView
(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, -1000.0f, 1.0f
);
One issue I can see is a difference between linear and hyperbolic depth. It looks like your "Linear Depth (F32)" G-buffer depth is actually hyperbolic, which is fine because the code expects this. However the light's depth is in fact linear but is then compared against the clip space depth after perspective divide.
It'd probably be easiest to just make the light buffer's depth hyperbolic (gl_FragCoord.z), but changing to compare against eye-space Z should work too:
float ShadowCoordZ = -(vec4(_WSPosition, 1.0f) * m_LightView).z;
The bit about "ShadowCoord.xy is always 0.5, 0.5" is confusing. The G-buffer texture coord seems to work. I can't really tell with the shadow, but do the lighting equations work? If so maybe something's wrong with the matrices? I'd also pass in the inverse of your matrices as uniforms so time isn't spent computing it in the shader.
I just started to learning OpenGL 3.1 and I'm trying to implement deferred shading to my engine(framework?). I wrote simple shaders for first stage, lighting stage and deferred stage.
Lighting stage takes the diffuse color from deferred texture and saves it in lighting texture. Deferred stage draws the lighting texture. In lighting shader is a bug and scene is very strange. It looks like this, and it should look like this. Lighting stage vertex shader:
#version 150
in vec4 vertex;
out vec2 position;
void main(void)
{
gl_Position = vertex*2-1;
gl_Position.z = 0.0;
position.xy = vertex.xy;
}
Lighting stage fragment shader:
#version 150
in vec2 position;
uniform sampler2D diffuseTexture;
uniform sampler2D positionTexture;
out vec4 lightingOutput;
void main()
{
vec4 diffuse = texture(diffuseTexture, vec2(position.x, position.y));
vec4 position = texture(positionTexture, position.xy);
vec4 ambient = vec4(0.05, 0.05, 0.05, 1.0) * diffuse;
lightingOutput = diffuse;
}
That's what I render in lighting stage:
static const GLfloat _vertices[] =
{
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
};
And that's how I render it:
glUseProgram( programID[2] );
glEnableVertexAttribArray(vertexID[1]);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(
vertexID[1],
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, positionTexture);
glUniform1i(positionTextureID[1], 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuseTexture);
glUniform1i(diffuseTextureID[1], 0);
glDrawArrays( GL_TRIANGLES, 0, 6 );
glDisableVertexAttribArray(vertexID[1]);
If you need all the code it's here www.dropbox.com/s/hvfe4v4pb1pfxb3/code.zip.
How to fix that strange problem?
I have two images, and with the help of the instruction here:
http://en.wikibooks.org/wiki/OpenGL_Programming/Intermediate/Textures
I was able store them separately, into two separate textures, and upload them into video memory:
gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
Now, how would I access these textures with shaders to multiply these two textures?
For example, I found this example, about multiplication using shaders:
http://www.opengl.org/wiki/Texture_Combiners
//Vertex shader
#version 110
attribute vec4 InVertex;
attribute vec2 InTexCoord0;
attribute vec2 InTexCoord1;
uniform mat4 ProjectionModelviewMatrix;
varying vec2 TexCoord0;
varying vec2 TexCoord1; //Or just use TexCoord0
//------------------------
void main()
{
gl_Position = ProjectionModelviewMatrix * InVertex;
TexCoord0 = InTexCoord0;
TexCoord1 = InTexCoord1;
}
//------------------------
//Fragment shader
#version 110
uniform sampler2D Texture0;
uniform sampler2D Texture1;
//------------------------
varying vec2 TexCoord0;
varying vec2 TexCoord1; //Or just use TexCoord0
//------------------------
void main()
{
vec4 texel = texture2D(Texture0, TexCoord0);
texel *= texture2D(Texture1, TexCoord1);
gl_FragColor = texel;
}
But how would I make the textures that I've uploaded in a form of Vertex, so that I can use this Fragment shaders to accomplish this multiplication.
All I did was generated gluBuild2DMipmaps, but now I don't know how to apply Vertex/Fragment shaders to my texture?
Assume you have a quad where the first three values are vertex coord. and the last two your TexCoord.
-1.0f,-1.0f, 1.0f, 0.0f, 0.0f,
1.0f,-1.0f, 1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
1.0f,-1.0f, 1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f,
you have to submit your Hardware different uniforms and attributes:
first of all the (after MVP and so on.) the vertex and textcoord:
glEnableVertexAttribArray(VAA_Normal);
glVertexAttribPointer(VAA_Normal, 3, GL_FLOAT, GL_TRUE, 5*sizeof(GLfloat), (const GLvoid*)(5 * sizeof(GLfloat)));
glEnableVertexAttribArray(VAA_TexCoord);
glVertexAttribPointer(VAA_TexCoord, 2, GL_FLOAT, GL_TRUE, 5*sizeof(GLfloat), (const GLvoid*)(3 * sizeof(GLfloat)));
(VAA_Normal = glGetAttribLocation(aProgram, attribName);)
last but not least the important Texture:
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, aTexture);
dont forget: its up to you how you combine different textures
edit:
sorry forgot
glUniform1i(glGetUniformLocation(aProgramID, "TEXTURE0"), 0);