Today a wild bug that I had several times before appeared again...!
And I don't know how to fix it. I hope you know a trick to solve the problem or an official way to get it work. Some of tutorials don't seem to work the correct way they promise.
I have some quads, displayed as pictures on my Surfaceview. I also have two textures. One for the tiles and the walls and one for the objects so far.
I draw tiles and objects in my own order of isometric system. (because of preventing overlapping images)
On my smartphone, it works very well. The tiles use the texture of tiles and the objects use the texture of objects.
As you can see. The room itself is drawn with the first texture. The ovens are drawn with the second. (I use Xperia Mini Pro)
A friend of mine uses Galaxy S. And now, something weird is happening. All quads are using the same texture. There's no obvious solution I found how to fix the bug.
Here the image taken with a camera:
In the second texture there are also red tiles, so don't wonder about the color. Fact is, that all tiles suddenly use the first texture. You cannot see any parts drawn with the second one.
Here are some of my drawing functions:
Function for drawing pictures:
public void render(float posX, float posY) {
// ======== Pass Masking Color ========
if (this.masked) {
GLES20.glUniform1i(ShaderCache.activeShader.masked, 1);
GLES20.glUniform3i(ShaderCache.activeShader.maskColor, this.maskColor.r, this.maskColor.g, this.maskColor.b);
} else {
GLES20.glUniform1i(ShaderCache.activeShader.masked, 0);
}
// ======== Passing Vertex And UV Attributes ========
if (ImageCache.lastUsedImageBuffer != this.buffer) {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, this.buffer);
GLES20.glVertexAttribPointer(ShaderCache.activeShader.attributeVertex, 2, GLES20.GL_FLOAT, false, 16, 0);
GLES20.glVertexAttribPointer(ShaderCache.activeShader.attributeUV, 2, GLES20.GL_FLOAT, false, 16, 8);
ImageCache.lastUsedImageBuffer = this.buffer;
}
// ======== Set Sampler Texture2D ========
if (TextureCache.lastTextureUnit != this.imagetexture.unit) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.imagetexture.unit);
GLES20.glUniform1i(ShaderCache.activeShader.texture, this.imagetexture.unit);
TextureCache.lastTextureUnit = this.imagetexture.unit;
}
// ======== Passing Image Position ========
GLES20.glUniform2f(ShaderCache.activeShader.position, posX, posY);
// ======== Draw Arrays With Image Vertices ========
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, this.vertices);
}
And here the function just for generating textureunits:
int[] textureID = new int[1];
GLES20.glGenTextures(1, textureID, 0);
this.unit = textureID[0];
GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + this.unit);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.unit);
Thank you so much!
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, this.imagetexture.unit);
GLES20.glUniform1i(ShaderCache.activeShader.texture, this.imagetexture.unit);
I believe this is wrong. The sampler2d uniform value that you pass to glsl should be the number of the sampler, not the id of the texture. If you bind texture id 3 to sampler 0 (glActiveTexture(GL_TEXTURE0)), then you pass 0 to the uniform sampler2d, not 3. If you bind a texture to GL_TEXTURE1, then the sampler2d value becomes 1, etc.
Related
I am a little bit new to OpenGL. I am trying to draw 3D dynamic trail for aircraft using Java OpenGL and WorldWind Java I can draw it by using glDrawArrays. Since the trail of the aircraft increases in every frame(25fps) I put new vertice values to verticeBuffer. I also use rightFloatBuffer and leftFloatBuffer to draw GL_LINE_STRIP to the both sides of the trail as you may see in the attached firstpicture. Since the trail gets longer and longer as the aircraft flies I thought that I need to create a large FloatBuffer for the triangles (verticeBuffer) and 2 large FloatBuffers for the left and right lines.
My first question: What is the most efficient way to draw to many triangles? Based on my code I think after 5 hours of flight the FloatBuffers will be full. If I try to update values with for loop in each frame and if I have, say 50-75 aircraft at the same time, this will reduce the performance. And because of that, I update one triangle at each frame.
Second question: I want to draw a trail like in the second picture. As you see trail gets more transparent as it gets closer to aircraft. And when the aircraft turns color the bottom side of the trail seems different. How can I do it?
Third question: I use gl.DepthMask(false) and draw line_strip and gl.DepthMask(true) to draw smooth lines without a gap between the lines. But this time aircraft trail which is added to the scene first always seems on the top no matter if it is under another trail. What can I do to overcome this? Or what can I do to draw smooth lines without gaps considering the amount of the vertices?
My code to draw the trail is below:
private final FloatBuffer verticeBuffer = GLBuffers.newDirectFloatBuffer(3000000);
private final FloatBuffer rightFloatBuffer = GLBuffers.newDirectFloatBuffer(1500000);
private final FloatBuffer leftFloatBuffer = GLBuffers.newDirectFloatBuffer(1500000);
protected void drawTrail() {
gl.glPushAttrib(GL2.GL_CURRENT_BIT | GL2.GL_COLOR_BUFFER_BIT | GL2.GL_LINE_BIT | GL2.GL_ENABLE_BIT
| GL2.GL_DEPTH_BUFFER_BIT);
try {
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL2.GL_SRC_ALPHA, GL2.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
doDrawTrail(dc);
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
gl.glDisable(GL.GL_BLEND);
} finally {
gl.glPopAttrib();
}
}
protected void doDrawTrail() {
updateTrailVertices();
float[] colors = new float[]{trailColor.getRed() / 255.f, trailColor.getGreen() / 255.f, trailColor.getBlue() / 255.f};
gl.glColor4f(colors[0], colors[1], colors[2], 0.6f);
gl.glEnable(GL2.GL_LINE_SMOOTH);
gl.glHint(GL2.GL_LINE_SMOOTH_HINT, GL2.GL_NICEST);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, verticeBuffer.rewind());
gl.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, verticeBuffer.limit() / 3);
gl.glColor3f(colors[0], colors[1], colors[2]);
gl.glLineWidth(3f);
//To draw smooth lines
gl.glDepthMask(false);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, rightFloatBuffer.rewind());
gl.glDrawArrays(GL.GL_LINE_STRIP, 0, rightFloatBuffer.limit() / 3);
gl.glVertexPointer(3, GL.GL_FLOAT, 0, leftFloatBuffer.rewind());
gl.glDrawArrays(GL.GL_LINE_STRIP, 0, leftFloatBuffer.limit() / 3);
gl.glDepthMask(true);
}
protected void updateTrailVertices() {
// In each frame when the aircraft position changes this function updates the last vertices
if (positionChange) {
positionChange = false;
//I need to set the position and the limit of the buffers to draw only updated parts
verticeBuffer.position(lastIndex * 2);
rightFloatBuffer.position(lastIndex);
leftFloatBuffer.position(lastIndex);
verticeBuffer.limit((lastIndex * 2) + 6);
rightFloatBuffer.limit(lastIndex + 3);
leftFloatBuffer.limit(lastIndex + 3);
List<Vec4> pointEdges = computeVec4(this.currentPosition, this.currentHeading, this.currentRoll, this.span);
verticeBuffer.put((float) pointEdges.get(0).x).put((float) pointEdges.get(0).y).put((float) pointEdges.get(0).z);
verticeBuffer.put((float) pointEdges.get(1).x).put((float) pointEdges.get(1).y).put((float) pointEdges.get(1).z);
rightFloatBuffer.put((float) pointEdges.get(0).x).put((float) pointEdges.get(0).y).put((float) pointEdges.get(0).z);
leftFloatBuffer.put((float) pointEdges.get(1).x).put((float) pointEdges.get(1).y).put((float) pointEdges.get(1).z);
lastIndex = rightFloatBuffer.position();
}
}
If you can use geometry shaders, the most efficient way to display the flight track is to have one vertexbuffer and render it as a line strip. The vertexbuffer contains the earlier locations and a normal vector (plane up direction). With these two values the the geometry shader you can transform it into quads. These quads should contain texture coordinates, which can be used in the fragment shader to display the borders.
You need only one draw call and reduce the data stored on the gpu to the absolute minimum.
The fading of the flight track can be done by using a uniform with the plane coordinates. One of your shades can calculate the distance to the plane and with that a alpha value for the pixel.
Please see bottom of question for the current solution I have gone for, thanks to Finlaybob, elect, gouessej
An appeal to the Elders of OpenGL.... I am having big problems with detecting the relative position of a mouse click on my textured plane.
I am making a game where I am drawing a single large square and texturing it with a large generated map texture. The view is always top down and you can only currently move the X Y and Z coordinates of that square.
Screenshot of the map
OpenGL init
screenRatio = (float)screenW / (float)screenH;
System.out.println("init");
glu = new GLU();
GL2 gl2 = drawable.getGL().getGL2();
gl2.glShadeModel( GL2.GL_SMOOTH );
gl2.glHint( GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST );
gl2.glClearColor( 0f, 0f, 0f, 1f );
gl2.glDepthMask(false);
gl2.glEnable(GL2.GL_DEPTH_TEST);
Set camera position
gl2.glViewport(0, 0, 1024, 768);
gl2.glMatrixMode( GL2.GL_PROJECTION );
gl2.glLoadIdentity();
glu.gluPerspective( 45, screenRatio, 1, 100 );
glu.gluLookAt( 0, 0, 3, 0, 0, 0, 0, 1, 0 );
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glLoadIdentity();
Move position to start drawing the map
// typical camera coord example:
// CENTRE: 0.0f, 0.0f, 10f
// FULL ZOOM OUT AND TOP LEFT: -25f, 25f, 40f
// move position
gl2.glTranslatef( -cameraX, -cameraY, -cameraZ );
I suspect the glTranslatef z-coord may be a suspect. As I am drawing the square 40f ( for example ) away from the origin
Map vertex information
// here are the coordinates/dimensions of my textured square ( my map )
float[] vertexArray = {
-25f, 25f,
25f, 25f,
25f, -25f,
25f, -25f,
};
Mouse click position calculation
"Borrowed" from java-tips 1628-how-to-use-gluunproject-in-jogl.html
int x = mouse.getX(), y = mouse.getY();
int viewport[] = new int[4];
double mvmatrix[] = new double[16];
double projmatrix[] = new double[16];
int realy = 0;
double wcoord[] = new double[4];
gl2.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
gl2.glGetDoublev(GL2.GL_MODELVIEW_MATRIX, mvmatrix, 0);
gl2.glGetDoublev(GL2.GL_PROJECTION_MATRIX, projmatrix, 0);
realy = viewport[3] - (int) y - 1;
glu.gluUnProject(
(double) x,
(double) realy,
0.0, // I have experimented with having this as 1.0 also
mvmatrix, 0,
projmatrix, 0,
viewport, 0,
wcoord, 0
);
Experimenting with the near/far bit ( 3rd param of gluUnProject ) seems to produce a better effect but there seems to be no sweet spot ( the best I found was 0.945 )
I would very much like mCX, mCY to be relative to the rendered map coordinates ( -25f - 25f ) regardless of Z position
mCX = (float)wcoord[0];
mCY = (float)wcoord[1];
Draw a rectangle at the translated coordinates
gl2.glColor3f(1.f, 0.f, 0.f);
gl2.glBegin(GL2.GL_QUADS);
gl2.glVertex2f( mCX-0.1f, mCY+0.1f );
gl2.glVertex2f( mCX+0.1f, mCY+0.1f );
gl2.glVertex2f( mCX+0.1f, mCY-0.1f );
gl2.glVertex2f( mCX-0.1f, mCY-0.1f );
gl2.glEnd();
Currently the coordinates work well in relation to x & y translation, if I click the very centre of the screen it will draw a box approximately in the correct place regardless of my glTranslatef movement. If I click away from the centre of the screen I see an exponential offset.
Demonstration of exponential offset
When I click the very dead centre of the screen it will draw this mauve square exactly around the mouse point, but with the smallest of movement it will create the following effect:
Fully zoomed in, click a couple of pixels right of centre
UPDATE AND WORKING... FOR NOW
At the time of generating the texture for my map I also generate an alternative texture which represents each "tile" as a different colour. In my initial and current attempt the colour of this tile is a function of it's X and Y coordinates ( a map is made up of 100 tiles across and 100 tiles down, so the x+y coordinates range from 0 - 99 )
I end up with a texture which looks like a gradient from green to red. The below code will, at the time of a mouse click, quickly render this texture ( imperceptible to user ) and read the rgb value under the mouse. We then turn that rgb value into a world coordinate and BOOM... the relative coordinates of my map are realised.
float pX, pY;
// render a colourised version of the scene for the purposes of "picking"
// https://www.opengl.org/archives/resources/faq/technical/selection.htm
public void pick ( GL2 gl2 ) {
// DRAW PICKING SCENE
gl2.glClearBufferfv(GL2.GL_COLOR, 0, clearColor);
gl2.glClearBufferfv(GL2.GL_DEPTH, 0, clearDepth);
gl2.glTranslatef( -cameraX, -cameraY, -cameraZ );
// draw my map but use the colour gradient texture
for ( Entity e : this.entities ) {
e.drawPick( gl2 );
}
// not sure what this does #cargo-cult
gl2.glFlush();
gl2.glFinish();
gl2.glPixelStorei(GL2.GL_UNPACK_ALIGNMENT, 1);
// After rendering ask OpenGL to read the colour of the screen at the given window coordinates!
FloatBuffer buffer = FloatBuffer.allocate(4);
int realy = 0;
int viewport[] = new int[4];
gl2.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
realy = viewport[3] - (int) mouse.getY() - 1;
gl2.glReadPixels( mouse.getX(), realy, 1, 1, GL2.GL_RGBA, GL2.GL_FLOAT, buffer);
float[] pixels = new float[3];
pixels = buffer.array();
// pixels holds rgb values respectively
// convert the red + green values back into x + y values
pX = (pixels[0] * 255) - 25f;
pY = -((pixels[1] * 255) - 25f);
// draw the proper texture
for ( Entity e : this.entities ) {
e.draw( gl2 );
}
}
You've almost got it. You're going to need a good value for Z in the unproject function though.
What you are trying to do is take the position of the cursor and multiply by a matrix to give a point in "3d space". Your matrices are likely 4x4 or 4x3, so you need a 4 component vector. (x,y,z,w)
When you draw your map, the existing point is multiplied by 1 or more matrices including the projection matrix. ( e.g. -25.0f,25.0f,0.0f,1.0f - actually a 3d point). When this is multiplied by all matrices, the GPU essentially gets back a value in normalised device coordinates (NDC) (between -1 and 1 in all axes) for that vertex.
To do the opposite and unproject you'll need to have a valid/good value for Z. The reason is that in NDC everything that is drawn is in -1,1 on all axes, to get everything in (further away things are squashed a bit). This is how you get flickering and weirdness if you have a huge > 100000 zFar distance for example, it still has to fit into -1,1.
The best way to do this is to use the depth buffer, by capturing the depth value it'll give you a good approxomation of the z coordinate in NDC, which you can pass to the unproject call.
The reason why 0.945 is the sweet spot is probably dependent on how far the camera is from your map or vice versa. It's usually the case that the depth buffer has much more detail closer to the near plane than the far - it's not linear.
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/ has a good visual near the bottom of the page, and is a good resource for intro to matrices in general:
You can see the distortion caused by moving to NDC. This is required for viewing from a perspactive viewpoint, but you need to take it into consideration when you transform backward too.
Colour picking as mentioned is also viable for picking, but will still require some work. Because you have a single object, you'll have to render each texel of the image with a different colour, output that to a separate colour buffer, check to see what colour is on the buffer and somehow relate that to a point in space. It could probably be done though, but I'd say colour picking is more suited to multiple objects.
From what I've read - the depth buffer one might be more suitable for you as it's one object, and the depth buffer will give you a Z coordinate for every point you click on. It could still be on your far plane, but it will still give you a value.
Alternatively, as suggested by #elect use an orthographic projection.
I'm working on a 2d engine. It already works quite good, but I keep getting pixel-errors.
For example, my window is 960x540 pixels, I draw a line from (0, 0) to (959, 0). I would expect that every pixel on scan-line 0 will be set to a color, but no: the right-most pixel is not drawn. Same problem when I draw vertically to pixel 539. I really need to draw to (960, 0) or (0, 540) to have it drawn.
As I was born in the pixel-era, I am convinced that this is not the correct result. When my screen was 320x200 pixels big, I could draw from 0 to 319 and from 0 to 199, and my screen would be full. Now I end up with a screen with a right/bottom pixel not drawn.
This can be due to different things:
where I expect the opengl line primitive is drawn from a pixel to a pixel inclusive, that last pixel just is actually exclusive? Is that it?
my projection matrix is incorrect?
I am under a false assumption that when I have a backbuffer of 960x540, that is actually has one pixel more?
Something else?
Can someone please help me? I have been looking into this problem for a long time now, and every time when I thought it was ok, I saw after a while that it actually wasn't.
Here is some of my code, I tried to strip it down as much as possible. When I call my line-function, every coordinate is added with 0.375, 0.375 to make it correct on both ATI and nvidia adapters.
int width = resX();
int height = resY();
for (int i = 0; i < height; i += 2)
rm->line(0, i, width - 1, i, vec4f(1, 0, 0, 1));
for (int i = 1; i < height; i += 2)
rm->line(0, i, width - 1, i, vec4f(0, 1, 0, 1));
// when I do this, one pixel to the right remains undrawn
void rendermachine::line(int x1, int y1, int x2, int y2, const vec4f &color)
{
... some code to decide what std::vector the coordinates should be pushed into
// m_z is a z-coordinate, I use z-buffering to preserve correct drawing orders
// vec2f(0, 0) is a texture-coordinate, the line is drawn without texturing
target->push_back(vertex(vec3f((float)x1 + 0.375f, (float)y1 + 0.375f, m_z), color, vec2f(0, 0)));
target->push_back(vertex(vec3f((float)x2 + 0.375f, (float)y2 + 0.375f, m_z), color, vec2f(0, 0)));
}
void rendermachine::update(...)
{
... render target object is queried for width and height, in my test it is just the back buffer so the window client resolution is returned
mat4f mP;
mP.setOrthographic(0, (float)width, (float)height, 0, 0, 8000000);
... all vertices are copied to video memory
... drawing
if (there are lines to draw)
glDrawArrays(GL_LINES, (int)offset, (int)lines.size());
...
}
// And the (very simple) shader to draw these lines
// Vertex shader
#version 120
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 mP;
varying vec4 vColor;
void main(void) {
gl_Position = mP * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
// Fragment shader
#version 120
#ifdef GL_ES
precision highp float;
#endif
varying vec4 vColor;
void main(void) {
gl_FragColor = vColor.rgb;
}
In OpenGL, lines are rasterized using the "Diamond Exit" rule. This is almost the same as saying that the end coordinate is exclusive, but not quite...
This is what the OpenGL spec has to say:
http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
Also have a look at the OpenGL FAQ, http://www.opengl.org/archives/resources/faq/technical/rasterization.htm, item "14.090 How do I obtain exact pixelization of lines?". It says "The OpenGL specification allows for a wide range of line rendering hardware, so exact pixelization may not be possible at all."
Many will argue that you should not use lines in OpenGL at all. Their behaviour is based on how ancient SGI hardware worked, not on what makes sense. (And lines with widths >1 are nearly impossible to use in a way that looks good!)
Note that OpenGL coordinate space has no notion of integers, everything is a float and the "centre" of an OpenGL pixel is really at the 0.5,0.5 instead of its top-left corner. Therefore, if you want a 1px wide line from 0,0 to 10,10 inclusive, you really had to draw a line from 0.5,0.5 to 10.5,10.5.
This will be especially apparent if you turn on anti-aliasing, if you have anti-aliasing and you try to draw from 50,0 to 50,100 you may see a blurry 2px wide line because the line fell in-between two pixels.
Here are two pictures of the same image:
this is what it looks like when viewed in preview...
and this is how it looks in my game...
Obviously the character is scaled down in my game, however, when I scale down the sprite in preview or pixelmator, it is still smooth. Even when the image is at a 1:1 scale it still has the jagged edges.
This is my render method
public void render(Camera camera, List<Entity> entities) {
shader.loadViewMatrix(Main.createViewMatrix(camera));
//per textured model
GL30.glBindVertexArray(((RenderComponent) entities.get(0).getComponent(EntityComponentType.RENDER)).texturedModel.getRawModel().getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
for(Entity e : entities) {
RenderComponent render = (RenderComponent) e.getComponent(EntityComponentType.RENDER);
//load transformation matrix per entity
shader.loadTransformationMatrix(Main.createTransformationMatrix(render.position, render.rx, render.ry, render.getScaleX(), render.getScaleY()));
shader.loadSprite((AnimationComponentContainer) e.getComponent(EntityComponentType.ANIMATION));
//activate texture for each entity
GL13.glActiveTexture(GL13.GL_TEXTURE0);
GL11.glBindTexture(GL11.GL_TEXTURE_2D, render.getTexturedModel().getTexture().getTextureID());
//render entity
GL11.glDrawElements(GL11.GL_TRIANGLES, render.getTexturedModel().getRawModel().getVertexCount(), GL11.GL_UNSIGNED_INT, 0);
}
//per textured model
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL30.glBindVertexArray(0);
}
And in my fragment shader I sample the image
vec4 color = texture(sampler, pass_TextureCoords);
and remove transparency
if(color.a < 0.5) discard;
out_Color = vec4(totalDiffuse, 1) * color;
My question is, how do I prevent the jagged edges from occurring (they are most prominent around his pants)? Or how do I smooth them out? The image itself if 512x1024
Make sure the internal rendering resolution of the game is large enough for the full image, and be sure that the game isn't casting any light onto the sprite itself, because it looks like the character is interacting with that green light over there and it's causing some gradient issues on the pants.
I am trying to implement simple shadow mapping technique in JOGL 2.0 and I struggle with rendering depth values into texture. Maybe I am doing it completely wrong but it is weird that rendering scene in color works properly. I have also found a similar question here at stackoverflow, which is asked here: Render the depth buffer into a texture using a frame buffer
and problem is solved by calling
gl.glDrawBuffer(GL2.GL_NONE);
gl.glReadBuffer(GL2.GL_NONE);
However, this does not help in my case. When I render scene in texture in color as normally, function works properly. Here is the result:
However, after trying to render depth values, it just renders white color (and something which doesn't correspond with the scene at all)
---- UPDATED code, which is working properly now:
private void initializeFBO3(GL2 gl) {
//Create frame buffer
gl.glGenFramebuffers(1, frameBufferID, 0);
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, frameBufferID[0]);
// ------------- Depth buffer texture --------------
gl.glGenTextures(1,depthBufferID,0);
gl.glBindTexture(GL2.GL_TEXTURE_2D, depthBufferID[0]);
gl.glTexImage2D(GL2.GL_TEXTURE_2D, // target texture type
0, // mipmap LOD level
GL2.GL_DEPTH_COMPONENT, // internal pixel format
//GL2.GL_DEPTH_COMPONENT
shadowMapWidth, // width of generated image
shadowMapHeight, // height of generated image
0, // border of image
GL2.GL_DEPTH_COMPONENT, // external pixel format
GL2.GL_UNSIGNED_INT, // datatype for each value
null); // buffer to store the texture in memory
//Some parameters
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP_TO_EDGE);
gl.glTexParameteri(GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP_TO_EDGE);
//Attach 2D texture to this FBO
gl.glFramebufferTexture2D(GL2.GL_FRAMEBUFFER,
GL2.GL_DEPTH_ATTACHMENT,
GL2.GL_TEXTURE_2D,
depthBufferID[0],0);
gl.glBindTexture(GL2.GL_TEXTURE_2D, 0);
//Disable color buffer
//https://stackoverflow.com/questions/12546368/render-the-depth-buffer-into-a-texture-using-a-frame-buffer
gl.glDrawBuffer(GL2.GL_NONE);
gl.glReadBuffer(GL2.GL_NONE);
//Set pixels ((width*2)* (height*2))
//It has to have twice the size of shadowmap size
pixels = GLBuffers.newDirectByteBuffer(shadowMapWidth*shadowMapHeight*4);
//Set default frame buffer before doing the check
//http://www.opengl.org/wiki/FBO#Completeness_Rules
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0);
int status = gl.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER);
// Always check that our framebuffer is ok
if(gl.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER) != GL2.GL_FRAMEBUFFER_COMPLETE)
{
System.err.println("Can not use FBO! Status error:" + status);
}
}
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2(); // get the OpenGL graphics context
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity(); // reset the model-view matrix
//Render scene into Frame buffer first
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, frameBufferID[0]);
renderSmallScene(gl);
//Read pixels from buffer
gl.glBindFramebuffer(GL2.GL_READ_FRAMEBUFFER, frameBufferID[0]);
//Read pixels
gl.glReadPixels(0, 0, shadowMapWidth, shadowMapHeight, GL2.GL_DEPTH_COMPONENT , GL2.GL_UNSIGNED_BYTE, pixels);
//Switch back to default FBO
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0);
drawSceneObjects(gl);
//Draw pixels, format has to have only one
gl.glDrawPixels(shadowMapWidth, shadowMapHeight, GL2.GL_LUMINANCE , GL2.GL_UNSIGNED_BYTE, pixels);
}
Working result:
You must read about using FBO and OpenGL in general.
In your code you create FBO and its attachments in each frame. That's wrong.It's huge overhead.Construct your FBOs on init only once.Second, you must bind FBO in order to draw into it (or read from it), otherwise OpenGL will draw into default FBO.Take a look here and here
So ,once your FBO is ready you render into it like this:
glBindFrameBuffer((GL_DRAW_FRAMEBUFFER, yourFbo);
drawSceneObjects(gl);
glBindFrameBuffer((GL_READ_FRAMEBUFFER, yourFbo);
readPixelsHere()
glBindFrameBuffer((GL_FRAMEBUFFER, 0);///switch to default FBO
In fact , in your case ,as you leave the FBO bound,just call
glBindFrameBuffer((GL_READ_FRAMEBUFFER, yourFbo);
after drawing your geometry.
Also , if you are not using shaders there is no reason to use textures as FBO attachments.Create render buffer instead.