I'm trying to figure out how does glOrtho work. I always have (0, 0) point in (w/2, h/2) means it the center of my opengl widget, however I changed this behaviour with glOrtho:
void Widget::initializeGL() {
glClearColor(0.1, 0.1, 0.1, 0);
}
void Widget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glColor3f(1, 0, 0);
glBegin(GL_QUADS);
glVertex2f(0.0, 0.0);
glVertex2f(1.0, 1.0);
glVertex2f(0.5, 0.5);
glVertex2f(0.2, 0.7);
glEnd();
}
void Widget::resizeGL(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, (GLdouble) w, (GLdouble) h, 0.0, 0.0, 0.0);
}
So I always get the same picture
I want the coodinates were starting from left bottom or top left corner, but not from the center.
You don't reset the matrix mode to model-view after setting the projection matrix. So the call to glLoadIdentity() in paintGL() will reset any projection matrix you have set up.
void Widget::resizeGL(int w, int h) {
...
glMatrixMode(GL_MODELVIEW);
}
Keep in mind that this will draw something that is less than a pixel large. So you may want to change your geometry, too.
Btw, if you are just starting, I would recommend not to learn the deprecated OpenGL matrix stack or glVertex2f. It might be easier on first sight, but you will hit a wall in the long run.
I'm trying to figure out how does glOrtho work. I always have (0, 0)
point in (w/2, h/2) means it the center of my opengl widget, however I
changed this behaviour with glOrtho:
glOrtho(0.0, (GLdouble) w, (GLdouble) h, 0.0, 0.0, 0.0);
No, you did not change anything with glOrtho - you are not using glOrtho at all. Your glOrtho call will just generate a GL_INVALID_VALUE error and do nothing else, because it is invalid to cal it with near == far. As a result, you are using an identity matrix as projection, and this means that (0,0) is the center of the screen, (1,1) to top right corner, and so on.
So even if you fix your code to not overwrite the projection matrix with an identy matrix, as #Nico Schertler suggested,it won't change a thing.
I also second Mr. Schertler's recommendation: don't use this old crap. Fixed function pipeline is deprecated for almost a decade, and immediate mode (glBegin/glEnd) is out of fashion since 20 years.
Related
I'm trying to develop an application which will be used for the visualization of 3D objects and its simulations. In this I have to draw 'n' number of objects (may be a triangle, rectangle or some other non-convex polygons) with individual color shades.For this I'm using QGLWidget in Qt5 (OS - Windows 7/8/10).
structure used for populating objects information:
typedef struct {
QList<float> r,g,b;
QList<double> x,y,z;
}objectData;
The number of objects and their corresponding coordinate values will be read from a file.
paintGL function:
void paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(25, GLWidget::width()/(float)GLWidget::height(), 0.1, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0,0,5, 0,0,0, 0,1,0);
glRotatef(140, 0.0, 0.0, 1.0);
glRotatef(95, 0.0, 1.0, 0.0);
glRotatef(50, 1.0, 0.0, 0.0);
glTranslated(-1.0, 0.0, -0.6);
drawObjects(objData, 1000)
}
Drawing of Objects Function:
void drawObjects(objectData objData,int objCnt) {
glPushMatrix();
glBegin(GL_POLYGON);
for(int i = 0; i < objCnt; i++) {
glColor3f(objData.r[i],objData.g[i],objData.b[i] );
glVertex3d(objData.x[i],objData.y[i],objData.z[i]);
}
glEnd();
glFlush();
glPopMatrix();
}
Issue:
Now, when the number of objects to be drawn exceeds a certain maximum value (for example say n = 5000), the application speed gradually decreases. I'm unable to use QThread since it already inherits QGLWidget.
Please suggest how to improve the performance of the application when number of objects count is higher. I don't know where I'm doing mistake.
Screenshot of that sample:
Sample image which contains number of objects in mesh view
You are using the fixed pipeline instead of the programmable one, where you tell to each stage of the rendering process, what should be done, and nothing more. Among other noticeable differences that I encourage you to research (research "modern opengl", which will lead you to doing OpenGL 3.3 and above type of work).
The old fixed pipeline is terribly inefficient, when the computer has to talk to the graphics card for every geometries while rendering. By contrast, the modern programmable pipeline allows you to push the data of the models to render into the VRAM, from where it will be directly accessed during rendering (very fast memory accesses).
You also get rid of the generic ways of "doing stuff", that are mechanically slower than customized ones.
Also, I encourage you to use QOpenGLWidget instead of the former QGLWidget class. As mentioned in http://doc.qt.io/qt-5/qglwidget.html, this class is obsolete.
Modern OpenGL quick start:
http://www.opengl-tutorial.org/
So, you are not doing anything "wrong". You are just not using the current technology. Have fun!
You are using OpenGLs immediate mode which is very slow for large numbers of vertices und should almost never be used. Use the retained mode instead. See this answer for more detail: https://stackoverflow.com/a/6734071
Thank you #dave and #Zedka9. It works fine for me when I started to use the intermediate mode in openGL. I have modified the drawObject function like this
Drawing of Objects Function:
After organizing and copying the vertices and colors to these buffers
GLfloat vertices[1024*1024],colors[1024*1024];
int vertArrayCnt; // number of verticies
void drawObjects(void) {
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glColorPointer(3, GL_FLOAT, 0, colors);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glPushMatrix();
glDrawArrays(GL_TRIANGLES, 0, vertArrayCnt);
glPopMatrix();
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
glDisableClientState(GL_COLOR_ARRAY);
}
Coded in procesing (processing.org):
I want to know when the mouse or another shape collides with a rectangle,
this is very easy but I have one problem: I want it to work when the rectangle is rotated (example: rotate(radians(90))).
Both Kevin and Asad's contributions are useful.
In terms of using the 2D renderer, you need to roll your own functionality for that. For this you should be familiar with a few bits and bobs of linear algebra (vector and matrices mainly and just a few operations anyway).
I am going to assume you're already familiar with 2D transformations (using pushMatrix()/popMatrix() along with translate(),rotate(),scale()) if not, I warmly recommend the 2D Transformations Processing tutorial
I am going to explain some of the concepts only briefly (as it's a big topic on it's own).
If you used translate()/rotate()/scale() before, it's all been matrix operations handled for you behind the scenes. In 2D, a transformation can be stored in a 3x3 matrix like so:
X Y T
1 0 0
0 1 0
0 0 1
The rotation and scale are stored in the 1st and 2nd column (2 values each) while translation is stored in the last column. In theory you could have a 2x3 matrix instead of a 3x3 matrix, but an NxN matrix has a few nice properties. One of the nice things is being simple to multiply with a vector. Position can be stored as vectors and we'd like to transform a vector by multiplying it with a transformation matrix. If you look at a vector as a single column vector, the 3x3 form of the matrix allow multiplication(see matrix multiplication rules here).
In short:
You can store transformations in a matrix
You can apply these transformation to a vector using multiplication
Back to your issue, checking if a point is within a box with transformations applied, you can do this:
convert the test point's coordinate system to the box's transformed coordinate system by:
inverting the box's transformation matrix and
multiplying the point to the inverted transformation matrix.
This may be hard to comprehend at first, but one way to look at is imagining you rotate the whole 'world'(coordinate system) so your rotated box is straight (essentially rotating in the opposite direction, or inverting the transformation) then check if the point is in the box.
Luckily all these matrix operations don't need to be implemented from scratch: PMatrix2D deals with this.
Here is a basic commented sketch explaining all the above:
Box box1,box2;
void setup(){
size(400,400);
box1 = new Box(200,100);
box1.translate(75,100);
box1.rotate(radians(30));
box1.scale(1.1);
box2 = new Box(100,200);
box2.translate(275,150);
box2.rotate(radians(-5));
box2.scale(.95);
}
void draw(){
background(255);
box1.update(mouseX,mouseY);
box2.update(mouseX,mouseY);
box1.draw();
box2.draw();
}
class Box{
PMatrix2D coordinates = new PMatrix2D();//box coordinate system
PMatrix2D reverseCoordinates = new PMatrix2D();//inverted coordinate system
PVector reversedTestPoint = new PVector();//allocate reversed point as vector
PVector testPoint = new PVector();//allocate regular point as vector
float w,h;//box width and height
boolean isHovered;
Box(float w,float h){
this.w = w;
this.h = h;
}
//whenever we update the regular coordinate system, we update the reversed one too
void updateReverseCoordinates(){
reverseCoordinates = coordinates.get();//clone the original coordinate system
reverseCoordinates.invert();//simply invert it
}
void translate(float x,float y){
coordinates.translate(x,y);
updateReverseCoordinates();
}
void rotate(float angle){
coordinates.rotate(angle);
updateReverseCoordinates();
}
void scale(float s){
coordinates.scale(s);
updateReverseCoordinates();
}
boolean isOver(float x,float y){
reversedTestPoint.set(0,0);//reset the reverse test point
testPoint.set(x,y);//set the x,y coordinates we want to test
//transform the passed x,y coordinates to the reversed coordinates using matrix multiplication
reverseCoordinates.mult(testPoint,reversedTestPoint);
//simply test the bounding box
return ((reversedTestPoint.x >= 0 && reversedTestPoint.x <= w) &&
(reversedTestPoint.y >= 0 && reversedTestPoint.y <= h));
}
void update(float x,float y){
isHovered = isOver(x,y);
}
void draw(){
if(isHovered) fill(127);
else fill(255);
pushMatrix();
applyMatrix(coordinates);
rect(0,0,w,h);
popMatrix();
}
}
You're looking for the modelX() and modelY() functions. Just pass in mouseX and mouseY (z is 0) to find the position of the mouse in rotated space. Similarly, pass in the position of your rectangles to find their rotated points.
Here's the example from the reference:
void setup() {
size(500, 500, P3D);
noFill();
}
void draw() {
background(0);
pushMatrix();
// start at the middle of the screen
translate(width/2, height/2, -200);
// some random rotation to make things interesting
rotateY(1.0); //yrot);
rotateZ(2.0); //zrot);
// rotate in X a little more each frame
rotateX(frameCount / 100.0);
// offset from center
translate(0, 150, 0);
// draw a white box outline at (0, 0, 0)
stroke(255);
box(50);
// the box was drawn at (0, 0, 0), store that location
float x = modelX(0, 0, 0);
float y = modelY(0, 0, 0);
float z = modelZ(0, 0, 0);
// clear out all the transformations
popMatrix();
// draw another box at the same (x, y, z) coordinate as the other
pushMatrix();
translate(x, y, z);
stroke(255, 0, 0);
box(50);
popMatrix();
}
This question already has answers here:
Opengl: 2d HUD over 3D
(3 answers)
Closed 6 years ago.
I have a subclass "GLWidget" of QGLWidget where I render a 3D scene. I can do rotations and zoom on it.
I call with a QTimer the following function :
void GLWidget::processCurrent()
{
draw();
printStats();
glFlush();
swapBuffers();
}
and the main OpenGL render function "draw()" is :
void GLWidget::draw()
{
if (isDisplayFirst)
{
isDisplayFirst = false;
glViewport(0, 0, w_width, w_height);
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrixi
gluPerspective(45.0f, (float)w_width / w_height, g_nearPlane, g_farPlane);
gluLookAt (0.0, 0.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
glScalef(0.03f, 0.03f, 0.03f);
}
rotateScene();
glClearColor(0.0 ,0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_POINT_SPRITE);
glTexEnvi(GL_POINT_SPRITE, GL_COORD_REPLACE, GL_TRUE);
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE_NV);
glEnable(GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE);
GLuint vbo_disk = 0;
glBindBuffer(GL_ARRAY_BUFFER, vbo_disk);
glVertexPointer(4, GL_DOUBLE, 4*sizeof(double), Galaxy->pos);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4f(1.0f, 1.0f, 1.0f, 0.2f);
glDrawArrays(GL_POINTS, 0, Galaxy->getNumParticles_disk());
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_BLEND);
glDisable(GL_POINT_SPRITE);
}
I have already rendered 2D text (statistics) on this GLWidget with "printStats()" function. I would like now to draw a "2D scale line" on this 3D scene.
I succeed in draw this line by doing into printStats():
glDisable(GL_TEXTURE_2D);
glColor3f(1.0f, 1.0f, 1.0f);
glLineWidth(3.0f);
glBegin(GL_LINES);
glVertex2d(5, 40);
glVertex2d(20, 40);
glEnd();
glEnable(GL_TEXTURE_2D);
but my problem is that when I do rotations or zoom, this line moves with the 3D scene.
What is the way to lock this 2D line while being able to do operations on the 3D object ?
I want to avoid to use "overpainting" with overriding paintEvent.
I also try to use glPush/Pop Matrix but there are conflicts between 2D and 3D.
Could you give me some advice to get it ?
You are trying to implement HUD functionality, in principle what you need to to draw your 3D scene normaly, then backup all the OpenGL states that you want to reuse, and set up a new projection matrix with gluOrtho2D or glOrtho. Additionally you want to turn off the depth check.
After the call to the ortho function you will most likely draw in screen scale, so you will have to calculate the size of your line accordingly. Once you are done with the hud, you can pop the changes off the stack so you can draw again.
There are a couple of questions on stackoverflow that deal with drawing an OpenGl HUD
OpenGl 2D HUD over 3D
OpenGl 2d HUD in 3D Application
and a pretty decent discussion on the gamedev forum
http://www.gamedev.net/topic/388298-opengl-hud/
I have a camera in OpenGL.I had no problem with it until adding FPS controller.The problem is that the basic FPS behavior is ok. The camera moves forward,backward,left and right+ rotates towards the direction supplied by mouse input.The problems begin when the camera moves to the sides or the back of the target position.In such a case camera local forward,backward,left,right directions aren't updated based on its current forward look but remain the same as if it was right in front of the target.Example:
If the target object position is at (0,0,0) and camera position is at (-50,0,0) (to the left of the target) and camera is looking at the target,then to move it back and forth I have to use the keys for left and right movement while backward/forward keys move the camera sideways.
Here is the code I use to calculate camera position, rotation and LookAt matrix:
void LookAtTarget(const vec3 &eye,const vec3 ¢er,const vec3 &up)
{
this->_eye = eye;
this->_center = center;
this->_up = up;
this->_direction =normalize((center - eye));
_viewMatrix=lookAt( eye, center , up);
_transform.SetModel(_viewMatrix );
UpdateViewFrustum();
}
void SetPosition(const vec3 &position){
this->_eye=position;
this->_center=position + _direction;
LookAtTarget(_eye,_center,_up);
}
void SetRotation(float rz , float ry ,float rx){
_rotationMatrix=mat4(1);
vec3 direction(0.0f, 0.0f, -1.0f);
vec3 up(0.0f, 1.0f, 0.0f);
_rotationMatrix=eulerAngleYXZ(ry,rx,rz);
vec4 rotatedDir= _rotationMatrix * vec4(direction,1) ;
this->_center = this->_eye + vec3(rotatedDir);
this->_up =vec3( _rotationMatrix * vec4(up,1));
LookAtTarget(_eye, _center, up);
}
Then in the render loop I set camera's transformations:
while(true)
{
display();
fps->print(GetElapsedTime());
if(glfwGetKey(GLFW_KEY_ESC) || !glfwGetWindowParam(GLFW_OPENED)){
break;
}
calculateCameraMovement();
moveCamera();
view->GetScene()->GetCurrentCam()->SetRotation(0,-camYRot,-camXRot);
view->GetScene()->GetCurrentCam()->SetPosition(camXPos,camYPos,camZPos);
}
lookAt() method comes from GLM math lib.
I am pretty sure I have to multiply some of the vectors (eye ,center etc) with rotation matrix but I am not sure which ones.I tried to multiply _viewMatrix by the _rotationMatrix but it creates a mess.The code for FPS camera position and rotation calculation is taken from here.But for the actual rendering I use programmable pipeline.
Update:
I solved the issue by adding a separate method which doesn't calculate camera matrix using lookAt but rather using the usual and basic approach:
void FpsMove(GLfloat x, GLfloat y , GLfloat z,float pitch,float yaw){
_viewMatrix =rotate(mat4(1.0f), pitch, vec3(1, 0, 0));
_viewMatrix=rotate(_viewMatrix, yaw, vec3(0, 1, 0));
_viewMatrix= translate(_viewMatrix, vec3(-x, -y, -z));
_transform.SetModel( _viewMatrix );
}
It solved the problem but I still want to know how to make it work with lookAt() methods I presented here.
You need to change the forward direction of the camera, which is presumably fixed to (0,0,-1). You can do this by rotating the directions about the y axis by camYRot (as computed in the lookat function) so that forwards is in the same direction that the camera is pointing (in the plane made by the z and x axes).
I am trying to create a finely triangulated mesh. In the draw function :
// Draws triangular strip as only lines
glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
// Create Cloth Mesh
glBegin(GL_TRIANGLE_STRIP);
glNormal3f(0,0,1);
for(float i = 0.0 ; i < 2.0; i+=.05)
{
for(float j = -1.0 ; j < 1.0 ; j+=.05)
{
glVertex3f(j,1-i+.05,0);
glVertex3f(j,1-i,0);
}
}
glEnd();
I get the following output :
which I what I expected.
But if I rotate the scene, I see this on the back side:
(If its not clear, its feebly lit mesh, but the triangles are not the same as showing up on front.)
Q1. Shouldn't the back side be not visible at all ? I have these flag enabled :
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
Q2. Even if the back side shows up, why does it shows these irregular, long triangles and not the same ones as on front ?
P.S. This is the resize function :
void MyGLWidget::resizeGL(int width, int height)
{
int side = qMin(width, height);
glViewport((width - side) / 2, (height - side) / 2, side, side);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2, +2, -2, +2, 1.0, 15.0);
glMatrixMode(GL_MODELVIEW);
}
P.P.S: Yes, I understand this is not modern OpenGL.
For me, this looks like the triangles, that are produced by the triangle-strip to "jump back" to the left side. This happens whenever you start a new row. Basically, they consist of the last-vertices of the previous row and the first vertices of the next row. Backface culling seems to work, but the large triangles are visible from the back because their winding order is exactly opposite to the one of the small triangles.
If you don't want to have them, you either have to reset the triangle-strip at the end of each row, or use another structure (GL_TRIANGLES).