How to make the texture in sliced mode? - opengl

I have a GL.GL_QUAD_STRIP with a texture , since the GL.GL_QUAD_STRIP sizes are much larger then the texture image sizes , this image become stretched and blur , So I thought maybe there is a way to set this texture in "sliced" mode to make it more clearly and sharp .
Edit: "sliced" I mean in the location the images end I would be start to be drawn again except to be appear one whit hard stretch .
That's what I have so far -
double m_x , m_y , m_z ;
Texture m_cubeSides ;
public void display(GLAutoDrawable gLDrawable)
{
final GL gl = gLDrawable.getGL();
gl.glTexParameteri ( GL.GL_TEXTURE_2D,GL.GL_TEXTURE_WRAP_T,GL.GL_LINEAR_MIPMAP_LINEAR);
gl.glTexParameteri( GL.GL_TEXTURE_2D,GL.GL_TEXTURE_WRAP_S,GL.GL_LINEAR_MIPMAP_LINEAR);
m_cubeSides.bind();
gl.glBegin(GL.GL_QUAD_STRIP);
// Quad 1
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3d(m_x, m_y, 0);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3d(m_x, 0, 0);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3d(0, m_y, 0);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3d(0, 0, 0);
// Quad 2 - front
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3d(0, m_y, m_z);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3d(0, 0, m_z);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3d(m_x, m_y, m_z);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3d(m_x, 0, m_z);
// Quad 3 - east side
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3d(m_x, m_y, m_z);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3d(m_x, 0, m_z);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3d(m_x, m_y, 0);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3d(m_x, 0, 0);
// Quad 4 - west side
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex3d(0, m_y, 0);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3d(0, 0, 0);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3d(0, m_y, m_z);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex3d(0, 0, m_z);
gl.glEnd();
}

I'm not sure what you mean by sliced mode, however changing the texture coordinates would work. There are an awful lot of calls to glTexCoord2f so perhaps a variable to replace all the instances of 1.0f in the glTexCoord2f calls and then vary that till you get a nice result. You've already set the texture wrap mode to repeat which is required.
Something like:
float textureMax = 5.0f;
...
gl.glTexCoord2f(textureMax , 0.0f);
gl.glVertex3d(m_x, m_y, 0);
gl.glTexCoord2f(textureMax ,textureMax );
gl.glVertex3d(m_x, 0, 0);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex3d(0, m_y, 0);
gl.glTexCoord2f(0.0f, textureMax );
gl.glVertex3d(0, 0, 0);
The downside of this though is that you need a texture you can tile, otherwise this may not look great.
Another option is a bigger texture, of course :)

Related

Image cropping for non standard aspect ratio format

I am facing the problem of rendering the correct image with some portion of the edges cropped out. I can observe this only for non-standard aspect ratio.
In my case width is 1228 and height is 972 which is yielding an aspect ratio of 1.26.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
glClearColor(0.0, 0.0, 0.0, 1.0);
float vx = float(m_uiImageWidth) / float(m_uiImageWidth);
float vy = float(m_uiImageHeight) / float(m_uiImageWidth);
glEnable(GL_TEXTURE_2D);
glTexImage2D(GL_TEXTURE_2D, 0, 3, m_uiImageWidth, m_uiImageHeight, 0, GL_BGR, GL_UNSIGNED_BYTE, m_arrayBufferVS1);
glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, m_texture);
//glTranslatef(0.0f, 0.0f, -1.36f);
glTranslatef(0.0f, 0.0f, -1.358f);
//Normal
if(m_bContextMenuNormal)
glRotatef(180, 1, 0, 0);
else if (m_bContextMenuRotate180 && m_bContextMenuMirror)
{
//do nothing
}
else if(m_bContextMenuMirror)
glRotatef(180, 0, 0, 0);
else if(m_bContextMenuRotate180)
glRotatef(180, 0, 1, 0);
glScalef(1, -1, 1);
glBegin(GL_QUADS);
glTexCoord2f(1.0f, 1.0f); //top right
glVertex3f(vx, vy, 0.0f);
glTexCoord2f(0.0f, 1.0f); // left top
glVertex3f(-vx, vy, 0.0f);
glTexCoord2f(0.0f, 0.0f); //left bottom
glVertex3f(-vx, -vy, 0.0f);
glTexCoord2f(1.0f, 0.0f); //right bottom
glVertex3f(vx, -vy, 0.0f);
glEnd();
glDisable(GL_TEXTURE_2D);
This is my code snippet. It would be a great help if anyone points out the mistake I have made and suggestions to fix.
modify your calls to glTexCoord2f, the decimal values are interpolated between the four vertexes and then multiplied by the width and height of the image to calculate the coordinates of each pixel from the texture to draw to the screen. if you want to crop the left and right of your image with an aspect ratio of 1.26 into a square you would use the following texture coordinates:
glTexCoord2f(1.0f - 0.13f, 1.0f); //top right
glTexCoord2f(0.0f + 0.13f, 1.0f); // left top
glTexCoord2f(0.0f + 0.13f, 0.0f); //left bottom
glTexCoord2f(1.0f - 0.13f, 0.0f); //right bottom
0.13 * 1228 is 159.64 pixels, and when you remove 159.64 pixels from either side of your 1228 pixel wide texture the remaining portion of the image is 972 pixels wide, meaning the aspect ratio of the pixels drawn will be 1:1 because your texture is 972 pixels tall

Text color is not correct

void text(string str)
{
for (int i = 0; i < str.length(); i++)
{
glColor3f(0.0f, 0.0f, 0.0f);
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, str[i]);
}
}
void render(void)
{
int width = glutGet(GLUT_WINDOW_WIDTH);
int height = glutGet(GLUT_WINDOW_HEIGHT);
if (height == 0) height = 1;
GLfloat aspect = (GLfloat)width / (GLfloat)height;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_SCISSOR_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, aspect, 0.1f, 100.0f);
// Top view - top left
glViewport(0, 0, width/2, height/2);
glScissor(0, 0, width/2, height/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
PilotView(0.0f, 0.0f, -5.0f, 0.0f, 0.0f, 0.0f, 1.0f);
glRasterPos3f(-0.1f, -0.1f, 4.0f);
text("Front");
diode();
// Corner view - top right
glViewport(width/2, 0, width/2, height/2);
glScissor(width/2, 0, width/2, height/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
PilotView(0.0f, 0.0f, -5.0f, 0.0f, -90.0f, 0.0f, 1.0f);
glRasterPos3f(4.0f, -0.1f, 0.1f);
text("Right");
diode();
// Front view - bottom left
glViewport(0, height/2, width/2, height/2);
glScissor(0, height/2, width/2, height/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
PilotView(0.0f, 0.0f, -5.0f, 90.0f, 0.0f, 0.0f, 1.0f);
glRasterPos3f(-0.1f, 4.0f, 0.0f);
text("Top");
diode();
// Right view - bottom right
glViewport(width/2, height/2, width/2, height/2);
glScissor(width/2, height/2, width/2, height/2);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
PilotView(0.0f, 0.0f, -5.0f, 20.0f, 0.0f, 0.0f, 1.0f);
glRasterPos3f(-0.1f, 4.0f, 0.0f);
text("Fro4nt");
diode();
glDisable(GL_SCISSOR_TEST);
glutSwapBuffers();
}
I'm not sure where the white "Front" and the yellow "Top"/"Right" is coming from (in terms of color). They all should be black. Does anyone know what the issue is?
Here is what the output looks like:
As suspected, this may come as a shock but glRasterPos (...) actually tracks the "current" color when you call that function. That is, whatever color was set before glRasterPos (...) was called, applies as the "current color" for drawing operations at that position. Think of it almost as the rasterizer's analog to glVertex (...), as I will explain below.
You need to set the current color before you call glRasterPos (...), to that end you should remove the glColor3f (...) call completely from your text (...) function, or perhaps modify that function to do both - set the color and then the raster pos, then draw the text.
glRasterPos — specify the raster position for pixel operations:
The current raster position consists of three window coordinates (x, y, z), a clip coordinate value (w), an eye coordinate distance, a valid bit, and associated color data and texture coordinates.

Render to texture, the texture is not shown completely

Basically when I am rendering to texture, it looks like some part of the texture got lost.
package org.yourorghere;
import com.jogamp.opengl.util.GLBuffers;
import java.awt.Component;
import java.nio.ByteBuffer;
import javax.media.opengl.*;
import javax.media.opengl.glu.GLU;
public class GLRenderer implements GLEventListener {
int[] textureID = new int[1];
private int floorWidth=48, floorHeight=48;
int[] frameBufferID = new int[1];
int[] depthRenderBufferID = new int[1];
ByteBuffer pixels;
GLU glu;
public void init(GLAutoDrawable drawable) {
glu = new GLU();
System.out.println("init");
GL2 gl = drawable.getGL().getGL2();
System.err.println("INIT GL IS: " + gl.getClass().getName());
// Setup the drawing area and shading mode
gl.glShadeModel(GL2.GL_SMOOTH); // try setting this to GL_FLAT and see what happens.
renderShadowsToTexture(gl);
gl.glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
}
public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
}
public void display(GLAutoDrawable drawable) {
GL2 gl = drawable.getGL().getGL2();
System.out.println("display");
float a = 1.0f;
gl.glMatrixMode(GL2.GL_PROJECTION);
// Reset the current matrix to the "identity"
gl.glLoadIdentity();
glu.gluPerspective(60.0f, (((Component)drawable).getWidth()/
((Component)drawable).getHeight()), 1.0f, 50.0f);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glLoadIdentity();
glu.gluLookAt(0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f);
// Clear the drawing area
gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT);
gl.glTranslatef(-2.5f, 0.0f, 0.0f);
gl.glEnable(GL2.GL_TEXTURE_2D);
gl.glBindTexture(GL2.GL_TEXTURE_2D, textureID[0]);
gl.glColor3f(1.0f, 1.0f, 1.0f);
gl.glBegin(GL2.GL_QUADS);
gl.glTexCoord2f(0, 0);
gl.glVertex3f(-1.0f,-1.0f, 0.0f);
gl.glTexCoord2f(0, a);
gl.glVertex3f(-1.0f, 1.0f, 0.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex3f( 1.0f, 1.0f, 0.0f);
gl.glTexCoord2f(a, 0);
gl.glVertex3f( 1.0f,-1.0f, 0.0f);
gl.glEnd();
gl.glDisable(GL2.GL_TEXTURE_2D);
gl.glRasterPos2d(3, -2);
gl.glDrawPixels(floorWidth, floorHeight, GL2.GL_RGBA, GL2.GL_UNSIGNED_BYTE, pixels);
}
private void renderShadowsToTexture(GL2 gl) {
gl.glGenTextures(1, textureID, 0);
gl.glBindTexture(GL2.GL_TEXTURE_2D, textureID[0]);
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);
// null means reserve texture memory, but texels are undefined
gl.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGB, floorWidth, floorHeight,
0, GL2.GL_RGB, GL2.GL_FLOAT, null);
gl.glGenFramebuffers(1, frameBufferID, 0);
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, frameBufferID[0]);
//Attach 2D texture to this FBO
gl.glFramebufferTexture2D(GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0,
GL2.GL_TEXTURE_2D, textureID[0], 0);
// depth buffer
gl.glGenRenderbuffers(1, depthRenderBufferID, 0);
gl.glBindRenderbuffer(GL2.GL_RENDERBUFFER, depthRenderBufferID[0]);
gl.glRenderbufferStorage(GL2.GL_RENDERBUFFER, GL2.GL_DEPTH_COMPONENT,
floorWidth, floorHeight);
gl.glFramebufferRenderbuffer(GL2.GL_FRAMEBUFFER, GL2.GL_DEPTH_ATTACHMENT,
GL2.GL_RENDERBUFFER, depthRenderBufferID[0]);
if(gl.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER) == GL2.GL_FRAMEBUFFER_COMPLETE)
System.out.println("[Viewer] GL_FRAMEBUFFER_COMPLETE!!");
else
System.out.println("..cazzo ^^");
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
gl.glPointSize(10.0f);
gl.glBegin(GL2.GL_POINTS);
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glVertex2d(1.0f, 1.0f); // THIS IS NOT SHOWN
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex2d(-1.0f, -1.0f);
gl.glVertex2d(-0.9f, -0.9f);
gl.glEnd();
gl.glPopMatrix();
pixels = GLBuffers.newDirectByteBuffer(floorWidth*floorHeight*4);
gl.glReadPixels(0, 0, floorWidth, floorHeight, GL2.GL_RGBA,
GL2.GL_UNSIGNED_BYTE, pixels);
System.out.println("glIsTexture: "+gl.glIsTexture(textureID[0]));
// bind the back buffer for rendering
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0);
}
public void dispose(GLAutoDrawable glad) {
// throw new UnsupportedOperationException("Not supported yet.");
System.out.println("dispose");
}
}
Starting from the left, the triangle and the first quad are rendered normally using the display() while the last quad on the right and the one below are respectively the quad rendered with the texture mapped on it and the quad showing what is inside the texture itself.
Basically I do not see the red point, only the blue ones. Why?
I'm not familiar with this particular OpenGL wrapper, but what I notice about your code is that in renderShadowsToTexture you do not configure two things: the viewport and the projection matrix. Both of these will affect the scaling of the resulting image.
The projection matrix will probably be the identity matrix (since you haven't run gluPerspective at all yet), which is reasonable for the coordinates you're using. But it is still good practice to set it explicitly to what you want for the sake of clarity and robustness (possibly with a pushMatrix/popMatrix around).
But I don't see where your code configures the viewport at all? Perhaps JOGL does that for you? If so, it will be the size of your window, not the size of the texture. This too-large viewport will cause portions of your scene to be cut off at the high-coordinate end, which is consistent with the texture you are seeing (note that the second blue point should be very close to the first one but shows up far away). So, you need to add to renderShadowsToTexture:
glViewport(0, 0, floorWidth, floorHeight)
and probably restore it afterward (or use glPushAttrib/glPopAttrib of GL_VIEWPORT_BIT).
Also, color components are red-green-blue, so your missing point will be green, not red.
According to Kevin Reid's answer (thanks to him) I revised renderShadowsToTexture(GL2 gl) and it worked great for me. I just wanted to share it below for newcomers.
private void renderShadowsToTexture(GL2 gl) {
gl.glGenTextures(1, textureID, 0);
gl.glBindTexture(GL2.GL_TEXTURE_2D, textureID[0]);
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);
// null means reserve texture memory, but texels are undefined
gl.glTexImage2D(GL2.GL_TEXTURE_2D, 0, GL2.GL_RGB, floorWidth,
floorHeight, 0, GL2.GL_RGB, GL2.GL_FLOAT, null);
gl.glGenFramebuffers(1, frameBufferID, 0);
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, frameBufferID[0]);
// Attach 2D texture to this FBO
gl.glFramebufferTexture2D(GL2.GL_FRAMEBUFFER, GL2.GL_COLOR_ATTACHMENT0,
GL2.GL_TEXTURE_2D, textureID[0], 0);
// depth buffer
gl.glGenRenderbuffers(1, depthRenderBufferID, 0);
gl.glBindRenderbuffer(GL2.GL_RENDERBUFFER, depthRenderBufferID[0]);
gl.glRenderbufferStorage(GL2.GL_RENDERBUFFER, GL2.GL_DEPTH_COMPONENT,
floorWidth, floorHeight);
gl.glFramebufferRenderbuffer(GL2.GL_FRAMEBUFFER,
GL2.GL_DEPTH_ATTACHMENT, GL2.GL_RENDERBUFFER,
depthRenderBufferID[0]);
if (gl.glCheckFramebufferStatus(GL2.GL_FRAMEBUFFER) == GL2.GL_FRAMEBUFFER_COMPLETE)
System.out.println("[Viewer] GL_FRAMEBUFFER_COMPLETE!!");
else
System.out.println("..cazzo ^^");
gl.glViewport(0, 0, floorWidth, floorHeight);
gl.glMatrixMode(GL2.GL_PROJECTION);
gl.glLoadIdentity();
gl.glOrthof(0, floorWidth, 0, floorHeight, -10, 10);
gl.glMatrixMode(GL2.GL_MODELVIEW);
gl.glPushMatrix();
gl.glLoadIdentity();
gl.glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
gl.glClear(GL2.GL_COLOR_BUFFER_BIT);
gl.glPointSize(10.0f);
gl.glBegin(GL2.GL_POINTS);
gl.glColor3f(0.0f, 1.0f, 0.0f);
gl.glVertex2d(20.0f, 32.0f); // THIS IS NOT SHOWN
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex2d(20.0f, 10.0f);
gl.glVertex2d(0.9f, 0.9f);
gl.glEnd();
gl.glPopMatrix();
pixels = GLBuffers.newDirectByteBuffer(floorWidth * floorHeight * 4);
gl.glReadPixels(0, 0, floorWidth, floorHeight, GL2.GL_RGBA,
GL2.GL_UNSIGNED_BYTE, pixels);
System.out.println("glIsTexture: " + gl.glIsTexture(textureID[0]));
// bind the back buffer for rendering
gl.glBindFramebuffer(GL2.GL_FRAMEBUFFER, 0);
}

OpenGL Depth Spaz Attack

I've begun learning OpenGL today, and it's just plain fantastic. However I cannot for the life of me make objects draw according to depth, instead of drawing order, so I hope someone can tell me what I'm doing wrong.
Here's the extremely simple code I'm using to create a cube:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//Simple translation
glBegin(GL_QUADS);
glColor3f(0.0f,1.0f,0.0f);
glVertex3f( 1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f,-1.0f);
glVertex3f(-1.0f, 1.0f, 1.0f);
glVertex3f( 1.0f, 1.0f, 1.0f);
glColor3f(1.0f,0.5f,0.0f);
glVertex3f( 1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f, 1.0f);
glVertex3f(-1.0f,-1.0f,-1.0f);
glVertex3f( 1.0f,-1.0f,-1.0f);
glColor3f(1.0f,0.0f,0.0f);
//You get the point, continue with all sides
glEnd(); // End Drawing The Cube
SDL_GL_SwapBuffers();
Here's the set up code:
if (SDL_Init(SDL_INIT_EVERYTHING)<0)
return -1;
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32);
SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2);
SDL_Surface* screen = SDL_SetVideoMode(screen_x,screen_y,32,SDL_HWSURFACE|SDL_GL_DOUBLEBUFFER|SDL_OPENGL);
if (screen == NULL)
return -2;
//glEnable(GL_DEPTH_TEST); //<-If this is uncommented look at figure 1
glDepthFunc(GL_LESS);
glClearColor(0, 0, 0, 0);
glClearDepth(1.0f);
glViewport(0, 0, screen_x, screen_y);
glMatrixMode(GL_PROJECTION); //projection with ortho, model otherwise
glLoadIdentity();
gluPerspective(60.0,1.0,0.0,10.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
Well, when I
glEnable(GL_DEPTH_TEST);
...
And if I don't enable it
So what am I supposed to do? I must be missing ... something? How do I fix my depth issue?
I found the answer!
http://www.opengl.org/resources/faq/technical/depthbuffer.htm
Here's where I found the answer, My near frame was at exactly 0, it needs to be slightly away from 0 in order for the depth buffer's precision to take effect. (If I read that correctly)
All is well.

Blending problems (OpenGL)

A have a question, maybe someone can help me.
I am trying to make a mirror effect using OpenGL. I draw a transparent plane, a "reflected" scene cut by stencil, and an original one.
But I have a completely non-transparent "wall" instead of the mirror. I know it happens because of the first mirror plane rendering (to get a stencil buffer). But I don't know what to do with this:(
Here is the code:
void CMirror::draw(CSceneObject * curscene)
{
glPushMatrix();
glClearStencil(0.0f);
glClear(GL_STENCIL_BUFFER_BIT);
//Draw into the stencil buffer
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
glStencilFunc(GL_ALWAYS, 1, 0);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
glEnable(GL_STENCIL_TEST);
glPushMatrix();
glTranslatef(this->coords[0], this->coords[1], this->coords[2]);
glScalef(this->size, this->size, this->size);
glColor4f(1, 0, 1, 0);
glBegin(GL_QUADS);
glVertex3f(0.0f, this->height / 2.0f, this->width / 2.0f);
glVertex3f(0.0f, this->height / -2.0f, this->width / 2.0f);
glVertex3f(0.0f, this->height / -2.0f, this->width / -2.0f);
glVertex3f(0.0f, this->height / 2.0f, this->width / -2.0f);
glEnd();
glPopMatrix();
glDisable(GL_STENCIL_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
//glClear(GL_COLOR_BUFFER_BIT);
//Draw the scene
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, 1, 255);
glPushMatrix();
glTranslatef( 2*this->coords[0], 2*this->coords[1], 2*this->coords[2]);
glScalef(-1.0f, 1.0f, 1.0f);
((CScene*)curscene)->draw();
glColor4f(0.0f, 0.30f, 0, 0.9);
((CScene*)curscene)->spline->draw();
((CScene*)curscene)->morph->draw();
glPopMatrix();
glDisable(GL_STENCIL_TEST);
//the mirror itself:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glPushMatrix();
glTranslatef(this->coords[0], this->coords[1], this->coords[2]);
glScalef(this->size, this->size, this->size);
glColor4f(0, 0, 0, 0.9);
glBegin(GL_QUADS);
glVertex3f(0.0f, this->height / 2.0f, this->width / 2.0f);
glVertex3f(0.0f, this->height / -2.0f, this->width / 2.0f);
glVertex3f(0.0f, this->height / -2.0f, this->width / -2.0f);
glVertex3f(0.0f, this->height / 2.0f, this->width / -2.0f);
glEnd();
glPopMatrix();
glDisable(GL_BLEND);
glPopMatrix();
}
What happens if you don't do that last draw (i.e. if the problem is still there, remove it as it complicates the example)?
One thing that's clear is that you don't seem to handle anything Z-buffer related.
When you draw your first quad to set the stencil, assuming Z-write is on, you end up setting the Z-values to your mirror Z. Drawing the scene that is supposed to be reflected in the mirror will be Z-rejected.
You need to clear the Z buffer for that region of the screen somehow. Obviously, a full Clear(DEPTH_BIT) can work but it depends on what you've already drawn on your screen.
Likewise, not updating the Z-buffer when updating the stencil can work depending on whether anything has been drawn there before.