I have a problem with drawing a cube with VBO from a .obj file.
Here is the .obj :
# cube.obj
#
g cube
v 0.0 0.0 0.0
v 0.0 0.0 1.0
v 0.0 1.0 0.0
v 0.0 1.0 1.0
v 1.0 0.0 0.0
v 1.0 0.0 1.0
v 1.0 1.0 0.0
v 1.0 1.0 1.0
vn 0.0 0.0 1.0
vn 0.0 0.0 -1.0
vn 0.0 1.0 0.0
vn 0.0 -1.0 0.0
vn 1.0 0.0 0.0
vn -1.0 0.0 0.0
f 1//2 7//2 5//2
f 1//2 3//2 7//2
f 1//6 4//6 3//6
f 1//6 2//6 4//6
f 3//3 8//3 7//3
f 3//3 4//3 8//3
f 5//5 7//5 8//5
f 5//5 8//5 6//5
f 1//4 5//4 6//4
f 1//4 6//4 2//4
f 2//1 6//1 8//1
f 2//1 8//1 4//1
To draw it, I first read the objet with the glmReadOBJ function. Next, I extract the information contained in the model generated (with the "trianglulate" function) to be able to create the VBO object and then draw it, here is what I do :
void triangulate(GLfloat* vertices, GLfloat* normals, GLMmodel *model)
{
int i, j;
int it = 0;
GLuint *tempN, *tempV;
for (int i = 0; i < model->numtriangles; i++)
{
tempV = model->triangles[i].vindices;
tempN = model->triangles[i].nindices;
for (int j = 0; j < 3; j++)
{
vertices[it] = model->vertices[tempV[j] - 1];
normals[it] = model->normals[tempN[j] - 1];
it++;
}
}
}
void glmInitVBO(GLMmodel* model, int* vboId)
{
GLfloat *vertices = (GLfloat*)malloc(model->numtriangles * 3 * sizeof(GLfloat));
GLfloat *normals = (GLfloat*)malloc(model->numtriangles * 3 * sizeof(GLfloat));
triangulate(vertices, normals, model);
glGenBuffersARB(1, vboId);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices) + sizeof(normals), 0, GL_STATIC_DRAW_ARB);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(vertices),vertices); // copy vertices starting from 0 offest
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices), sizeof(normals), normals); // copy normals after vertices
}
void glmDrawVBO(GLMmodel* model, int* vboId)
{
GLfloat *vertices = (GLfloat*)malloc(model->numtriangles * 3 * sizeof(GLfloat));
GLfloat *normals = (GLfloat*)malloc(model->numtriangles * 3 * sizeof(GLfloat));
triangulate(vertices, normals, model);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, *vboId);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, (void*)sizeof(vertices));
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawArrays(GL_TRIANGLES, 0, 36);
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
glDisableClientState(GL_NORMAL_ARRAY);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
}
In my main, I call glmReadOBJ, then glmInitVBO and finally glmDrawVBO but nothing happens : the window remains black, nothing is drawn.
I don't know what I did wrong and tried many things for hours, but the only thing I obtain in the end is a black window ...
Thank you for your help !
The main issue I see is unrelated to your OpenGL usage, but just a misunderstanding of how the sizeof operator works. For example in this code segment (there are more similar cases in the rest of the code):
GLfloat *vertices = (GLfloat*)malloc(model->numtriangles * 3 * sizeof(GLfloat));
GLfloat *normals = (GLfloat*)malloc(model->numtriangles * 3 * sizeof(GLfloat));
...
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices) + sizeof(normals), 0, GL_STATIC_DRAW_ARB);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(vertices),vertices); // copy vertices starting from 0 offest
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices), sizeof(normals), normals); // copy normals after vertices
vertices and normal are declared as pointer variables. Their sizes are therefore 32 bits (4 bytes) when building in 32-bit mode, and 64 bits (8 bytes) when building in 64-bit mode. So 4/8 are the values you get when using the sizeof operator on the variables.
What you need to pass to the glBufferData() and glBufferSubData() functions is the actual size of the data you allocated, not the size of the pointer. For example:
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, model->numtriangles * 3 * sizeof(GLfloat), vertices);
Another problem is with this call in glmInitVBO():
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);
where vboId is declared as a pointer to the int value that contains the VBO id. However, glBindBuffer() takes the id as an argument, not a pointer to the id. So the call should be:
glBindBufferARB(GL_ARRAY_BUFFER_ARB, *vboId);
BTW, these functions have been part of standard OpenGL since about version 1.1. There really shouldn't be a need to use the extension version.
Related
If one has two continuous ranges of device memory it is possible to copy memory from from one to the other using cudaMemcpy.
double* source = ...
double* dest = ...
cudaMemcpy(dest, source, N, cudaMemcpyDeviceToDevice);
Now suppose that I want to copy source into dest, but every 2 or 3 elements respectively.
That is dest[0] = source[0], dest[3] = source[2], dest[6] = source[4], ....
Of course a single plain cudaMemcpy cannot do this.
Intuitively, cudaMemcpy2D should be able to do the job, because "strided elements can be see as a column in a larger array".
But cudaMemcpy2D it has many input parameters that are obscure to interpret in this context, such as pitch.
For example, I manager to use cudaMemcpy2D to reproduce the case where both strides are 1.
cudaMemcpy2D(dest, 1, source, 1, 1, n*sizeof(T), cudaMemcpyDeviceToHost);
But I cannot figure out the general case, with dest_stride and source_stride difference from 1.
Is there a way to copy strided data to stride data with cudaMemcpy2D?
In which order do I have to put the known information about the layout?, namely, in terms of the two strides and sizeof(T).
cudaMemcpy2D(dest, ??, source, ???, ????, ????, cudaMemcpyDeviceToHost);
Yes, this can be done. It is easier to illustrate in code than words so:
#include <iostream>
int main()
{
const size_t swidth = 2;
const size_t sheight = 4;
size_t spitch = swidth * sizeof(int);
int source[swidth * sheight] = { 0, 1, 2, 3, 4, 5, 6, 7 };
const size_t dwidth = 3;
const size_t dheight = 4;
size_t dpitch = dwidth * sizeof(int);
int dest[dwidth * dheight] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
const size_t cwidth = 1 * sizeof(int);
const size_t cheight = 3;
int* source_d; cudaMalloc(&source_d, spitch * sheight);
cudaMemcpy(source_d, &source[0], spitch * sheight, cudaMemcpyHostToDevice);
cudaMemcpy2D(&dest[0], dpitch, source_d, spitch, cwidth, cheight, cudaMemcpyDeviceToHost);
for(int i=0; i < 12; i++) std::cout << i << " " << dest[i] << std::endl;
return 0;
}
which does this:
$ nvcc -std=c++11 -arch=sm_52 -o strided_copy strided_copy.cu
$ cuda-memcheck ./strided_copy
========= CUDA-MEMCHECK
0 0
1 -1
2 -1
3 2
4 -1
5 -1
6 4
7 -1
8 -1
9 -1
10 -1
11 -1
========= ERROR SUMMARY: 0 errors
In essence, you are copying a width of 4 bytes (an int) with a stride of 8 bytes (two ints) into a destination with a stride of 12 bytes (three ints). I only copied three rwos so that it obvious how the row argument works. Adjust the size of the copy element and strides, etc. to taste.
A generic function for such a strided copy could look roughly like this:
void cudaMemcpyStrided(
void *dst, int dstStride,
void *src, int srcStride,
int numElements, int elementSize, int kind) {
int srcPitchInBytes = srcStride * elementSize;
int dstPitchInBytes = dstStride * elementSize;
int width = 1 * elementSize;
int height = numElements;
cudaMemcpy2D(
dst, dstPitchInBytes,
src, srcPitchInBytes,
width, height,
kind);
}
And for your example, it could be called as
cudaMemcpyStrided(dest, 3, source, 2, 3, sizeof(double), cudaMemcpyDeviceToDevice);
"Roughly", because I just translated it on the fly from the (Java/JCuda based) code that I tested it with:
import static jcuda.runtime.JCuda.cudaMemcpy2D;
import java.util.Arrays;
import java.util.Locale;
import jcuda.Pointer;
import jcuda.Sizeof;
import jcuda.runtime.cudaMemcpyKind;
public class JCudaStridedMemcopy {
public static void main(String[] args) {
int dstLength = 9;
int srcLength = 6;
int dstStride = 3;
int srcStride = 2;
int numElements = 3;
runExample(dstLength, dstStride, srcLength, srcStride, numElements);
dstLength = 9;
srcLength = 12;
dstStride = 3;
srcStride = 4;
numElements = 3;
runExample(dstLength, dstStride, srcLength, srcStride, numElements);
dstLength = 18;
srcLength = 12;
dstStride = 3;
srcStride = 2;
numElements = 6;
runExample(dstLength, dstStride, srcLength, srcStride, numElements);
}
private static void runExample(int dstLength, int dstStride, int srcLength, int srcStride, int numElements) {
double dst[] = new double[dstLength];
double src[] = new double[srcLength];
for (int i = 0; i < src.length; i++) {
src[i] = i;
}
cudaMemcpyStrided(dst, dstStride, src, srcStride, numElements);
System.out.println("Copy " + numElements + " elements");
System.out.println(" to array with length " + dstLength + ", with a stride of " + dstStride);
System.out.println(" from array with length " + srcLength + ", with a stride of " + srcStride);
System.out.println("");
System.out.println("Destination:");
System.out.println(toString2D(dst, dstStride));
System.out.println("Flat: " + Arrays.toString(dst));
System.out.println("");
System.out.println("Source:");
System.out.println(toString2D(src, srcStride));
System.out.println("Flat: " + Arrays.toString(src));
System.out.println("");
System.out.println("Done");
System.out.println("");
}
private static void cudaMemcpyStrided(double dst[], int dstStride, double src[], int srcStride, int numElements) {
long srcPitchInBytes = srcStride * Sizeof.DOUBLE;
long dstPitchInBytes = dstStride * Sizeof.DOUBLE;
long width = 1 * Sizeof.DOUBLE;
long height = numElements;
cudaMemcpy2D(
Pointer.to(dst), dstPitchInBytes,
Pointer.to(src), srcPitchInBytes,
width, height,
cudaMemcpyKind.cudaMemcpyHostToHost);
}
public static String toString2D(double[] a, long columns) {
String format = "%4.1f ";
;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < a.length; i++) {
if (i > 0 && i % columns == 0) {
sb.append("\n");
}
sb.append(String.format(Locale.ENGLISH, format, a[i]));
}
return sb.toString();
}
}
To give an idea of what the function does, based on the examples/test cases, here is the output:
Copy 3 elements
to array with length 9, with a stride of 3
from array with length 6, with a stride of 2
Destination:
0.0 0.0 0.0
2.0 0.0 0.0
4.0 0.0 0.0
Flat: [0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 4.0, 0.0, 0.0]
Source:
0.0 1.0
2.0 3.0
4.0 5.0
Flat: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
Done
Copy 3 elements
to array with length 9, with a stride of 3
from array with length 12, with a stride of 4
Destination:
0.0 0.0 0.0
4.0 0.0 0.0
8.0 0.0 0.0
Flat: [0.0, 0.0, 0.0, 4.0, 0.0, 0.0, 8.0, 0.0, 0.0]
Source:
0.0 1.0 2.0 3.0
4.0 5.0 6.0 7.0
8.0 9.0 10.0 11.0
Flat: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0]
Done
Copy 6 elements
to array with length 18, with a stride of 3
from array with length 12, with a stride of 2
Destination:
0.0 0.0 0.0
2.0 0.0 0.0
4.0 0.0 0.0
6.0 0.0 0.0
8.0 0.0 0.0
10.0 0.0 0.0
Flat: [0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 4.0, 0.0, 0.0, 6.0, 0.0, 0.0, 8.0, 0.0, 0.0, 10.0, 0.0, 0.0]
Source:
0.0 1.0
2.0 3.0
4.0 5.0
6.0 7.0
8.0 9.0
10.0 11.0
Flat: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0]
Done
I have been asked to design and animate a solar system in openGL. I am doing so in C. I am a bit confused as to exactly how I should go about animating the orbits. How should I be incrementing the rotation angle for each planet to control the speed of it's orbit around the sun?
Here is all of the code I have written so far, just trying to take it step by step:
#include <GL/glut.h>
#include <GL/glu.h>
#define FACTOR 30.0
#define SLICES 25
#define STACKS 25
//Viewing angle variables
int eye_x = 2.0;
int eye_y = 3.0;
int eye_z = 10.0;
int up_x = 0.0;
int up_y = 1.0;
int up_z = 0.0;
//Planet diameters in relation to earth
double sun_radius = 100.0;
double earth_radius = 1.0;
double moon_radius = 0.2724;
double mercury_radius = 0.383;
double venus_radius = 0.949;
double mars_radius = 0.532;
double jupiter_radius = 11.21;
double saturn_radius = 9.45;
double uranus_radius = 4.01;
double neptune_radius = 3.88;
double pluto_radius = 0.187;
//Planet distances from sun in relation to earth's distance
double mercury_distance = (sun_radius / FACTOR) + 0.387;
double venus_distance = mercury_distance + 0.723;
double earth_distance = venus_distance + 1.0;
double mars_distance = earth_distance + 1.52;
double jupiter_distance = mars_distance + 5.20;
double saturn_distance = jupiter_distance + 9.58;
double uranus_distance = saturn_distance + 19.20;
double neptune_distance = uranus_distance + 30.05;
double pluto_distance = neptune_distance + 39.24;
/**
* Init function initializing the background to black.
*/
void init()
{
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glOrtho(-100.0, 100.0, -100.0, 100.0, -100.0, 100.0);
glMatrixMode(GL_MODELVIEW | GL_PROJECTION);
glEnable(GL_DEPTH_TEST);
gluLookAt(eye_x, eye_y, eye_z, 0.0, 0.0, 0.0, up_x, up_y, up_z);
}
/*
void stars()
{
int noOfStars = rand() % 10;
int i = 0;
while(i < noOfStars)
{
glColor3f(1.0, 1.0, 1.0);
glPointSize(20.0f);
int x = rand() % 10;
int y = rand() % 10;
int z = -8.0;
glBegin(GL_POINTS);
glVertex3f(x, y, z);
glEnd();
i++;
}
glFlush();
glutSwapBuffers();
}
*/
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//stars();
//"Zoom out"
glTranslatef(0.0, 0.0, -20.0);
//Draw sun
glColor4f(1.0, 0.5, 0.0, 0.3);
glutWireSphere(sun_radius / FACTOR, SLICES, STACKS);
//Draw mercury
//Rotate around sun
//glRotatef(, 0.0, 1.0, 0.0);
//Distance from sun to mercury
glTranslatef(mercury_distance, 0.0, 0.0);
glPushMatrix();
//glRotatef( , 0.0, 1.0, 0.0);
glColor4f(1.0, 0.75, 0.75, 0.3);
glutWireSphere(mercury_radius, SLICES, STACKS);
glPopMatrix();
/*
//Draw venus
//Distance from sun to venus
glTranslatef(venus_distance, 0.0, 0.0);
glPushMatrix();
glColor4f(1.0, 0.75, 0.75, 0.3);
glutWireSphere(venus_radius, SLICES, STACKS);
glPopMatrix();
//Draw earth
//Distance from sun to earth
glTranslatef(earth_distance, 0.0, 0.0);
glPushMatrix();
glColor4f(1.0, 0.75, 0.75, 0.3);
glutWireSphere(earth_radius, SLICES, STACKS);
glPopMatrix();
*/
glFlush();
glutSwapBuffers();
}
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowPosition(0,0);
glutInitWindowSize(1000, 1000);
glutCreateWindow("solar system");
init();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutMainLoop();
return 0;
}
First, there is not a single distance from the sun for any of the planets - they move in a Kepler ellipse. (Earth was closest to the sun two weeks ago at the beginning of January and will be farthest away in summer.)
Accordingly, the position angle of a planet will not change at a constant rate, if you want to do this accurately. You can of course simplify and say that planetary orbits are close enough to circles for this not to matter (and say that Pluto is not a planet any more, so it even doesn't matter there).
But let's go for an exact solution: This is governed by Newton's law:
F = g * M_1 * M_2 / r^2 // How do you put equations here?
and energy conservation, trading kinetic energy E = M v^2 / 2 for potential energy E = - g * M_1 * M_2 / r
So, to simulate the motion of a planet around the sun, get its position, its velocity and the gravitational force acting upon it, calculate where you end up one time step later, calculate the new velocity and force acting on it, and repeat. (Do the same for all planets and ignore gravitational interactions between them for the moment.)
That would be an actual simulation of the solar system. If you only want to simulate the positions at any given time, look up Keplers laws - essentially a consequence of applying Newtons law.
I just saw that the article above even has a section on "Position as a function of time" - so that should help you with the algorithm.
So in my program, I'm using OpenGL/GLSL to construct a square and texturing it.
It's modern OpenGL 4.0+ so doesn't use glBegin/glEnd etc.
My square is made up of 2 triangles, constructed using glDrawArrays(GL_TRIANGLES, 0, 6);
As you can see with my function below, it creates 2 triangles. I'm using 18 vertices in an array when really I only need 12 to create a square because 6 of them are used in both triangles. Its the same with the 24 colours and 8 text coordinates.
void Ground::constructGeometry(Shader* myShader)
{
//Triangle 1 (x,y,z)
vert[0] =-dimY; vert[1] = dimX; vert[2] = dimZ; //Point 2
vert[3] =-dimY; vert[4] =-dimX; vert[5] = dimZ; //Point 1
vert[6] = dimY; vert[7] =-dimX; vert[8] = dimZ; //Point 4
//Triangle 2 (x,y,z)
vert[9] = dimY; vert[10] =-dimX; vert[11] = dimZ; //Point 4
vert[12] = dimY; vert[13] = dimX; vert[14] = dimZ; //Point 3
vert[15] =-dimY; vert[16] = dimX; vert[17] = dimZ; //Point 2
//Colours 1 (r,g,b,a)
col[0] = 1.0f; col[1] = 0.0f; col[2] = 0.0f; col[3] = 1.0f;
col[4] = 1.0f; col[5] = 0.0f; col[6] = 0.0f; col[7] = 1.0f;
col[8] = 1.0f; col[9] = 0.0f; col[10] = 0.0f; col[11] = 1.0f;
//Colours 2 (r,g,b,a)
col[12] = 1.0f; col[13] = 0.0f; col[14] = 0.0f; col[15] = 1.0f;
col[16] = 1.0f; col[17] = 0.0f; col[18] = 0.0f; col[19] = 1.0f;
col[20] = 1.0f; col[21] = 0.0f; col[22] = 0.0f; col[23] = 1.0f;
//(s,t) coords for Tri 1
tex[0] = 0.0; tex[1] = 1.0;
tex[2] = 0.0; tex[3] = 0.0;
tex[4] = 1.0; tex[5] = 0.0;
//(s,t) coords for Tri 2
tex[6] = 1.0; tex[7] = 0.0;
tex[8] = 1.0; tex[9] = 1.0;
tex[10] = 0.0; tex[11] = 1.0;
glGenVertexArrays(2, &m_vaoID[0]);
glBindVertexArray(m_vaoID[0]);
glGenBuffers(3, m_vboID);
GLint vertexLocation= glGetAttribLocation(myShader->handle(), "in_Position");
GLint colorLocation= glGetAttribLocation(myShader->handle(), "in_Color");
GLint texCoordLocation = glGetAttribLocation(myShader->handle(), "in_TexCoord");
glUniform1i(glGetUniformLocation(myShader->handle(), "DiffuseMap"), 0);
glBindBuffer(GL_ARRAY_BUFFER, m_vboID[0]);
glBufferData(GL_ARRAY_BUFFER, totalVerts *sizeof(GLfloat), vert, GL_STATIC_DRAW);
glEnableVertexAttribArray(vertexLocation);
glVertexAttribPointer(vertexLocation, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_vboID[1]);
glBufferData(GL_ARRAY_BUFFER, totalCols *sizeof(GLfloat), col, GL_STATIC_DRAW);
glEnableVertexAttribArray(colorLocation);
glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, m_vboID[2]);
glBufferData(GL_ARRAY_BUFFER, totalTexs *sizeof(GLfloat), tex, GL_STATIC_DRAW);
glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0,0);
glEnableVertexAttribArray(texCoordLocation);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
}
How can this be made more efficient so when making the second triangle I can use vert[x] that's already been used instead of declaring the same ones again (points 4 and 2)?
And the same with colours?
And how does this affect my rendering function below?
void Ground::render(GLuint texName, Shader* myShader)
{
glUseProgram(myShader->handle()); //find shader passed
glBindTexture(GL_TEXTURE_2D, texName); //blending needed to use alpha channel
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBindVertexArray(m_vaoID[0]); //select first VAO
glDrawArrays(GL_TRIANGLES, 0, 6); //draw first object 0-3, then second 3-6
glDisable(GL_BLEND);
glUseProgram(0);
glBindVertexArray(0); //unbind the vertex array object
}
Obviously I guess it's OK to do it the way I have for only 2 triangles, but I wouldn't want to write out hundreds of vertices if, for some reason, I suddenly wanted a whole bunch of triangles...
Use glDrawElements() instead of glDrawArrays() if you would like to reuse vertices.
glDrawElements takes an index array argument, which allows you to specify the indices of vertices in the vertex array, making it possible to use them multiple times.
As an alternative to the (correct) answers using glDrawElements, you could use glDrawArrays with GL_TRIANGLE_FAN instead of GL_TRIANGLES. A fan uses the first three vertices to draw a triangle, then each subsequent vertex will generate a triangle using the new vertex, the last vertex and the first vertex. Now you only need four vertices (arranged counter-clockwise) in your array, and the call looks like:
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
What you asking for is called indexed rendering. The basic idea is to provide an index buffer those elements reference the vertex IDs in your vertex arrays. So for two triangles sharing one edge, you can define just the 4 corner vertices and can use and index array like {0,1,2, 2,1,3}. You will have to use glDrawElements() to do the drawing.
You might also want to have a look at this wiki page to get an overview of what drawing paths are available in modern GL.
Well question is similiar to my previous one about glOrtho variant
glOrtho OpenGL es 2.0 variant how fix blank screen?
Triangle below is draw perfectly at ortho projection (without projection it's squashed triangle, instead of the three equal sides triangle on rectangle viewport)
GLfloat triangle_vertices[] =
{
-0.5, -0.25, 0.0,
0.5, -0.25, 0.0,
0.0, 0.559016994, 0.0
};
Ortho matrix code:
typedef float[16] matrix;
void ortho_matrix(float right, float left, float bottom, float top, float near, float far, matrix result)
{
// First Column
result[0] = 2.0 / (right - left);
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
// Second Column
result[4] = 0.0;
result[5] = 2.0 / (top - bottom);
result[6] = 0.0;
result[7] = 0.0;
// Third Column
result[8] = 0.0;
result[9] = 0.0;
result[10] = -2.0 / (far - near);
result[11] = 0.0;
// Fourth Column
result[12] = -(right + left) / (right - left);
result[13] = -(top + bottom) / (top - bottom);
result[14] = -(far + near) / (far - near);
result[15] = 1;
}
Setting my projection matrix to ortho, where aspect_ratio = screen_width/screen_heigth
ortho_matrix(-aspect_ratio, aspect_ratio, -1.0, 1.0, -1.0, 1.0, PROJECTION_MATRIX);
Task is to change ortho projection to perspective, so i write function for this
UPD: changed to col-major
void frustum_matrix(float right, float left, float bottom, float top, float near, float far, matrix result)
{
// First Column
result[0] = 2 * near / (right - left);
result[1] = 0.0;
result[2] = 0.0;
result[3] = 0.0;
// Second Column
result[4] = 0.0;
result[5] = 2 * near / (top - bottom);
result[6] = 0.0;
result[7] = 0.0;
// Third Column
result[8] = (right + left) / (right - left);
result[9] = (top + bottom) / (top - bottom);
result[10] = -(far + near) / (far - near);
result[11] = -1;
// Fourth Column
result[12] = 0.0;
result[13] = 0.0;
result[14] = -(2 * far * near) / (far - near);
result[15] = 0.0;
}
Setting my projection to frustum matrix, where aspect_ratio = screen_width/screen_heigth
frustum_matrix(-aspect_ratio, aspect_ratio, -1.0, 1.0, 0.1, 1.0, PROJECTION_MATRIX);
Well i peek matrix at glFrustrum page http://www.opengl.org/sdk/docs/man/xhtml/glFrustum.xml, but matrix for ortho func is from same source and works fine. Anyway i see similiar frustum matrix at various places like https://stackoverflow.com/a/5812983/1039175 frustum function.
All what i got is blank screen, viewport and other stuff related to drawning is set right.
It looks like your matrix indices are transposed from glFrustum's doc page. Do you transpose the matrix before uploading it? OpenGL typically refers to column vector matrices, so if you're copying the equations from glFrustum, the indices should look like this:
[0] [4] [ 8] [12]
[1] [5] [ 9] [13]
[2] [6] [10] [14]
[3] [7] [11] [15]
I have to admit that I'm too lazy to read your code, but... assuming your clear color is set to white, it could be that you didn't set the viewport :
Make sure you call this at least once before rendering:
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
GLsizei width = viewport[2];
GLsizei height = viewport[3];
glViewport(0, 0, width, height);
As for some general advice: don't try to reinvent the wheel with rewriting the matrix code (unless perhaps for some academic purpose). If you consider switching to c++ it's worth checking out the glm library : http://glm.g-truc.net/
It has replacements for exactly those matrix functions you are trying to implement and then some... I use it myself and it's a fantastic math lib to work with as it is specifically aimed towards opengl-es 2.0 and glsl.
#include <GL/glut.h>
#include <GL/gl.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define N 200
typedef struct vertex{
float x; // x position of the point
float y; // y position of the point
float r; // red color component of the point
float g; // green color component of the point
float b; // blue color component of the point
char isVisited;
}Vertex;
Vertex *borderLines,*interPolationLines;
int vertex_Count;// total vertex
int counter;//counts matched y coordinates
FILE *f,*g;
void readTotalVertexCount(){
if((f = fopen("vertex.txt","r"))==NULL){
printf("File could not been read\n");
return ;
}
fscanf(f,"%d",&vertex_Count);
/*if((g = fopen("points.txt","w"))==NULL){
return ;
}*/
}
void readVertexCoordinatesFromFile(){
Vertex v[vertex_Count];
borderLines = (Vertex *)calloc(N*vertex_Count,sizeof(Vertex));
interPolationLines = (Vertex *)calloc(N*N*(vertex_Count-1),sizeof(Vertex));
int i = 0;int j;
//read vertexes from file
while(i<vertex_Count){
fscanf(f,"%f",&(v[i].x));
fscanf(f,"%f",&(v[i].y));
fscanf(f,"%f",&(v[i].r));
fscanf(f,"%f",&(v[i].g));
fscanf(f,"%f",&(v[i].b));
//printf("%f %f \n",v[i].x,v[i].y);
i++;
}
Vertex *borderLine,*temp;
float k,landa;
// draw border line actually I am doing 1D Interpolation with coordinates of my vertexes
for (i = 0;i < vertex_Count;i++){
int m = i+1;
if(m==vertex_Count)
m = 0;
borderLine = borderLines + i*N;
for(j = 0;j < N; j++){
k = (float)j/(N - 1);
temp = borderLine + j;
landa = 1-k;
//finding 1D interpolation coord. actually they are borders of my convex polygon
temp->x = v[i].x*landa + v[m].x*k;
temp->y = v[i].y*landa + v[m].y*k;
temp->r = v[i].r*landa + v[m].r*k;
temp->g = v[i].g*landa + v[m].g*k;
temp->b = v[i].b*landa + v[m].b*k;
temp->isVisited = 'n'; // I didn't visit this point yet
//fprintf(g,"%f %f %f %f %f\n",temp->x,temp->y,temp->r,temp->g,temp->b);
}
}
/* here is actual place I am doing 2D Interpolation
I am traversing along the border of the convex polygon and finding the points have the same y coordinates
Between those two points have same y coord. I am doing 1D Interpolation*/
int a;counter = 0;
Vertex *searcherBorder,*wantedBorder,*interPolationLine;
int start = N*(vertex_Count); int finish = N*vertex_Count;
for(i = 0;i< start ;i++){
searcherBorder = i + borderLines;
for(j = i - i%N + N +1; j< finish; j++){
wantedBorder = j + borderLines;
if((searcherBorder->y)==(wantedBorder->y) && searcherBorder->isVisited=='n' && wantedBorder->isVisited=='n'){
//these points have been visited
searcherBorder->isVisited = 'y';
wantedBorder->isVisited = 'y';
interPolationLine = interPolationLines + counter*N;
//counter variable counts the points have same y coordinates.
counter++;
//printf("%d %d %d\n",i,j,counter);
//same as 1D ınterpolation
for(a= 0;a< N;a++){
k = (float)a/(N - 1);
temp = interPolationLine + a;
landa = 1-k;
temp->x = (wantedBorder->x)*landa + (searcherBorder->x)*k;
temp->y = (wantedBorder->y)*landa + (searcherBorder->y)*k;
temp->r = (wantedBorder->r)*landa + (searcherBorder->r)*k;
temp->g = (wantedBorder->g)*landa + (searcherBorder->g)*k;
/*if(temp->x==temp->y)
printf("%f %f \n",wantedBorder->x,searcherBorder->x);*/
temp->b = (wantedBorder->b)*landa + (searcherBorder->b)*k;
}
}
}
}
fclose(f);
}
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,1.0,1.0);
int i,j;
Vertex *interPol,*temp;
glBegin (GL_POINTS);
for(i = 0;i< counter;i++){
interPol = interPolationLines + i*N;
for(j = 0;j< N;j++){
temp = interPol + j;
glColor3f((temp)->r,(temp)->g,(temp)->b);
//fprintf(g,"%f %f \n",(temp)->x,(temp)->y);
glVertex2f ((temp)->x,(temp)->y);
}
}
//printf("%d\n",counter);
fclose(g);
glEnd ();
glFlush();
}
void init(void){
glutInitDisplayMode( GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(900,500);
glutInitWindowPosition(200,100);
glutCreateWindow("2D InterPolation");
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
}
int main(int argc, char** argv)
{
readTotalVertexCount();
readVertexCoordinatesFromFile();
glutInit(&argc,argv);
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
I am implementing 2D Interpolation of a convex polygon and my code does not care about concav.my code works for some convex polygons but for others fail.For those my code fails it does not draw middle of the polygon.it only draws an upper and lower triangle.it reads vertexes from file vertex.txt and its format:x co,y co,red,green,blue color info of that point like below and for the values below my code fails.Thanks for replies in advance.I will get mad.
7
0.9 0.4 1.0 0.0 1.0
0.8 0.2 1.0 0.0 1.0
0.5 0.1 1.0 0.0 0.0
0.3 0.3 0.0 0.0 1.0
0.3 0.35 0.0 0.0 1.0
0.4 0.4 0.0 1.0 0.0
0.6 0.5 1.0 1.0 1.0
Without fully debugging your program, I'm suspicious of the line that says, for(j = i - i%N + N +1; j< finish; j++){. I don't know exactly what you're intending to do, but it just looks suspicious. Furthermore, I would recommend a different algorithm:
Trace around the polygon
Mark any edges that span the desired y-value
Corner cases aside, there's only a solution if you find exactly two hits.
Calculate the intersection of the edges with the y-value
Perform the x-interpolation
Also, concise questions are better than, "Why doesn't my program work?" Forgive me but it feels like a homework problem.
Note: Should this be a comment instead of an answer? I'm new here...