I'm using c++ to translate a 3d model entered using command line arguments into a 2d picture in assimp. However I'm not sure of the best way to go about it. I have the basic hard coding for to create a set object but I need to redo it using vectors and loops. What's the best way to go about it?
void createSimpleQuad(Mesh &m) {
// Clear out vertices and elements
m.vertices.clear();
m.indices.clear();
// Create four corners
Vertex upperLeft, upperRight;
Vertex lowerLeft, lowerRight;
Vertex upperMiddle;
// Set positions of vertices
// Note: glm::vec3(x, y, z)
upperLeft.position = glm::vec3(-0.5, 0.5, 0.0);
upperRight.position = glm::vec3(0.5, 0.5, 0.0);
lowerLeft.position = glm::vec3(-0.5, -0.5, 0.0);
lowerRight.position = glm::vec3(0.5, -0.5, 0.0);
upperMiddle.position = glm::vec3(-0.9, 0.5, 0.0);
// Set vertex colors (red, green, blue, white)
// Note: glm::vec4(red, green, blue, alpha)
upperLeft.color = glm::vec4(1.0, 0.0, 0.0, 1.0);
upperRight.color = glm::vec4(0.0, 1.0, 0.0, 1.0);
lowerLeft.color = glm::vec4(0.0, 0.0, 1.0, 1.0);
lowerRight.color = glm::vec4(1.0, 1.0, 1.0, 1.0);
upperMiddle.color = glm::vec4(0.5, 0.15, 0.979797979, 1.0);
// Add to mesh's list of vertices
m.vertices.push_back(upperLeft);
m.vertices.push_back(upperRight);
m.vertices.push_back(lowerLeft);
m.vertices.push_back(lowerRight);
m.vertices.push_back(upperMiddle);
// Add indices for two triangles
m.indices.push_back(0);
m.indices.push_back(3);
m.indices.push_back(1);
m.indices.push_back(0);
m.indices.push_back(2);
m.indices.push_back(3);
m.indices.push_back(0);
m.indices.push_back(2);
m.indices.push_back(4);
}
If you want to generate a 2D-picture out of a 3D-Model you need to:
Import the model
Render it via a common render-lib into a texture or manually by using our viewer and take a snapshot
At this moment there is no post-process to generate a 2D-View automatically in Assimp.
But when you want to do this with your own render-code this is not so hard to do. After importing your model you have to:
Get the bounding box for your imported asset, just check the opengl-samples in the assimp-repo for some tips
Calculate the diameter for this bounding box.
Create a camera, for OpenGL you can use glm for calculating the View-Matrix
Place the asset at (0|0|0) world coordinate system
Move your camera by the diameter at let it view onto (0|0|0)
Render the view into a 2D-Texture or just take a screenshot
Related
I render 3 images (left-view, center-view, right-view) with 90° horizontal foV and map them on 3 grids that create an overall image (basically like left, front and right views of a cubemap texture). Therefore the 3 unique images have to fit together somehow.
Everything works fine if i define the projection matrix for each image like this:
gluPerspective(90, 1, 0.1, 500)
However, since i'm trying to create an image with 210° (horizontal) and 60° (vertical) field of View, i would like to define it like this:
gluPerspective(60, 1.5, 0.1, 500)
But using this, the 3 images don't fit together in terms of their image content, foV, frustum or whatever.
So my question is: Do i have to use an aspect ratio of 1 if i want the images to fit together. And if i have to, why?
Some additional information:
i render the images in an fbo with a resolution that has the same aspect ratio like my hor./ver. foV
viewport is defined like this: glViewport (0, 0, width, height);
The modelview definition for the 3 views:
left-view: gluLookAt(0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
center-view: gluLookAt(0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 0.0, 1.0);
right-view: gluLookAt(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);
This was a sufficient explanation for me:
http://ledin.cs.sonoma.edu/CS375_OpenGL_Slides/Perspective_gluFrustum.pdf
I am creating the solar system and I keep running into problems with the lighting. The first problem is that the moon casts no shadows on the earth and the earth casts no shadows on the moon.
The other problem is that the light that is shining on the the earth and the moon are not coming from my sun, but from the center point of the orbit. I added the red lines in the picture below to show what I mean.
the picture below should illustrate what my two problems are.
Here is the code that is dealing with the lights and the planets.
glDisable(GL_LIGHTING);
drawCircle(800, 720, 1, 50);
//SUN
//Picture location, major radius, minor radius, major orbit, minor orbit, angle
Planet Sun ("/home/rodrtu/Desktop/SolarSystem/images/Sun.png",
100, 99, 200.0, 0.0, 0.0);
double sunOrbS = 0;
double sunRotS = rotatSpeed/10;
cout << sunRotS << " Sun Rotation" << endl;
//orbit speed, rotation speed, moon reference coordinates (Parent planet's major and minor Axis)
Sun.displayPlanet(sunOrbS, sunRotS, 0.0, 0.0);
//Orbit path
//EARTH
GLfloat light_diffuse[] = { 1.5, 1.5, 1.5, 1.5 };
GLfloat pos[] = { 0.0, 0.0, 0.0, 200.0 };
glEnable(GL_LIGHTING);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, pos);
Planet Earth ("/home/rodrtu/Desktop/SolarSystem/images/EarthTopography.png",
50, 49, 500.0, 450.0, 23.5);
double eaOrbS = orbitSpeed;
double eaRotS = rotatSpeed*3;
Earth.displayPlanet(eaOrbS, eaRotS, 0.0, 0.0);
//EARTH'S MOON
Planet Moon ("/home/rodrtu/Desktop/SolarSystem/images/moonTest.png",
25, 23, 100.0, 100.0, 15);
double moOrbS = rotatSpeed*4;
double moRotS = eaOrbS;
Moon.displayPlanet(moOrbS, moRotS, Earth.getMajorAxis(), Earth.getMinorAxis());
orbitSpeed+=.9;
if (orbitSpeed > 359.0)
orbitSpeed = 0.0;
rotatSpeed+=2.0;
if (rotatSpeed > 7190.0)
rotatSpeed = 0.0;
This next functions are used to determine the orbit coordinate and location of each planet
void Planet::setOrbit(double orbitSpeed, double rotationSpeed,
double moonOrbitX, double moonOrbitY)
{
majorAxis = orbitSemiMajor * cos(orbitSpeed / 180.0 * Math::Constants<double>::pi);
minorAxis = orbitSemiMinor * sin(orbitSpeed / 180.0 * Math::Constants<double>::pi);
glTranslate(majorAxis+moonOrbitX, minorAxis+moonOrbitY, 0.0);
glRotatef(orbitAngle, 0.0, 1.0, 1.0);
glRotatef(rotationSpeed, 0.0, 0.0, 1.0);
}
void Planet::displayPlanet(double orbitSpeed,double rotationSpeed,
double moonOrbitX, double moonOrbitY)
{
GLuint surf;
Images::RGBImage surfaceImage;
surfaceImage=Images::readImageFile(texture);
glEnable(GL_TEXTURE_2D);
glGenTextures(0, &surf);
glBindTexture(GL_TEXTURE_2D, surf);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
surfaceImage.glTexImage2D(GL_TEXTURE_2D,0,GL_RGB);
glPushMatrix();
setOrbit(orbitSpeed,rotationSpeed, moonOrbitX, moonOrbitY);
drawSolidPlanet(equatRadius, polarRadius, 1, 40, 40);
glPopMatrix();
}
What am I doing wrong? I read up on the w component of GL_POSITION and I changed my position to be 200 (where the sun is centered), but the light source is still coming from the center of the orbit.
To make a proper reply for the light position issue..
[X, Y, Z, W] is called homogenous coordinates
A coordinate [X, Y, Z, W] in homogenous space is will be [X/W, Y/W, Z/W] in 3D space.
Now, consider the following W values :
W=1.0 : [1.0, 1.0, 1.0, 1.0] is [1.0, 1.0, 1.0] in 3D place.
W=0.1 : [1.0, 1.0, 1.0, 0.1] is [10.0, 10.0, 10.0] in 3D place.
W=0.001 : [1.0, 1.0, 1.0, 0.001] is [1000.0, 1000.0, 1000.0] in 3D place.
When we keep moving towards W=0 the [X/W, Y/W, Z/W] values approaches a point at infinity. It's actually no longer a point, but a direction from [0,0,0] to [X,Y,Z].
So when defining the light position we need to make sure to get this right.
W=0 defines a directional light, so x,y,z is a directional vector
W=1 defined a positional light, so x,y,z is a position in 3D space
You'll get to play around with this a lot once you dig deeper into matrix math. If you try to transform a direction (W=0) with a translation matrix for example, it will not have any effect. This is very relevant here as well since the light position will be affected by the modelview matrix.
Some easy to understand information here for further reading :
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/
If OpenGL doesn't have a "cast shadow" function, how could I acomplish this then?
What you must understand is, that OpenGL has no concept of a "scene". All OpenGL does is drawing points, lines or triangles to the screen, one at a time. After it's drawn, it has no influence on the following drawing operations.
So to do something fancy like shadows, you must get, well, artistic. By that I mean, like an artist who paints a plastic picture which has depth with "just" a brush and a palette of colours, you must use OpenGL in a artistic way to recreate with it the effects you desire. Drawing a shadow can be done in various ways. But the most popular one is known by the term Shadow Mapping.
Shadow Mapping is a two step process. In the first step the scene is rendered into a "grayscale" picture "seen" from the points of view of the light, where the distance from the light is drawn as the "gray" value. This is called a Shadow Depth Map.
In the second step the scene is drawn as usual, where the lights' shadow depth map(s) are projected into the scene, as if the lights were a slide projector (where everything receives that image, as OpenGL doesn't shadow). In a shader the depth value in the shadow depth map is compared with the actual distance to the light source for each processed fragments; if the distance to the light is farther than the corresponding pixel in the shadow map this means that while rendering the shadow map something got in front of the currently processed geometry fragment, which hence lies in the shadow, so it's drawn in a shadow color (usually the ambient illumination color); you might want to combine this with an Ambient Occlusion effect to simulate soft, self shadowing ambient illumination.
I'm having problems in OpenGL getting my object (a planet) to rotate relative to the current camera rotation. It seems to work at first, but then after rotating a bit, the rotations are no longer correct/relative to the camera.
I'm calculating a delta (difference) in mouseX and mouseY movements on the screen. The rotation is stored in a Vector3D called 'planetRotation'.
Here is my code to calculate the rotation relative to the planetRotation:
Vector3D rotateAmount;
rotateAmount.x = deltaY;
rotateAmount.y = deltaX;
rotateAmount.z = 0.0;
glPushMatrix();
glLoadIdentity();
glRotatef(-planetRotation.z, 0.0, 0.0, 1.0);
glRotatef(-planetRotation.y, 0.0, 1.0, 0.0);
glRotatef(-planetRotation.x, 1.0, 0.0, 0.0);
GLfloat rotMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, rotMatrix);
glPopMatrix();
Vector3D transformedRot = vectorMultiplyWithMatrix(rotateAmount, rotMatrix);
planetRotation = vectorAdd(planetRotation, transformedRot);
In theory - what this does is, sets up a rotation in the 'rotateAmount' variable. It then gets this into model space, by multiplying this vector with the inverse model transform matrix (rotMatrix).
This transformed rotation is then added to the current rotation.
To render this is the transform being setup:
glPushMatrix();
glRotatef(planetRotation.x, 1.0, 0.0, 0.0);
glRotatef(planetRotation.y, 0.0, 1.0, 0.0);
glRotatef(planetRotation.z, 0.0, 0.0, 1.0);
//render stuff here
glPopMatrix();
The camera sort of wobbles around, the rotation I'm trying to perform, doesn't seem relative to the current transform.
What am I doing wrong?
GAH! Don't do that:
glPushMatrix();
glLoadIdentity();
glRotatef(-planetRotation.z, 0.0, 0.0, 1.0);
glRotatef(-planetRotation.y, 0.0, 1.0, 0.0);
glRotatef(-planetRotation.x, 1.0, 0.0, 0.0);
GLfloat rotMatrix[16];
glGetFloatv(GL_MODELVIEW_MATRIX, rotMatrix);
glPopMatrix();
OpenGL is not a math library. There are proper linear algebra libraries for that kind of job.
As for your problems. A vector is not fit to store a rotation. You need at least a Vector (axis of rotation) and the angle itself, or better yet a Quaternion.
Also rotations don't add. They're no commutative, however addition is a commutative operation. Rotations in fact multiply.
How to fix your code: Rewrite it from scratch using the proper mathematical methods. For this please read up the topics of "Rotation matrices" and "Quaternions" (Wikipedia has them).
Suppose I have a point at (250,125,-20).
After the following transformation,
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(100.0, 50.0, 0.0);
glRotatef(-25.0, 0.0, 1.0, 0.0);
How can I get the value of current coordinates of that point?
Need I write a subroutine to multiply a matrix to a vector?
Are there any built-in solutions?
You can't get the coordinates for a specific vertex (point) after a transformation, however for this particular case you can get the ModelViewMatrix after the translate/rotate is applied.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(100.0, 50.0, 0.0);
glRotatef(-25.0, 0.0, 1.0, 0.0);
glGetFloatv(GL_MODELVIEW_MATRIX , *your_matrix*);
//print your matrix to check if that is the desired transformation coordinates
There is no magic tape in OpenGL, you will have to write your own framework e.g: for every objects in your world a class where you hold the vertices and what data you find relevant.
I am using freeglut for opengl rendering...
I need to draw an envelop looking like a cone (2D) that has to be filled with some color and some transparency applied.
Is the freeglut toolkit equipped with such an inbuilt functionality to draw filled geometries(or some trick)?
or is there some other api that has an inbuilt support for filled up geometries..
Edit1:
just to clarify the 2D cone thing... the envelop is the graphical interpretation of the coverage area of an aircraft during interception(of an enemy aircraft)...that resembles a sector of a circle..i should have mentioned sector instead..
and glutSolidCone doesnot help me as i want to draw a filled sector of a circle...which i have already done...what remains to do is to fill it with some color...
how to fill geometries with color in opengl?
Edit2:
All the answers posted to this questions can work for my problem in a way..
But i would definitely would want to know a way how to fill a geometry with some color.
Say if i want to draw an envelop which is a parabola...in that case there would be no default glut function to actually draw a filled parabola(or is there any?)..
So to generalise this question...how to draw a custom geometry in some solid color?
Edit3:
The answer that mstrobl posted works for GL_TRIANGLES but for such a code:
glBegin(GL_LINE_STRIP);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(200.0, 0.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(200.0, 200.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 200.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
which draws a square...only a wired square is drawn...i need to fill it with blue color.
anyway to do it?
if i put some drawing commands for a closed curve..like a pie..and i need to fill it with a color is there a way to make it possible...
i dont know how its possible for GL_TRIANGLES... but how to do it for any closed curve?
On Edit3: The way I understand your question is that you want to have OpenGL draw borders and anything between them should be filled with colors.
The idea you had was right, but a line strip is just that - a strip of lines, and it does not have any area.
You can, however, have the lines connect to each other to define a polygon. That will fill out the area of the polygon on a per-vertex basis. Adapting your code:
glBegin(GL_POLYGON);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(200.0, 0.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(200.0, 200.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 200.0, 0.0);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
Please note however, that drawing a polygon this way has two limitations:
The polygon must be convex.
This is a slow operation.
But I assume you just want to get the job done, and this will do it. For the future you might consider just triangulating your polygon.
I'm not sure what you mean by "an envelop", but a cone is a primitive that glut has:
glutSolidCone(radius, height, number_of_slices, number_of_stacks)
The easiest way to fill it with color is to draw it with color. Since you want to make it somewhat transparent, you need an alpha value too:
glColor4f(float red, float green, float blue, float alpha)
// rgb and alpha run from 0.0f to 1.0f; in the example here alpha of 1.0 will
// mean no transparency, 0.0 total transparency. Call before drawing.
To render translucently, blending has to be enabled. And you must set the blending function to use. What you want to do will probably be achieved with the following. If you want to learn more, drop me a comment and I will look for some good pointers. But here goes your setup:
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Call that before doing any drawing operations, possibly at program initialization. :)
Since you reclarified your question to ask for a pie: there's an easy way to draw that too using opengl primitives:
You'd draw a solid sphere using gluSolidSphere(). However, since you only want to draw part of it, you just clip the unwanted parts away:
void glClipPlane(GLenum plane, const GLdouble * equation);
With plane being GL_CLIPPLANE0 to GL_CLIPPLANEn and equation being a plane equation in normal form (ax + by + c*z + d = 0 would mean equation would hold the values { a, b, c, d }. Please note that those are doubles and not floats.
I remember there was a subroutine for that. But it's neither too hard to do by yourself.
But I don't understand the 2D -thing. Cone in 2D? Isn't it just a triangle?
Anyway, here's an algorithm to drawing a cone in opengl
First take a circle, subdivision it evenly so that you get a nice amount of edges.
Now pick the center of the circle, make triangles from the edges to the center of the circle. Then select a point over the circle and make triangles from the edges to that point.
The size shape and orientation depends about the values you use to generate the circle and two points. Every step is rather simple and shouldn't cause trouble for you.
First just subdivision a scalar value. Start from [0-2] -range. Take the midpoint ((start+end)/2) and split the range with it. Store the values as pairs. For instance, subdividing once should give you: [(0,1), (1,2)] Do this recursively couple of times, then calculate what those points are on the circle. Simple trigonometry, just remember to multiply the values with π before proceeding. After this you have a certain amount of edges. 2^n where n is the amount of subdivisions. Then you can simply turn them into triangles by giving them one vertex point more. Amount of triangles ends up being therefore: 2^(n+1). (The amounts are useful to know if you are doing it with fixed size arrays.
Edit: What you really want is a pie. (Sorry the pun)
It's equally simple to render. You can again use just triangles. Just select scalar range [-0.25 - 0.25], subdivide, project to circle, and generate one set of triangles.
The scalar - circle projection is simple as: x=cos(v*pi)r, y=sin(vpi)*r where (x,y) is the resulting vertex point, r is a radius, and trigonometric functions work on radiances, not degrees. (if they work with degrees, replace pi with 180)
Use vertex buffers or lists to render it yourself.
Edit: About the coloring question. glColor4f, if you want some parts of the geometry to be different by its color, you can assign a color for each vertex in vertex buffer itself. I don't right now know all the API calls to do it, but API reference in opengl is quite understandable.
On the edit on colors:
OpenGL is actually a state machine. This means that the current material and/or color position is used when drawing. Since you probably won't be using materials, ignore that for now. You want colors.
glColor3f(float r, float g, float b) // draw with r/g/b color and alpha of 1
glColor4f(float r, float g, float b, float alpha)
This will affect the colors of any vertices you draw, of any geometry you render - be it glu's or your own - after the glColorXX call has been executed. If you draw a face with vertices and change the color inbetween the glVertex3f/glVertex2f calls, the colors are interpolated.
Try this:
glBegin(GL_TRIANGLES);
glColor3f(0.0, 0.0, 1.0);
glVertex3f(-3.0, 0.0, 0.0);
glColor3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 3.0, 0.0);
glColor3f(1.0, 0.0, 0.0);
glVertex3f(3.0, 0.0, 0.0);
glEnd();
But I pointed at glColor4f already, so I assume you want to set the colors on a per-vertex basis. And you want to render using display lists.
Just like you can display lists of vertices, you can also make them have a list of colors: all you need to do is enable the color lists and tell opengl where the list resides. Of course, they need to have the same outfit as the vertex list (same order).
If you had
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices_);
glDisableClientState(GL_VERTEX_ARRAY);
you should add colors this way. They need not be float; in fact, you tell it what format it should be. For a color list with 1 byte per channel and 4 channels (R, G, B and A) use this:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices_);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors_);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
EDIT: Forgot to add that you then have to tell OpenGL which elements to draw by calling glDrawElements.