I was learning about how to use textures with GLSL (in LWJGL) to create a simple fragment shader that blurs a texture. The first attempt (for testing purposes) was a very simple shader which just takes the original color values:
uniform sampler2D rectTexture;
void main(){
vec4 color = texture2D(rectTexture, gl_FragCoord.st);
gl_FragColor = color;
}
The shader compiles fine. After compilation I link and start to use it, up to this everything's working and no errors are reported. Then I try to set the uniform variable for the texture:
uniformTextureAddr = ARBShaderObjects.glGetUniformLocationARB(programObject, "rectTexture");
ARBMultitexture.glActiveTextureARB(ARBMultitexture.GL_TEXTURE0_ARB);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, texture);
ARBShaderObjects.glUniform1iARB(uniformTextureAddr, 0);
Then I just draw a quad with normal texcoords (0.0f-1.0f on both dimensions) but the texture doesn't show up. The texture itself is not the problem; I draw a second quad next to the first one without my fragment shader an it shows up as you would expect. The basic approach is taken from NeHe: GLSL - An Introduction. uniformTextureAddr is not -1 and if I use an even simpler shader, which just turns every pixel red, I get a red quad. As expected. So the bug has to be in the whole sampler2D business. Trivial mistakes, such as the quad simply being out of frame, are also ruled out by this.
And yes, after drawing without the shader I call glUseProgramObject(programObj) with my shader again.
By the way, this is running on Windows XP SP3 with a ATI Radeon Catalyst 10.6 driver and LWJGL version 2.4.2.
UPDATE: I think something might be wrong with the program itself. When I add another variable to the shader:
uniform sampler2D secondTexture;
uniform sampler2D rectTexture;
void main(){
vec4 color = texture2D(rectTexture, gl_FragCoord.st);
gl_FragColor = color;
}
and call glGetUniformLocationARB(programObject, "secondTexture"); it just returns -1, even though it should be there. Log info still only says:
Info log:
Fragment shader was successfully compiled to run on hardware.
UPDATE 2:
The actual texture is copied from the backbuffer. A simple white line is drawn in a smaller viewport and then copied to a texture:
GL11.glViewport(0, 0, 256, 256);
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glColor3f(1.0f, 1.0f, 1.0f);
GL11.glBegin(GL11.GL_LINES);
GL11.glVertex3f(0.0f, 0.0f, 0.0f);
GL11.glVertex3f(256.0f, 256.0f, 0.0f);
GL11.glEnd();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glCopyTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_LUMINANCE, 0, 0, 256, 256, 0);
GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
GL11.glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
But like I said, I don't think the texture is the actual problem, since it shows up fine on the second quad without my custom shader. Also, don't worry about binding; this is the only texture in the program and is only bound once at the very beginning.
Here is my drawing code:
ARBShaderObjects.glUseProgramObjectARB(programObject);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0.0f, 1.0f);
GL11.glVertex3f(0.0f, 0.0f, 0.0f);
GL11.glTexCoord2f(1.0f, 1.0f);
GL11.glVertex3f(256.0f, 0.0f, 0.0f);
GL11.glTexCoord2f(1.0f, 0.0f);
GL11.glVertex3f(256.0f, 256.0f, 0.0f);
GL11.glTexCoord2f(0.0f, 0.0f);
GL11.glVertex3f(0.0f, 256.0f, 0.0f);
GL11.glEnd();
ARBShaderObjects.glUseProgramObjectARB(0);
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0.0f, 1.0f);
GL11.glVertex3f(256.0f, 0.0f, 0.0f);
GL11.glTexCoord2f(1.0f, 1.0f);
GL11.glVertex3f(512.0f, 0.0f, 0.0f);
GL11.glTexCoord2f(1.0f, 0.0f);
GL11.glVertex3f(512.0f, 256.0f, 0.0f);
GL11.glTexCoord2f(0.0f, 0.0f);
GL11.glVertex3f(256.0f, 256.0f, 0.0f);
GL11.glEnd();
You are providing texture coordinates but not using them in shader. Instead, you are using gl_FragCoord, which gives you window coordinates:
texture2D(rectTexture, gl_FragCoord.st)
You should use gl_MultiTexCoord0.xy instead.
Since you are using GL_TEXTURE_2D to store the rectTexture, the sampler will expect normalized texture coordinates (i.e. [0.0, 1.0]).
So your shader should be modified to:
uniform vec2 invTextureSize; // contains [1.0 / w, 1.0 / h];
uniform sampler2D rectTexture;
void main() {
vec4 color = texture2D( rectTexture, gl_FragCoord.st * invTextureSize.xy );
gl_FragColor = color;
}
In addition, you will need to setup the GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_WRAP_S and GL_TEXTURE_WRAP_T properly for that texture object.
If not, most opengl driver will provide a rgba = [0, 0, 0, 0] color to the shader.
Please see the reference of glTexParameter
The following configuration works for most GL_TEXTURE_2D objects
glTexParameter( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameter( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameter( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameter( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
Hope this helps.
Are you using a vertex shader also? Some cards require that you provide both a vertex and a fragment shader.
Related
I'm using LWJGL to draw "tiles", or textured 2D squares on the screen. However, the texture coordinate is always (0, 0) and therefore the textured square only uses the first pixel colour to fill it.
This is my vertex shader:
#version 330 core
in vec4 in_Position;
in vec4 in_Color;
in vec2 in_TextureCoord;
out vec4 pass_Color;
out vec2 pass_TextureCoord;
void main(void) {
gl_Position = in_Position;
pass_Color = in_Color;
pass_TextureCoord = in_TextureCoord;
}
And this is my fragment shader:
#version 330 core
uniform sampler2D texture_diffuse;
in vec4 pass_Color;
in vec2 pass_TextureCoord;
out vec4 out_Color;
void main(void) {
out_Color = pass_Color;
// Override out_Color with our texture pixel
out_Color = texture(texture_diffuse, pass_TextureCoord);
}
And this is essentially the code I'm using to draw the square:
ARBShaderObjects.glUseProgramObjectARB(shaderProgram);
glBindTexture(GL_TEXTURE_2D, sprite.getId());
glBegin(GL11.GL_QUADS);
glVertex2d(screenMinX, screenMinY);
glTexCoord2d(0.0, 0.0);
glVertex2d(screenMaxX, screenMinY);
glTexCoord2d(1.0, 0.0);
glVertex2d(screenMaxX, screenMaxY);
glTexCoord2d(1.0, 1.0);
glVertex2d(screenMinX, screenMaxY);
glTexCoord2d(0.0, 1.0);
glEnd();
// release the shader
ARBShaderObjects.glUseProgramObjectARB(0);
I cannot fix it because I don't know how the above code works in the first place. I have not told the shaders what in_Position, in_Color or in_TextureCoord are but the first two seem to work just fine. It is in_TextureCoord, which is eventually passed to the fragment shader, that seems to have a constant value of (0, 0) - I have determined that by setting the output colour of the fragment shader to have one of the channels equal to the X-coordinate of the texture coordinate. It remained a solid colour throughout the square, indicating that there was no change in texture coordinate.
The square produced with the code above should be textured but instead is painted a solid colour - the first pixel of the texture given. How can I change the code to make the texture coordinate change accordingly? If I appear to have some misunderstanding to how this all fits together, please correct me.
This is the tutorial I used to try to accomplish the above.
p.s. I am aware that the Java snippet is using deprecated immediate-mode, but I don't know how to use glDrawArrays or any other commonly suggested method to accomplish the same. Could you help me to change this?
I am aware that the Java snippet is using deprecated immediate-mode, but I don't know how to use glDrawArrays or any other commonly suggested method to accomplish the same. Could you help me to change this?
Since you do not need the attribute in_Color anymore, you have to delete the attribute from the vertex shader (and of course also pass_Color from the vertex shader and the fragment shader).
Otherwise, you have to expand my solution logically by the color attribute.
Set up an array for the vertex positions an for the texture coordinates:
float[] posData = {
screenMinX, screenMinY, 0.0, 1.0,
screenMaxX, screenMinY, 0.0, 1.0,
screenMaxX, screenMaxY, 0.0, 1.0,
screenMinX, screenMaxY, 0.0, 1.0 };
float[] texData = { 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 };
Generate a vertex array object:
int vaoObj = glGenVertexArrays();
glBindVertexArray(vaoObj);
Generate array buffers for the vertices and texture coordinates, enable the attribute indices and associate them buffers to the attribute indices:
FloatBuffer posBuffer = MemoryUtil.memAllocFloat(posData.length);
posBuffer.put(posData).flip();
FloatBuffer texBuffer = MemoryUtil.memAllocFloat(texData.length);
texBuffer.put(texData).flip();
int vboPosObj = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboPosObj);
glBufferData(GL_ARRAY_BUFFER, posBuffer, GL_STATIC_DRAW);
// index 0 to associate with "in_Position"
glVertexAttribPointer(0, 4, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(0); // 0 = attribute index of "in_Position"
int vboTexObj = glGenBuffers();
glBindBuffer(GL_ARRAY_BUFFER, vboTexObj);
glBufferData(GL_ARRAY_BUFFER, texBuffer, GL_STATIC_DRAW);
// index 0 to associate with "in_TextureCoord"
glVertexAttribPointer(1, 2, GL_FLOAT, false, 0, 0);
glEnableVertexAttribArray(1); // 1 = attribute index of "in_TextureCoord"
Release the vertex array object:
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
You have to specify the attribute indices of the attributes in_Position and in_TextureCoord.
Either you use explicit layout specifications in the vertex shader:
layout (location = 0) in vec4 in_Position;
layout (location = 1) in vec2 in_TextureCoord;
Or you specify the attribute indices in the shader program, right before you link the shader program (glLinkProgram).
glBindAttribLocation(shaderProgramID, 0, "in_Position");
glBindAttribLocation(shaderProgramID, 1, "in_TextureCoord");
If the object is to be drawn, it is sufficient to bind the Vertex Array Object:
glBindVertexArray(vaoObj);
glDrawArrays(GL_QUADS, 0, 4); // 4 = number of vertices
glBindVertexArray(0);
Note, if a buffer objects or a vertex array object is not further used, it has to be deleted, to prevent memory leaks. Buffer objects are deleted by glDeleteBuffers and vertex array objects are deleted by glDeleteVertexArrays.
Buffer objects are not "created under" vertex array objects, it is not sufficient to delete the vertex array object only (see OpenGL Vertex Array/Buffer Objects)
If you use need to use box to show some texture image that will be fit the full box area you can use two triangles for it and following parameters for -1,-1 to 1,1 area (that can be used with appropriate shaders to show).
Vertex (two triangles coordinates):
-1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f
Then use can use following texture coordinates for full size:
0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
just doing some tinkering with lwjgl and making some 2d shapes. Not sure what I'm doing wrong but I'm not able to show more than the first green square on screen. Here is the code for my window loop function:
private void loop() {
// This line is critical for LWJGL's interoperation with GLFW's
// OpenGL context, or any context that is managed externally.
// LWJGL detects the context that is current in the current thread,
// creates the GLCapabilities instance and makes the OpenGL
// bindings available for use.
GL.createCapabilities();
GLFWVidMode vidmode = glfwGetVideoMode(glfwGetPrimaryMonitor());
glOrtho(0, vidmode.width(),0, vidmode.height(),-1,1);
// Set the clear color
glClearColor(.0f, 0.6f, 0.6f, 0.0f);
// Run the rendering loop until the user has attempted to close
// the window or has pressed the ESCAPE key.
while (!glfwWindowShouldClose(window) && !dataH.isGameOver()) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear the framebuffer
glBegin(GL_QUADS);
{
glColor3f(0.1f, 1.0f, 0.1f); // Green
glVertex2d(xMapCentre - 100,yMapCentre - 100);
glVertex2d(xMapCentre - 100,yMapCentre + 100);
glVertex2d(xMapCentre + 100,yMapCentre + 100);
glVertex2d(xMapCentre + 100,yMapCentre - 100);
glColor3f(0.2f, 0.2f, 0.2f); // Dark Gray
glVertex2f(-0.9f, -0.7f);
glColor3f(1.0f, 1.0f, 1.0f); // White
glVertex2f(-0.5f, -0.7f);
glColor3f(0.2f, 0.2f, 0.2f); // Dark Gray
glVertex2f(-0.5f, -0.3f);
glColor3f(1.0f, 1.0f, 1.0f); // White
glVertex2f(-0.9f, -0.3f);
}
glEnd();
glBegin(GL_TRIANGLES); // Each set of 3 vertices form a triangle
{
glColor3f(0.0f, 0.0f, 1.0f); // Blue
glVertex2f(0.1f, -0.6f);
glVertex2f(0.7f, -0.6f);
glVertex2f(0.4f, -0.1f);
glColor3f(1.0f, 0.0f, 0.0f); // Red
glVertex2f(0.3f, -0.4f);
glColor3f(0.0f, 1.0f, 0.0f); // Green
glVertex2f(0.9f, -0.4f);
glColor3f(0.0f, 0.0f, 1.0f); // Blue
glVertex2f(0.6f, -0.9f);
}
glEnd();
glfwSwapBuffers(window); // swap the color buffers
// Poll for window events. The key callback above will only be
// invoked during this call.
glfwPollEvents();
}
}
Any help would be appreciated, and let me know if I'm being too vague. Thanks.
Generally, when rendering 2D structures in 3D space, you should disable the back-face culling glDisable(GL_CULL_FACE). Otherwise you can only see them from one side. In your shaders you have to be aware of the normal direction.
In the 2D only case, check for your winding order of the triangles if you want to have back or front face culling, set glFontFace(GL_CCW) or glFrontFace(GL_CW) for counter-clockwise and clockwise winding order respectively. (I cant confirm if the winding order makes a difference in 2D when using glVertex2f)
Also try to diable the depth test and depth write glDisable(GL_DEPTH_TEST) and glDepthMask(GL_FALSE).
I have been learning how to use shaders in lwjgl. Now i have ran into an issue, where i need to rotate my mask for shading to get different results. How can i modify the mask transformation/rotation after it is bind, or do i need to modify it before. I tried almost anything but couldn't find an existing question / instructions. Any help will be greatly appreciated! This is my code for drawing a textured rectangle using my custom shader program.
private static void drawTexture(int shaderProgram, int texID1, int texID2) {
glUseProgram(shaderProgram);
setTextureUnits(shaderProgram);
bindTextures(texture1.getTextureID(), texture2.getTextureID(), mask.getTextureID());
glBegin(GL11.GL_QUADS);
glColor3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0,0);
glVertex2f(-0.5f,-0.5f);
glColor3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(1,0);
glVertex2f(+0.5f,-0.5f);
glColor3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(1,1);
glVertex2f(+0.5f,+0.5f);
glColor3f(1.0f, 1.0f, 1.0f);
glTexCoord2f(0,1);
glVertex2f(-0.5f,+0.5f);
glEnd();
glUseProgram(0);
}
Here is the answer to my own question:
create a matrix2 variable, and rotate the textCoords of your mask. the -+0.5's are for rotate around center. To fix any issues like exposed corners, clamp your textures on to the edge.
shader:
mat2 textureMatrix = mat2(cos(angle), sin(angle), -sin(angle), cos(angle));
float mask = texture2D(mask, textureMatrix*(gl_TexCoord[0].xy-0.5)+0.5).a;
I have some cube models and a lantern model in the "world" (with normals) and a light source which is placed in specific coordinates. The problem comes when I try move around the models, position of lightsource changes every frame to viewport position. Here is my initialization part of code, which contain lighting init:
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glShadeModel(GL11.GL_SMOOTH);
GL11.glClearDepth(1.0f);
GL11.glClearColor(0.0f, 0.75f, 1.0f, 1);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glDepthFunc(GL11.GL_LESS);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glLoadIdentity();
GL11.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST);
ByteBuffer temp = ByteBuffer.allocateDirect(16);
temp.order(ByteOrder.nativeOrder());
byf = temp;
GL11.glLight(GL11.GL_LIGHT1, GL11.GL_AMBIENT, (FloatBuffer)temp.asFloatBuffer().put(lightAmbient).flip()); // Setup The Ambient Light
GL11.glLight(GL11.GL_LIGHT1, GL11.GL_DIFFUSE, (FloatBuffer)temp.asFloatBuffer().put(lightDiffuse).flip()); // Setup The Diffuse Light
GL11.glLight(GL11.GL_LIGHT1, GL11.GL_POSITION,(FloatBuffer)temp.asFloatBuffer().put(lightPosition).flip()); // Position The Light
GL11.glEnable(GL11.GL_LIGHT1);
GL11.glEnable(GL11.GL_LIGHTING);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glLoadIdentity();
GL11.glFogi(GL11.GL_FOG_MODE, fogMode[fogfilter]);
temp.asFloatBuffer().put(fogColor).flip();
GL11.glFog(GL11.GL_FOG_COLOR, temp.asFloatBuffer());
GL11.glFogf(GL11.GL_FOG_DENSITY, 0.35f);
GL11.glHint(GL11.GL_FOG_HINT, GL11.GL_DONT_CARE);
GL11.glFogf(GL11.GL_FOG_START, 1.0f);
GL11.glFogf(GL11.GL_FOG_END, 5.0f);
GL11.glEnable(GL11.GL_FOG);
I have seen some similar problems but their solutions didn't help me at all. I know that the problem is with irregular order of setting Matrixes, but I have no idea which one (Matrix) and where I should change.
I tried to place setting Modelview matrix before the init of lighting but it didn't work for me.
By the way, I don't want to set the correct light position every frame, it works for me but it can slow the render.
Your'e probably using a code similar to this or glulookat().
GL11.glTranslatef(Camera.x, Camera.y, Camera.z);
GL11.glRotatef(Camera.roatationz, 0.0f, 0.0f, 1.0f);
GL11.glRotatef(Camera.roatationx, 1.0f, 0.0f, 0.0f);
GL11.glRotatef(Camera.roatationy, 0.0f, 1.0f, 0.0f);
//Render stuff here
Your light has to move as well. :)
The following code produces the image that follows. The image I am using for the background is 640 x 480, as is the displayMode. The texture background is a .bmp and is loaded with the Slick texture loader. I am confuse to why it is not filling the Quad and why it is reflected.
EDIT: The background of my OpenGL scene is pink, the black you see is from the Quad created. The background image is the green block with a 2px light blue border with "test" plastered on it.
private void renderBackground(){
float w = displayMode.getHeight()/2;
float h = displayMode.getWidth()/2;
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPushMatrix();
GL11.glLoadIdentity();
GLU.gluOrtho2D(-w, w, -h, h);
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPushMatrix();
GL11.glLoadIdentity();
GL11.glDisable(GL11.GL_DEPTH_TEST);
if(useTextures)background.bind();
GL11.glBegin(GL11.GL_QUADS);
GL11.glTexCoord2f(0.0f, 0.0f);
GL11.glVertex2f(-w,-h);
GL11.glTexCoord2f(1.0f, 0.0f);
GL11.glVertex2f(w,-h);
GL11.glTexCoord2f(1.0f, 1.0f);
GL11.glVertex2f(w, h);
GL11.glTexCoord2f(0.0f, 1.0f);
GL11.glVertex2f(-w, h);
GL11.glEnd();
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glMatrixMode(GL11.GL_PROJECTION);
GL11.glPopMatrix();
GL11.glMatrixMode(GL11.GL_MODELVIEW);
GL11.glPopMatrix();
}
Now when I add GL11.glTranslatef(20.0f, 20.0f, 0.0f); you will notice that the pink appears, which is the colour created int my "initGL" method:
GL11.glClearColor(1.0f, 0.75f, 0.796f, 0.0f);
My GL_PROJECTION contains the following before pushing it, my GL_MODELVIEW is unmodified when renderBackground() is called.
GL11.glMatrixMode(GL11.GL_PROJECTION); // Select The Projection Matrix
GL11.glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
GLU.gluPerspective(45.0f, (float) displayMode.getWidth() / (float) displayMode.getHeight(), 0.1f, 25.0f);
//position camera
GLU.gluLookAt(5.0f, 3.0f, -5.0f, 0.0f, 0.0f, -10.0f, 0.0f, 1.0f, 0.0f);
GL11.glMatrixMode(GL11.GL_MODELVIEW); // Select The Modelview Matrix
I need more information to determine the problem, but here is a list with some possibilities.
1) You are using an older video card, which does not support texture non-power of 2, since you are using a library to load the texture, maybe it is detecting it, creating a power of two image, and filling it with black.
2) You (or some library you are using) changed the matrix of the texture matrix stack, and it is changing the texture coordinates.
3) You are doing something wrong when you load the texture (or call the library to do so).
The first thing I would check is if your video card supports texture non-power of 2 extension. You can check it at runtime, see how to detect if openGL/card supports non power of 2?
What I see first, is that you compute
float w = displayMode.getHeight()/2;
float h = displayMode.getWidth()/2;
switched?
Second, the texture could be flipped because the loader flipped it (when I remember right this happened to me, too especially with BMPs).