I have a 3D scene with an object and I would like to save a view of that object that is different from the one of the current screen I look at.
So I thought I'd just have to do something like this (pseudo code):
PushMatrix()
LoadIdentity()
TranslateAndRotate()
gluperspective()
setViewport()
DrawScene()
saveScreenshot()
PopMatrix()
But I only get a picture of the current view of my camera, not the one I specified.
Did I forget something?
EDIT:
Because of the answer below, I tried the following code:
void ScenePhotograph(GLubyte* Target, float *Translation, float RotationAroundY)
{
glMatrixMode(GL_PROJECTION);
gluPerspective(54.0f, (GLfloat)openGLControl1->Width / (GLfloat)openGLControl1->Height, 1.0f, 3000.0f);
glViewport(0,0,openGLControl1->Width, openGLControl1->Height);
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(Translation[0],Translation[1],Translation[2]);
glRotatef(RotationAroundY, 0,1,0);
openGLControl1_OnDrawGL(NULL,System::EventArgs::Empty);
openGLControl1->Refresh();
glReadPixels(0, 0, openGLControl1->Width, openGLControl1->Height, GL_RGB, GL_UNSIGNED_BYTE, Target);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
cam->SetView();
openGLControl1_OnDrawGL(NULL,System::EventArgs::Empty);
openGLControl1->Refresh();
glutSwapBuffers();
}
That is giving me an access violation at glutSwapBuffers();
Any Ideas?
First, make sure you are not mixing diferent matrix in your code. To get a screenshot, you will need to position your camera exactly as you normally do to view it on your sccreen, but, before you swap the buffers, you read the pixels from the current framebuffer and store it as an image.
So, what you need is something like this:
glMatrixMode(GL_PROJECTION);
gluPerspective();
glMatrixMode(GL_MODELVIEW);
glClear(); // clear buffers here
loadIdendity();
setCameraPosition();
TranslateRotate();
DrawScene();
screenShot();
// do again to set your camera to correct position
glClear(); // clear buffers here
loadIdendity();
setCameraPosition();
TranslateRotate();
DrawScene();
swapBuffers();
as you can see, screenShot take care of reading the pixels from your current framebuffer and save it as an image. So do everything again to position your camera to the correct place
Related
I'm using qWidget which inherits QGLWidget and below the widget I have 2 buttons.
button1: +
button2: -
this is my code:
void GLWidget::paintGL() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,_w,0,_h,-1,1);
glViewport(_camera_pos_x,0,_w,_h);
glBegin(GL_LINES);
glVertex2i(50,50);
glVertex2i(200,200);
glEnd();
update();
}
I want each time I'm pressing the + button, the screen will move 10 pixels to the right which means the line should move to the left by 10 pixels.
This is the code when im pressing the button:
void right() {_camera_pos_x += 10;}
_camera_pos_X is just a member int which is initialized to 0.
When I'm pressing the button another line is rendered 10 pixels to the right and I see 2 lines
What's wrong with my code?
By the way, I think im using old code of OpenGL, is there a better way to render a line?
First of all note, that drawing with glBegin/glEnd sequences is deprecated since more than 10 years.
Read about Fixed Function Pipeline and see Vertex Specification for a state of the art way of rendering.
glViewport specifies the transformation from normalized device coordinates to window coordinates. If you want to change the position of the line, then you have to draw the line at a different position, but that doesn't change the size of the viewport. Keep your viewport as large as the window:
glViewport(0, 0, _w, _h);
The default frame buffer is never cleared, so the rendering is always drawn on the rendering of the previous frames. Because of that, you can "see 2 lines". Use glClear to clear the framebuffer at the begine of the rendering:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Change the model view matrix to set the positon of the line:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,_w,0,_h,-1,1);
glViewport(0, 0, _w, _h);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(_camera_pos_x, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBegin(GL_LINES);
glVertex2i(50,50);
glVertex2i(200,200);
glEnd();
You must clear the old contents of the framebuffer, before drawing the new image. Put a glClear(GL_COLOR_BUFFER_BIT) at the beginning of paintGL().
So I'm trying to render a basic overlay onto my 3D scene, and currently I can either have the 3D scene or the 2D overlay, I cant work out how to get both
In my main method, where render is called, I moved specific render functions to manager classes, so in the main render I call :
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_COLOR_MATERIAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-aspect, aspect, -1, 1, -10, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
material.setColour(new Vector3f(1,1,1));
sLight.getPointLight().setPosition(camera.getPosition());
sLight.setDirection(camera.getForward());
DayCycle.getInstance().update(Time.getDelta());
shader.updateUniforms(transform.getTransformation(), transform.getProjectedTransformation(), material);
//material is a wrapper class for textures and specular value etc
//transform is a matrix wrapper for getting projected transformations, taking the camera position when its created
WorldManager.renderAll(true); //true denotes yes to wireframe mode
InterfaceManager.renderAll();
glfwSwapBuffers(window);
glfwPollEvents();
If i comment out WorldManager.renderAll(), I get the little 2d square in the right part of the screen, If i dont comment it, I get the world render but no little square
WorldManager.renderAll()
public static void renderAll(boolean wireframeMode)
{
RendererUtils.setWireframeMode(wireframeMode);
for (String s : chunks.keySet())
{
Chunk actingChunk = chunks.get(s);
Transform transform = new Transform();
Shader shader = PhongShader.getInstance();
transform.setTranslation(new Vector3f(actingChunk.getLocation().getX() * (Chunk.ChunkSize),0.0f, actingChunk.getLocation().getY() * (Chunk.ChunkSize)));
transform.setScale(1.0f, 50f, 1.0f);
shader.updateUniforms(transform.getTransformation(), transform.getProjectedTransformation(), actingChunk.getMaterial());
shader.bind();
actingChunk.getMesh().draw();
//transform.setRotation(new Vector3f(0,0,0));
}
}
InterfaceManager.renderAll()
public static void renderAll()
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, width, 0, height, -10, 10);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
RendererUtils.setWireframeMode(false);
for (Interface i : interfaces)
{
Transform transform = new Transform();
transform.setTranslation(new Vector3f(0,0,0));
InterfaceShader.getInstance().updateUniforms(transform.getProjectedTransformation());
InterfaceShader.getInstance().bind();
i.getMesh().draw();
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
}
When I have WorldManager.renderAll() uncommented, i get a nice sea of triangles (as its meant to look) but no 2D square
With it commented, I get a nice little square where its meant to be and nothing else
Shaders are here : https://pastebin.com/xWaWhQHy because I felt this post was getting too long to have them inlined
What's my problem? I cant figure out where it is
Edit : If i've missed any pertinent code, tell me and i'll upload it to a pastebin
Edit 2 : updated my code here to reflect that i'd removed a shader in interfaceManager to actually get a square to draw at all : https://pastebin.com/pHHDsCvF for the shader code
Edit 3 : Ive determined it's something to do with my interface shaders, If i use PhongShader instead of InterfaceShader then it works exactly how I wanted it to
I can suggest you to modify the code this way:
WorldManager.renderAll(true); //true denotes yes to wireframe mode
glClear(GL_DEPTH_BUFFER_BIT);
InterfaceManager.renderAll();
This way you will clear depth buffer before rendering 2d interface.
The problem was that I was still applying transformations to the vertices after passing them to the shader.
By editing out the transformation (and later scrapping the entire vertex shader) in the InterfaceShader instance, the little squares were appearing in the right place
I'm working on a little example, where I have loaded an object from a wavefront file - and am trying to get my picking right, I've gone over this and a few tutorials about 10 times... but must be missing something. Was wondering if anyone could provide an extra set of eyes.
I've used a saved list to draw the object, which appears fine on the screen... At the moment, when gl_select(x, y) runs, I get a hit no matter what, and if I enable the translate/rotate code (which is currently commented out) - I get no hits what-so-ever.
Relevant code blocks:
// gl_select, is called when the mouse is clicked, with its x and y coords
void gl_select(int x, int y)
{
GLuint buff[256];
GLint hits;
GLint view[4];
//Buffer to store selection data
glSelectBuffer(256, buff);
//Viewport information
glGetIntegerv(GL_VIEWPORT, view);
//Switch to select mode
glRenderMode(GL_SELECT);
//Clear the name stack!
glInitNames();
//Fill the stack with one element
glPushName(0);
//Restric viewing volume
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
//Restrict draw area
gluPickMatrix(x, y, 1.0, 1.0, view);
gluPerspective(60, 1, 0.0001, 1000.0);
//Draw the objects onto the screen
glMatrixMode(GL_MODELVIEW);
//Draw only the names in the stack
glutSwapBuffers();
DrawSavedObject();
//Back into projection mode to push the matrix
glMatrixMode(GL_PROJECTION);
glPopMatrix();
hits = glRenderMode(GL_RENDER);
cout << hits;
//Back to modelview mode
glMatrixMode(GL_MODELVIEW);
}
And the draw functions:
void DrawSavedObject()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(1.0,0.0,0.0);
//translate and rotate
//glRotated(rotation,0.0,0.0,1.0);
//glTranslated(7.0, 7.0, 0.0);
//Draw the saved object
glLoadName(7);
glCallList(list_object);
glutSwapBuffers();
}
And where the list is saved:
void SaveDisplayList(){
glNewList(list_object, GL_COMPILE);
glVertexPointer(3, GL_DOUBLE, 3*sizeof(GLdouble), vertices);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_TRIANGLES, verticesSize ,GL_UNSIGNED_INT, triangles);
glDisableClientState(GL_VERTEX_ARRAY);
glEndList();
}
Sorry again for the chunkiness of the code blocks.
A few things to consider here:
OpenGL selection mode is deprecated and never was HW accelerated, except on a few SGI boxes and 3DLabs GPUs.
DisplayLists don't mix with Vertex Arrays.
Why do you call glutSwapBuffers right before drawing your list of saved objects? Makes absolutely no sense at all.
I'm not sure if it's relevant but you're not supposed to store things like glVertexPointer in display lists. From the spec http://www.opengl.org/sdk/docs/man/xhtml/glNewList.xml:
Certain commands are not compiled into the display list but are
executed immediately, regardless of the display-list mode. These
commands are glAreTexturesResident, glColorPointer, glDeleteLists,
glDeleteTextures, glDisableClientState, glEdgeFlagPointer,
glEnableClientState, glFeedbackBuffer, glFinish, glFlush, glGenLists,
glGenTextures, glIndexPointer, glInterleavedArrays, glIsEnabled,
glIsList, glIsTexture, glNormalPointer, glPopClientAttrib,
glPixelStore, glPushClientAttrib, glReadPixels, glRenderMode,
glSelectBuffer, glTexCoordPointer, glVertexPointer, and all of the
glGet commands.
This could be what's causing your problem.
I know how to speed up rendering in 3d by simply rendering the nearest planes first.
But how do i get advantage of this type of method in 2d mode? I cant use depth testing because they are all in the same z-level.
So i was thinking if it could be speed up when i dont need to render the invisible parts of the layers "below". Is this possible?
Note that i am rendering in 3d mode, there may be 3d objects and 2d objects at the same time. So i cant switch to 2d render only, i always use 3d coordinates for everything. And i may rotate the camera as i wish, so camera-specific tricks arent acceptable.
Edit: i tried the method Ville suggested:
( http://img815.imageshack.us/img815/7857/zfighting.png )
but as you see, it will result in z-fighting.
The code i used for rendering that is here:
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_ALPHA_TEST);
glDisable(GL_POLYGON_OFFSET_FILL);
glColor4f(1,0,0,1);
DrawQuad(0, 0, 10, 10);
glColor4f(0,0,1,1);
DrawQuad(5, 5, 15, 15);
glDepthFunc(GL_LEQUAL);
It sounds like you are rendering all your "2D" objects on the same plane. You could render your 2D parts into an off-screen framebuffer with an orthographic projection and give them different Z values as datenwolf suggested. Then render the framebuffer texture into your main 3D scene.
What do you understand by 2D mode? Do you mean orthographic projection? Then I have good news: Depth testing works there perfectly as well. gluOrtho2D is basically the same like glOrtho(..., -1, 1); i.e. you have the Z range -1 ... 1 to spend.
EDIT due to comment:
It is perfectly possible to combine rendering several projections in one single frame:
void render_perspective_scene(void);
void render_ortho_scene(void);
void render_HUD();
void display()
{
float const aspect = (float)win_width/(float)win_height;
glViewport(0,0,win_width,win_height);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-aspect*near/lens, aspect*near/lens, -near/lens, near/lens, near, far);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
render_perspective_scene();
// just clear the depth buffer, so that everything that's
// drawn next will overlay the previously rendered scene.
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-aspect*scale, aspect*scale, -scale, scale, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
render_ortho_scene();
// Same for the HUD, only that we render
// that one in pixel coordinates.
glClear(GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, win_width, 0, win_height, 0, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
render_HUD();
}
Of course if you've fallen for those bad tutorials that place the projection matrix setup in the reshape handler you're of course mind blocked, to see that obvious solution.
Hi I got 4 viewports and one large that I can switch between now I got an object namely the camera and the cameras target position that I show with rendering a sphere at those locations. I want to show the cameras position in 3 of my viewports but not in the last which is the camera display but at the moment I got an all or nothing scenario.
void display(int what)
{
if(what==5){
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camControll();}
if(what==1){
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(75,15,-5,0,5,-5,0,1,0);}
if(what==2){
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,110,0,0,0,0,1,0,0);}
if(what==3){
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, float(320) / float(240), 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
camControll();}
if(what==4){
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(185,75,25,0,28,0,0,1,0);}
//glMatrixMode(GL_MODELVIEW);
//glLoadIdentity();
////gluLookAt(cos(shared.time) * shared.distance, 10, sin(shared.time) * shared.distance, 0, 0, 0, 0, 1, 0);
////ca.orbitYaw(0.05);
//ca.lookAt();
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
drawScene(); // scene that all views should render
drawCamera(); / camera position that only certain views should render
glutSwapBuffers();
}
I'm thinking that perhaps I could do one sweep for first the 3 viewports and then call glutSwapBuffers() and then do the other viewport without the camera position but some stuttering I previously had was traced to glutSwapBuffers() being called for each viewport so I guess there has to be another way only that I cant figure it out.
You have to render everything before swapping buffers.
As you do it - it is not going to work. Actually, it will work, but not you want.
EDIT
To render to a texture take a look into one of the links here.
After changing a view, render the image for the specific view to a texture. Then for the final image, set the final view and render all 3 textures. Only when the final image is rendered, swap buffers.
On the 2nd thought, it would be much better if you could set the vertices of all objects to render and render whole image in one pass.