I have a cube made with a triangle strip, and I am trying to find the UV coordinates for it.
vert = new VBO<Vector3>(new Vector3[] {
new Vector3(1, 1, 1),
new Vector3(0, 1, 1),
new Vector3(1, 1, 0),
new Vector3(0, 1, 0),
new Vector3(1, 0, 1),
new Vector3(0, 0, 1),
new Vector3(0, 0, 0),
new Vector3(1, 0, 0)
});
ind = new VBO<uint>(new uint[] { 3, 2, 6, 7, 4, 2, 0, 3, 1, 6, 5, 4, 1, 0 }, BufferTarget.ElementArrayBuffer);
Does anyone know what they would be?
Short Answer: You can assign any value to the UV coordinates, even if they overlap ( albeit, this isn't usually desirable ). So long as you create a UV coordinate for every vertex coordinate. If you're Ok with overlaps, you could just declare 8 Vector2(s) as your UV coordinates and assign them with any value between -1 and 1.
Long answer:
This all depends on the way you index your coordinates.
UV coordinates tell you how to map a 2D polygonal region of a 2D texture to your 3D model geometry. There should be a UV coordinate for every vertex coordinate, if your UV(s) and vertices use the same indices ( which doesn't seem optimal for your vertex coordinates as they are ).
Indices designate which of your coordinates ( 3 indices for triangles, 4 for squares ) correlate to a 2D (texture) or 3D (model) polygon. The way your vertex coordinates are defined, unless you duplicated every vertex in a way that every 3 vertices defines a triangle, you'd have to use indexing to indicate which of your 8 vertices is a polygon. For example, the indices { 0, 1, and 3 } indicate the top-right-rear ( rear here, meaning further on the positive Z axis ) triangle on top of your cube.
An issue comes with using the same index array for your vertices and UV(s). If you indexed your model as is, your model faces wouldn't have any problems but some of your UV faces would overlap with other previously defined UV faces. This is because the vertices of some faces will be shared with other vertices on the the other side of your texture space. Think about your cube as if it were a cross and to put it together, you would wrap the base back around to the top. You can't do that if your cube's geometry only exists in 2 dimensions ( as it would in your UV coordinates ).
The seemingly best solution in this case would be to use cube projection, which I don't know how to do yet. So, I'll recommend what I understand is the next best solution:
Duplicate any vertices that would cause the UV faces to wrap over one another ( the base of the cross ) and optionally vertices that would cause too much distortion in the way the texture would be applied to the vertex coordinates; the 2 outer vertices of the head, "hip"(?), and arms of the cross would be further spaced out, requiring distortion in the texture to produce the desired outputs.
Doing so should result in you having 10 vertex coordinates, 10 UV coordinates, and 36 indices, where every 3 indices defines a triangle ( 12 triangles ).
Keep in mind, there multiple ways of achieving what you're asking so deeper research is recommended.
A visual representation of the previously described coordinate and indexing alignment.
( Fixed the Z axis )
This represents duplication of the vertex and UV coordinates at index 0 and 1 to indices 8 and 9. Vertex coordinates 8 and 9 hold the same 3D location value as vertex 0 and 1, whereas the UV coordinates 8 and 9 are located lower on the Y axis than coordinates 6 and 7.
I forgot to put this in the example image but the indices in the example would be:
int indices[] = {
0, 1, 2,
1, 2, 3,
2, 3, 4,
3, 4, 5,
0, 2, 4,
0, 4, 6,
1, 3, 5,
1, 5, 7,
4, 5, 6,
5, 6, 7,
6, 7, 8,
7, 8, 9
}
This will give you 12 modelspace triangles and 12 UV triangles, where every 3 indices is a triangle.
EDIT: As per the link provided by #Rabbid76, 14 vertex and UV coordinates would be better as you wouldn't get the distortion. The way I mentioned is just another way of doing it that has its ups and downs( more distortion, slightly less memory usage ).
Related
I am trying to render 3D prisms in LWJGL OpenGL with flat shading. For example, I have a cube indexed as following:
I only have 8 vertices in the vertex buffer, which I have indexed as above. Is there any way to implement flat normal shading on the cube such as below? I don't want to rewrite my vertex and index buffers to include duplicate vertices if possible.
If you don't need any other attributes (e.g. texture coordinates), then there is an option to create a cube mesh with face normal vectors, by 8 vertices only. Use the flat Interpolation qualifier for the normal vector.
Vertex shader:
flat out vec3 surfaceNormal;
Fragment sahder:
flat out vec3 surfaceNormal;
When the flat qualifier is used, then the output of the vertex shader will not be interpolated. The value given to the fragment shader is one of the attributes associated to one vertex of the primitive, the Provoking vertex.
For a GL_TRINANGLE primitive this is either the last or the first vertex. That can be chosen by glProvokingVertex.
Choose the first vertex:
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
For the order of the points of your cube mesh (image in the question)
front back
1 3 7 5
+---+ +---+
| | | |
+---+ +---+
0 2 6 4
you have to setup the following vertex coordinates and normal vectors:
// x y z nx, ny, nz
-1, -1, -1, 0, -1, 0, // 0, nv front
-1, -1, 1, 0, 0, 1, // 1, nv top
1, -1, -1, 0, 0, 0, // 2
1, -1, 1, 1, 0, 0, // 3, nv right
1, 1, -1, 0, 1, 0, // 4, nv back
1, 1, 1, 0, 0, 0, // 5
-1, 1, -1, 0, 0, -1, // 6, nv bottom
-1, 1, 1, -1, 0, 0, // 7, nv left
Define the indices in that way, that the vertices 7, 3, 0, 4, 6, 1 are the first vertex for both triangles of the left, right, front, back, bottom and top of the cube:
0, 2, 3, 0, 3, 1, // front
4, 6, 7, 4, 7, 5, // back
3, 2, 4, 3, 4, 5, // right
7, 6, 0, 7, 0, 1, // left
6, 4, 2, 6, 2, 0, // bottom
1, 3, 5, 1, 5, 7 // top
Draw 12 triangle primitives. e.g:
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
For flat shading, it is better to use a geometry shader to compute the normals for each of the primitives. Although you can use the provoking-vertex method when rendering a cube, you cannot use it for certain geometric objects where the number of faces is more than that of the vertices: e.g. consider the polyhedron obtained by gluing two tetrahedra at their base triangle. Such an object will have 6 triangles but only 5 vertices (note that Euler's formula still holds: v-e+f = 5-9+6 = 2), so there are not enough vertices to send the face-normals via the vertices. Even if you can do that, another reason not to use provokig-vertex method is that it is not convenient to do so, because you would have to find a way to enumare the vertices in a way such that each vertex uniquely 'represents' a single face, so that you can associate the face-normal with it.
In a nutshell, just use a geometry shader, it is much simpler and more importantly much more robust. Not to mention that the normal calculations are done on the fly inside the GPU, rather than you having to set them up on CPU, creating & binding the necessary buffers and defining attributes which increases both the set-up costs and eats up the memory bandwith between the CPU and the GPU.
I'm new to OpenGL and I'm trying to understand how the projection matrix works in it.
To create a simple case, I define a triangle in the world space and its coordinates are:
(0,1,0), (1,0,0), (-1,0,0)
I set the modelview matrix and projection matrix as below:
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
0, 0, 2,
0, 0, 0,
0, 1, 0);
glMatrixMode(GL_PROJECTION);
glOrtho(-2, 2, -2, 2, -0.1, -2.0); // does not work
// glOrtho(-2, 2, -2, 2, 0.1, 2.0); // works
From my understanding, gluLookAt() is used to set the viewing matrix. Since OpenGL does not have a concept of "camera", and thus it transforms the entire world to reach the effect of a camera. In the above code, I assume the "camera" is at (0,0,2), looking at (0,0,0). So OpenGL internally moves the triangle backwards along z axis to z=-2.
To define a view frustum, glOrtho() get 6 parameters. To make the triangle visible in the frustum, I set the near and far value to -0.1 and -2.0 respectively and this should indicate that the frustum include [-0.1, -2.0] on z axis.
I searched for similar questions and found out someone states that the last two parameters of glOrtho() is in fact -near and -far. But if this is correct, the following code should work(but it doesn't):
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
0, 0, -2, // changed 2 to -2, thus the triangle should be transformed to z=2?
0, 0, 0,
0, 1, 0);
glMatrixMode(GL_PROJECTION);
glOrtho(-2, 2, -2, 2, -0.1, -2.0); // -near=-0.1, -far=-2.0, thus the frustum should include [0.1, 2.0], thus include the triangle
If I'm correct, the triangle should be drawn on the screen, so there must be something wrong with my code. Can anyone help?
First of all note, that the fixed function pipeline matrix stack and drawing by 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.
If you use a view matrix like this:
gluLookAt(0, 0, 2, 0, 0, 0, 0, 1, 0);
Then the values for the near and the far plane have to be positive when you set up the the projection matrix,
glOrtho(-2, 2, -2, 2, 0.1, 2.0);
because, gluLookAt transforms the vertices to view space (in view space the z axis points out of the viewport), but the projection matrix inverts the z-axis.
But be careful, since the triangle is at z=0
(0,1,0), (1,0,0), (-1,0,0)
and the distance from the camera to the triangle is 2, because of the view matrix, the triangle is placed exactly on the far plane (which is 2.0 too). I recommend to increase the distance to the far plane from 2.0 to (e.g.) 3.0:
glOrtho(-2, 2, -2, 2, 0.1, 3.0);
If you change the view matrix,
gluLookAt(0, 0, -2, 0, 0, 0, 0, 1, 0);
then still the (view space) z-axis points out of the viewport, but you look at the "back" side of the triangle. The triangle is still in the center of the view (0, 0, 0), but the camera position has changed. The triangle is still in front of the camera.
If you would do
gluLookAt(0, 0, 2, 0, 0, 4, 0, 1, 0);
then you would look away from the triangle. You would have to project the backside of the view to the viewport to "see" the triangle (glOrtho(-2, 2, -2, 2, -0.1, -3.0);).
Further note, that glOrtho multiplies the current matrix by the orthographic projection matrix. This means you should set the identity matrix, before you use glOrtho, as you do it with the model view matrix:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-2, 2, -2, 2, 0.1, 2.0);
Explanation
The projection, view and model matrix interact together to present the objects (meshes) of a scene on the viewport.
The model matrix defines the position orientation and scale of a single object (mesh) in the worldspace of the scene.
The view matrix defines the position and viewing direction of the observer (viewer) within the scene.
The projection matrix defines the area (volume) with respect to the observer (viewer) projected onto the viewport.
At orthographic projection, this area (volume) is defined by 6 distances (left, right, bottom, top, near and far) to the viewer's position.
View matrix
The view coordinates system describes the direction and position from which the scene is looked at. The view matrix transforms from the wolrd space to the view (eye) space.
If the coordiante system of the view space is a Right-handed system, then the X-axis points to the left, the Y-axis up and the Z-axis out of the view (Note in a right hand system the Z-Axis is the cross product of the X-Axis and the Y-Axis).
Projection matrix
The projection matrix describes the mapping from 3D points of the view on a scene, to 2D points on the viewport. It transforms from eye space to the clip space, and the coordinates in the clip space are transformed to the normalized device coordinates (NDC) by dividing with the w component of the clip coordinates. The NDC are in range (-1,-1,-1) to (1,1,1). Every geometry which is out of the clippspace is clipped.
At Orthographic Projection the coordinates in the view space are linearly mapped to clip space coordinates and the clip space coordinates are equal to the normalized device coordinates, because the w component is 1 (for a cartesian input coordinate).
The values for left, right, bottom, top, near and far define a box. All the geometry which is inside the volume of the box is "visible" on the viewport.
The Orthographic Projection Matrix looks like this:
r = right, l = left, b = bottom, t = top, n = near, f = far
2/(r-l) 0 0 0
0 2/(t-b) 0 0
0 0 -2/(f-n) 0
-(r+l)/(r-l) -(t+b)/(t-b) -(f+n)/(f-n) 1
The z-axis is inverted by the projection matrix.
i want to know how is OpenGL's glLightfv() works i mean if a glortho is set to (10, -10, 10, -10, 10, -10) then if a traingle's vertices are within 5 (eg. glVertex3f(0, 5, 0), glVertex3f(-5, -5, -5) and so on until a 3d triangle is created) then where should i place the light?? From most tutorials they were 1, 1, 1, 0. but by this my Model which is a colour full 3d triangle, becomes full White, can anyone here make me understand how can the lighting function of opengl be used in program, with shadoes and colour, i hope i was clear, thanks in advance!!
Problem
When using a vertex buffer objects to draw textured primitives, we have to define a separate buffer to store a list of texture coordinates at each vertex. This texture coordinate array has to map to each vertex in the VBO, thus, we need a large array if we are drawing many primitives.
However, if all primitives have the same texture coordinates, it is a waste to repeat the coordinates for each primitive that will be drawn with glDraw* call.
Example
I have a large number of textured quads that need to be drawn. The quads share the same texture. All vertices are put in a VBO and a large texture coordinate array is created. The textured quads are drawn with a call to glDrawArrays.
4----3 8----7
| /| | /|
| / | | / |
| / | | / |
|/ | |/ |
1----2 5----6
vertex buffer: { 1, 2, 3, 4, 5, 6, 7, 8 }
Texture coordinate array: { 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1 }
<-------------------->
coordinates repeated
for second quad
The texture coordinate array repeats every 4 vertices. This buffer has to be recreated every time a batch of quads has to be drawn as we do not know the number of quads beforehand. The repeating texture coordinates also waste memory.
Question
Is there a way to remove the repetition in texture coordinate arrays when the primitives to be drawn have all the same texture coordinates?
I'm trying to model an object described in a WRL (VRML) file using OpenGL.
I'm not really concerned with parsing the file, I figure that part will be fairly straight forward. At this stage I am just trying to hard-code in a vertex array and index array so that I can get a good understanding of how this works so that I can generalise for any WRL input file.
I'm trying a basic box (rectangular prism) model first. I currently have this vertex array:
GLfloat vertices[] = {
-0.200000, -0.025000, -0.050000,
-0.200000, -0.025000, 0.050000,
-0.200000, 0.025000, -0.050000,
-0.200000, 0.025000, 0.050000,
0.200000, -0.025000, -0.050000,
0.200000, -0.025000, 0.050000,
0.200000, 0.025000, -0.050000,
0.200000, 0.025000, 0.050000
};
and this index array:
GLubyte indices[] = {
7, 3, 5, -1, 5, 3, 1, -1,
6, 2, 7, -1, 7, 2, 3, -1,
4, 0, 6, -1, 6, 0, 2, -1,
5, 1, 4, -1, 4, 1, 0, -1,
2, 0, 3, -1, 3, 0, 1, -1,
4, 6, 5, -1, 5, 6, 7, -1
};
which came directly from the WRL file Coordinate3 {point []} and IndexedFaceSet {coordIndex []}.
I then enable vertex array functionality by calling:
glEnableClientState(GL_VERTEX_ARRAY);
and set up the glVertexPointer:
glVertexPointer(3, GL_FLOAT, 0, vertices);
finally I use the glDrawElements function to draw the box:
glDrawElements(GL_POLYGON, 24, GL_UNSIGNED_BYTE, indices);
and then deactivate vertex array functionality:
glDisableClientState(GL_VERTEX_ARRAY);
So after this, I would expect a box to be drawn, and when I use glDrawElements(GL_POINTS, 24, GL_UNSIGNED_BYTE, indices); it shows the 8 vertices as epected in what, if the correct vertices were joined with lines, would represent the box expected (except there is a point in the middle, but when I use 26 as the count argument, then the point in the middle dissappears)
However when I use GL_POLYGON or GL_LINE_LOOP at the first argument to glDrawElements, I get rubbish. The 8 vertices are obviously there, but they're joined up in really strange ways.
I'm pretty confused by now, and I'm not even sure I'm doing this correctly. Perhaps someone could put me in the right direction at least?
A rectangular prism is not a GL_POLYGON. Note the singular form of that word: polygon. As in one polygon. A rectangular prism is composed of many polygons, not just one.
What you want is to draw some GL_TRIANGLES. Create an index list that shows each of the triangles that compose the box. That means each box face is made of two triangles, so you need 12 triangles total. That means 36 indices.