I'm not sure if this belongs here or in graphichs progamming.....I am getting a really annoying access violation reading error and I can't figure out why. What I am trying to do is to refactor a keyframing function (calculate the mid position between two vertices positions). This function compiles and works fine
glBegin(GL_TRIANGLES);
for(int i = 0; i < numTriangles; i++) {
MD2Triangle* triangle = triangles + i;
for(int j = 0; j < 3; j++) {
MD2Vertex* v1 = frame1->vertices + triangle->vertices[j];
MD2Vertex* v2 = frame2->vertices + triangle->vertices[j];
Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;
Vec3f normal = v1->normal * (1 - frac) + v2->normal * frac;
if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) {
normal = Vec3f(0, 0, 1);
}
glNormal3f(normal[0], normal[1], normal[2]);
MD2TexCoord* texCoord = texCoords + triangle->texCoords[j];
glTexCoord2f(texCoord->texCoordX, texCoord->texCoordY);
glVertex3f(pos[0], pos[1], pos[2]);
}
}
glEnd();
Here the function calculates the positions and draws them. What I'd like to do is to calculate all positions before hand, store them in a Vertex array and then draw them.
If I try and remove it and replace this bloc in the exact same part of the program with the following
int vCount = 0;
for(int i = 0; i < numTriangles; i++) {
MD2Triangle* triangle = triangles + i;
for(int j = 0; j < 3; j++) {
MD2Vertex* v1 = frame1->vertices + triangle->vertices[j];
MD2Vertex* v2 = frame2->vertices + triangle->vertices[j];
Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;
Vec3f normal = v1->normal * (1 - frac) + v2->normal * frac;
if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) {
normal = Vec3f(0, 0, 1);
}
indices[vCount] = normal[0];
vCount++;
indices[vCount] = normal[1];
vCount++;
indices[vCount] = normal[2];
vCount++;
MD2TexCoord* texCoord = texCoords + triangle->texCoords[j];
indices[vCount] = texCoord->texCoordX;
vCount++;
indices[vCount] = texCoord->texCoordY;
vCount++;
indices[vCount] = pos[0];
vCount++;
indices[vCount] = pos[1];
vCount++;
indices[vCount] = pos[2];
vCount++;
}
}
I get access violation error "Unhandled exception at 0x01455626 in Graphics_template_1.exe: 0xC0000005: Access violation reading location 0xed5243c0" pointing at line 7
Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;
where the two Vs seems to have no value in the debugger.... Till this point the function behaves in exactly the same way as the one above, I don't understand why this happens?
EDIT ------------------------------------------------------------------------------------
Thank you Werner for spotting that the issue was the array initialization! As per your advice I refactored the function using std:vector containers and made the drawing use glDrawArrays instead of immediate mode.... But instead of an improvement in performance the framerate is a lot lower than before! Am I using this function right/efficiently? This is the refactored draw function:
for(int i = 0; i < numTriangles; i++) {
MD2Triangle* triangle = triangles + i;
for(int j = 0; j < 3; j++) {
MD2Vertex* v1 = frame1->vertices + triangle->vertices[j];
MD2Vertex* v2 = frame2->vertices + triangle->vertices[j];
Vec3f pos = v1->pos * (1 - frac) + v2->pos * frac;
Vec3f normal = v1->normal * (1 - frac) + v2->normal * frac;
if (normal[0] == 0 && normal[1] == 0 && normal[2] == 0) {
normal = Vec3f(0, 0, 1);
}
normals.push_back(normal[0]);
normals.push_back(normal[1]);
normals.push_back(normal[2]);
MD2TexCoord* texCoord = texCoords + triangle->texCoords[j];
textCoords.push_back(texCoord->texCoordX);
textCoords.push_back(texCoord->texCoordY);
vertices.push_back(pos[0]);
vertices.push_back(pos[1]);
vertices.push_back(pos[2]);
}
}
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, 0, &normals[0]);
glTexCoordPointer(2, GL_FLOAT, 0, &textCoords[0]);
glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
glDrawArrays(GL_TRIANGLES, 0, vertices.size()/3);
glDisableClientState(GL_VERTEX_ARRAY); // disable vertex arrays
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
vertices.clear();
textCoords.clear();
normals.clear();
Is there something extra that I am doing here? Cos this is really meant to be more efficient that glBegin()/End(), right?
Thanks for your time and help!
OK, let's make it an answer. The guess was:
Does it crash when you do not write to indices? Did you check that you
are not writing past the end of indices (overwriting your other data
structs)?
Your reply wass, that you create an array GLfloat indices[] since you do not know the array size in advance.
The best (performing) solution would be to calculate the array size in advance and create the array approriately.
GLfloat *indices = new GLfloat[calculated_number_of_elements];
...use array...;
delete [] indices;
Better yet you can create a std::vector:
std::vector<GLfloat> indices(calculated_number_of_elements);
The vector also has the advantage that it can be resized dynamically.
Related
I have a depth map as 2D double array 480x640. I visualize it using openGL using glBegin(GL_TRIANGLES).
This is my code, it works correctly:
int main(int argc, char** argv){
ifstream ifs("D:\\DepthMaps1-20\\DepthMap_1.dat", std::ios::binary);
if (ifs) {
double dheight, dwidth;
ifs.read(reinterpret_cast<char*>(&dheight), sizeof dheight);
ifs.read(reinterpret_cast<char*>(&dwidth), sizeof dwidth);
height = static_cast<size_t>(dheight);
width = static_cast<size_t>(dwidth);
vector<vector<double>> dmap(height, vector<double>(width));
for (auto& row : dmap) {
for (double& col : row)
ifs.read(reinterpret_cast<char*>(&col), sizeof col);
}
double fx = 525.0;
double fy = 525.0; // default focal length
double cx = 319.5;
double cy = 239.5; // default optical center
vector<vector<double>> x(height, vector<double>(width));
vector<vector<double>> y(height, vector<double>(width));
vector<vector<double>> z(height, vector<double>(width));
for (unsigned i = 0; i < dmap.size(); i++)
{
for (unsigned j = 0; j < dmap[i].size(); j++)
{
z[i][j] = dmap[i][j] / 500.0;
x[i][j] = (j - cx) * z[i][j] / fx;
y[i][j] = (i - cy) * z[i][j] / fy;
}
}
GLFWwindow * window;
if (!glfwInit())
return -1;
window = glfwCreateWindow(640, 640, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, keyCallback);
while (!glfwWindowShouldClose(window))
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glBegin(GL_TRIANGLES);
glColor3f(189.0/255.0, 140.0 / 255.0, 194.0 / 255.0);
for (unsigned i = 0; i < dmap.size(); i++)
{
for (unsigned j = 0; j < dmap[i].size(); j++)
{
if (j < dmap[i].size() - 2 && i < dmap.size() - 2)
{
if (z[i][j] != 0 && z[i][j + 1] != 0 && z[i + 1][j] != 0 && z[i + 1][j+1] != 0)
{
glVertex3d(x[i][j], y[i][j], z[i][j]);
glVertex3d(x[i][j + 1], y[i][j + 1], z[i][j + 1]);
glVertex3d(x[i + 1][j], y[i + 1][j], z[i + 1][j]);
glVertex3d(x[i][j+1], y[i][j+1], z[i][j+1]);
glVertex3d(x[i + 1][j + 1], y[i + 1][j + 1], z[i + 1][j + 1]);
glVertex3d(x[i + 1][j], y[i + 1][j], z[i + 1][j]);
}
}
}
}
glEnd();
glFlush();
glfwSwapBuffers(window);
glfwPollEvents();
}
ifs.close();
}
return 0;}
So now I need to add lighting using mathematical formulas for reflection model. Idea is - lighting is taken as parallel (unidirectional) beams of the same intensity, the size of the light source is not limited. Illumination is set by the direction L [Lx Ly Lz].
This is my code for Lambert reflection model and it works, but I want better result.
float coord = -1.0f;
float coord1 = -1.0f;
float coord2 = -0.0f;
float coord4 = -1.0f;
float coord5 = -2.0f;
float coord6 = -1.0f;
int main(int argc, char** argv)
{
ifstream ifs("D:\\DepthMaps1-20\\DepthMap_1.dat", std::ios::binary);
if (ifs) {
double dheight, dwidth;
ifs.read(reinterpret_cast<char*>(&dheight), sizeof dheight);
ifs.read(reinterpret_cast<char*>(&dwidth), sizeof dwidth);
height = static_cast<size_t>(dheight);
width = static_cast<size_t>(dwidth);
vector<vector<double>> dmap(height, vector<double>(width));
for (auto& row : dmap) {
for (double& col : row)
ifs.read(reinterpret_cast<char*>(&col), sizeof col);
}
double fx = 525.0;
double fy = 525.0; // default focal length
double cx = 319.5;
double cy = 239.5; // default optical center
vector<vector<double>> x(height, vector<double>(width));
vector<vector<double>> y(height, vector<double>(width));
vector<vector<double>> z(height, vector<double>(width));
vector<vector<int>> brightness(height, vector<int>(width));
for (unsigned i = 0; i < dmap.size(); i++)
{
for (unsigned j = 0; j < dmap[i].size(); j++)
{
z[i][j] = dmap[i][j] / 500.0;
x[i][j] = (j - cx) * z[i][j] / fx;
y[i][j] = (i - cy) * z[i][j] / fy;
}
}
GLFWwindow * window;
if (!glfwInit())
return -1;
window = glfwCreateWindow(640, 640, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetKeyCallback(window, keyCallback);
while (!glfwWindowShouldClose(window))
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef(tippangle, 1, 0, 0);
glRotatef(viewangle, 0, 1, 0);
glScalef(scaleF, scaleF, scaleF);
//x
glRasterPos3f(1.1, 0.0, 0.0);
//y
glRasterPos3f(0.0, 1.1, 0.0);
//z
glRasterPos3f(0.0, 0.0, 1.1);
glTranslatef(d[0], d[1], d[2]);
glBegin(GL_TRIANGLES);
for (unsigned i = 0; i < dmap.size(); i++)
{
for (unsigned j = 0; j < dmap[i].size(); j++)
{
if (j < dmap[i].size() - 2 && i < dmap.size() - 2)
{
if (z[i][j] != 0 && z[i][j + 1] != 0 && z[i + 1][j] != 0 && z[i + 1][j + 1] != 0)
{
//Determination of the normal
glm::vec3 left = glm::vec3(0, 1, (z[i][j + 1] - z[i][j+1]));
glm::vec3 right = glm::vec3(1, 0, (z[i + 1][j] - z[i + 1][j]));
glm::vec3 normal = glm::normalize(glm::cross(left, right));
glm::vec3 Position_Light = glm::vec3(coord + 0, coord1+ 0, coord2 + 0); //Light source
glm::vec3 Position_View = glm::vec3(coord4, coord5, coord6); //observer
glm::vec3 Position_Point = glm::vec3(x[i][j], y[i][j], z[i][j]);
//Directions
glm::vec3 Light_Direction = glm::normalize(Position_Light - Position_Point); //To source
glm::vec3 View_Direction = glm::normalize(Position_View - Position_Point); // To the observer
glm::vec3 HalfWay_Direction = glm::normalize(Light_Direction + View_Direction); //Median vector (halfway)
double kd = 1;//diffuse reflectance for the Lambert model
double I = 0; //variable brightness
I = kd * glm::dot(Light_Direction, normal);
glColor3f(I, I, I);
glVertex3d(x[i][j], y[i][j], z[i][j]);
glVertex3d(x[i][j + 1], y[i][j + 1], z[i][j + 1]);
glVertex3d(x[i + 1][j], y[i + 1][j], z[i + 1][j]);
glVertex3d(x[i][j+1], y[i][j+1], z[i][j+1]);
glVertex3d(x[i + 1][j + 1], y[i + 1][j + 1], z[i + 1][j + 1]);
glVertex3d(x[i + 1][j], y[i + 1][j], z[i + 1][j]);
}
}
}
}
glEnd();
glFlush();
glfwSwapBuffers(window);
glfwPollEvents();
}
ifs.close();
}
return 0;
}
This is my result.
And I want this result.
Second result is an example for this work, but using c#. Sourse code here:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
double[,] depth;
int[,] brightness;
bool glConrerolIsLoaded;
float coord = 501.5f;
float coord1 = -17.5f;
float coord2 = -2979.5f;
float coord4 = -73.0f;
float coord5 = 1269.0f;
float coord6 = 413.5f;
int resNum = 0;
private void glControl1_Load(object sender, EventArgs e)
{
glConrerolIsLoaded = true;
GL.ClearColor(Color.Black);
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
glControl1.Invalidate();
panel1.Invalidate();
}
private void numericUpDown2_ValueChanged(object sender, EventArgs e)
{
glControl1.Invalidate();
panel1.Invalidate();
}
private void numericUpDown3_ValueChanged(object sender, EventArgs e)
{
glControl1.Invalidate();
panel1.Invalidate();
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
GL.LoadIdentity();
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.Viewport(0, 0, glControl1.Width, glControl1.Height);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
Matrix4 perspectiveMatrix = Matrix4.CreatePerspectiveFieldOfView(MathHelper.DegreesToRadians(45), glControl1.Width / glControl1.Height, 1.0f, 100.0f);
GL.LoadMatrix(ref perspectiveMatrix);
GL.MatrixMode(MatrixMode.Modelview);
GL.Translate(-25.0, -9.0, -45.0);
GL.Scale(0.04, 0.04, 0.04);
GL.Begin(BeginMode.Points);
for (int i = 0; i < depth.GetLength(0) - 1 ; i++)
{
for (int j = 0; j < depth.GetLength(1) - 1 ; j++)
{
if (depth[i, j] != 0 && depth[i + 1, j] != 0 && /*depth[i + 1, j + 1] != 0 &&*/ depth[i, j + 1] != 0)
{
Vector3 left = new Vector3(0, 1, Convert.ToSingle(depth[i, j + 1]) - Convert.ToSingle(depth[i, j]));
Vector3 right = new Vector3(1, 0, Convert.ToSingle(depth[i + 1, j]) - Convert.ToSingle(depth[i, j]));
Vector3 Normal = Vector3.Normalize(Vector3.Cross(left, right));
Vector3 Position_Light = new Vector3(coord + Convert.ToSingle(numericUpDown1.Value), coord1
+ Convert.ToSingle(numericUpDown2.Value), coord2 + Convert.ToSingle(numericUpDown3.Value));
Vector3 Position_View = new Vector3(coord4, coord5, coord6);
Vector3 Position_Point = new Vector3(i, j, Convert.ToSingle(depth[i, j]));
Vector3 Light_Direction = Vector3.Normalize(Position_Light - Position_Point);
Vector3 View_Direction = Vector3.Normalize(Position_View - Position_Point);
Vector3 HalfWay_Direction = Vector3.Normalize(Light_Direction + View_Direction);
double kd = 1;
double I = 0;
I = kd * Vector3.Dot(Light_Direction, Normal);
GL.Color3(I, I, I);
GL.Vertex3(i, j, depth[i, j]);
}
}
GL.End();
glControl1.SwapBuffers();
}
private void Form1_Load(object sender, EventArgs e)//Считывание карты глубины
{
string path = #"DepthMap_1.dat";
BinaryReader reader = new BinaryReader(File.Open(path, FileMode.Open));
double Height1 = reader.ReadDouble();
double Width1 = reader.ReadDouble();
depth = new double[Convert.ToInt16(Height1), Convert.ToInt16(Width1)];
brightness = new int[Convert.ToInt16(Height1), Convert.ToInt16(Width1)];
for (int i = 0; i < depth.GetLength(0); i++)
{
for (int j = 0; j < depth.GetLength(1); j++)
{
depth[i, j] = reader.ReadDouble();
}
}
reader.BaseStream.Close();
}
private void panel1_Paint(object sender, PaintEventArgs e)
{
}
}
}
So my question is what is incorrect in my code? If it light position could you please help me to fix it.
Color is composed of ambient + diffuse + specular. The specular component will add reflection which I think is what you are expecting. The calculations you are doing for color
I_diffuse = kd * glm::dot(Light_Direction, normal);
is just diffuse component.
So what you need will be
I_total = I_diffuse + I_specular;
You already have I_diffuse and you can get I_specular as below,
vec3 viewDir = normalize(viewPos - pointPos);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 I_specular = specularStrength * spec * Ks;
specularStrength can be used to control the strength of reflection.
Note :
The code you are using looks like in a fixed-function pipeline which is way deprecated. If possible please move it to the programmable pipeline with shaders.
You can follow: https://learnopengl.com/Lighting/Basic-Lighting
I found answer, I made mistake here:
//Determination of the normal
glm::vec3 left = glm::vec3(0, 1, (z[i][j + 1] - z[i][j+1]));
glm::vec3 right = glm::vec3(1, 0, (z[i + 1][j] - z[i + 1][j]));
It should be like this:
//Determination of the normal
glm::vec3 left = glm::vec3(0, 1, (z[i][j + 1] - z[i][j]));
glm::vec3 right = glm::vec3(1, 0, (z[i + 1][j] - z[i][j]));
I am trying to draw a 3D cylinder by LWJGL,
and i am trying to generate the vertices, indices and textCoordinate
and storing them in arrays
, but i am stuck how to calculate the size of the vertices, indices and textCoordinate arrays...etc.
anyone knows how i can do it please:
Here the snippet of the code:
// generate vertices for a cylinder
void buildVerticesSmooth() {
//=====> vertices = new float[]; <========
//=====> normals = new float[]; <========
//=====> texcoords = new float[]; <========
int texCoordsIndex = -1;
int verticesIndex = -1;
int normalsIndex = -1;
int indicesIndex = -1; // get unit circle vectors on XY-plane
float[] unitVertices = getUnitCircleVertices();
// put side vertices to arrays
for (int i = 0; i < 2; ++i) {
float h = -height / 2.0f + i * height; // z value; -h/2 to h/2
float t = 1.0f - i; // vertical tex coord; 1 to 0
for (int j = 0, k = 0; j <= sectors; ++j, k += 3) {
float ux = unitVertices[k];
float uy = unitVertices[k + 1];
float uz = unitVertices[k + 2];
// position vector
vertices[++verticesIndex] = (ux * radius); // vx
vertices[++verticesIndex] = (uy * radius); // vy
vertices[++verticesIndex] = (h); // vz
// normal vector
normals[++normalsIndex] = (ux); // nx
normals[++normalsIndex] = (uy); // ny
normals[++normalsIndex] = (uz); // nz
// texture coordinate
texcoords[++texCoordsIndex] = ((float) j / sectors); // s
texcoords[++texCoordsIndex] = (t); // t
}
}
// the starting index for the base/top surface
//NOTE: it is used for generating indices later
int baseCenterIndex = vertices.length / 3;
int topCenterIndex = baseCenterIndex + sectors + 1; // include center vertex
// put base and top vertices to arrays
for (int i = 0; i < 2; ++i) {
float h = -height / 2.0f + i * height; // z value; -h/2 to h/2
float nz = -1 + i * 2; // z value of normal; -1 to 1
// center point
vertices[++verticesIndex] = 0;
vertices[++verticesIndex] = 0;
vertices[++verticesIndex] = h;
normals[++normalsIndex] = 0;
normals[++normalsIndex] = 0;
normals[++normalsIndex] = nz;
texcoords[++texCoordsIndex] = 0.5f;
texcoords[++texCoordsIndex] = 0.5f;
for (int j = 0, k = 0; j < sectors; ++j, k += 3) {
float ux = unitVertices[k];
float uy = unitVertices[k + 1];
// position vector
vertices[++verticesIndex] = (ux * radius); // vx
vertices[++verticesIndex] = (uy * radius); // vy
vertices[++verticesIndex] = (h); // vz
// normal vector
normals[++normalsIndex] = (0); // nx
normals[++normalsIndex] = (0); // ny
normals[++normalsIndex] = (nz); // nz
// texture coordinate
texcoords[++texCoordsIndex] = (-ux * 0.5f + 0.5f); // s
texcoords[++texCoordsIndex] = (-uy * 0.5f + 0.5f); // t
}
}
int[] indices;
int k1 = 0; // 1st vertex index at base
int k2 = sectors + 1; // 1st vertex index at top
// indices for the side surface
for(int i = 0; i < sectors; ++i, ++k1, ++k2)
{
// 2 triangles per sector
// k1 => k1+1 => k2
indices[++indicesIndex] = (k1);
indices[++indicesIndex] = (k1 + 1);
indices[++indicesIndex] = (k2);
// k2 => k1+1 => k2+1
indices[++indicesIndex] = (k2);
indices[++indicesIndex] = (k1 + 1);
indices[++indicesIndex] = (k2 + 1);
}
// indices for the base surface
// NOTE: baseCenterIndex and topCenterIndices are pre-computed during vertex generation
// please see the previous code snippet
for(int i = 0, k = baseCenterIndex + 1; i < sectors; ++i, ++k)
{
if(i < sectors - 1)
{
indices[++indicesIndex] = (baseCenterIndex);
indices[++indicesIndex] = (k + 1);
indices[++indicesIndex] = (k);
}
else // last triangle
{
indices[++indicesIndex] = (baseCenterIndex);
indices[++indicesIndex] = (baseCenterIndex + 1);
indices[++indicesIndex] = (k);
}
}
// indices for the top surface
for(int i = 0, k = topCenterIndex + 1; i < sectors; ++i, ++k)
{
if(i < sectors - 1)
{
indices[++indicesIndex] = (topCenterIndex);
indices[++indicesIndex] = (k);
indices[++indicesIndex] = (k + 1);
}
else // last triangle
{
indices[++indicesIndex] = (topCenterIndex);
indices[++indicesIndex] = (k);
indices[++indicesIndex] = (topCenterIndex + 1);
}
}
}
As httpdigest said:
you know how many iterations every loop performs and you know how
many increments/additions you do per each array. Should be very simple
math now.
Is there an algorithm that could be used to generate a plane using the GL_TRIANGLES primitive type?
Here's my current function:
Mesh* Mesh::CreateMeshPlane(vec2 bottomleft, ivec2 numvertices, vec2 worldsize){
int numVerts = numvertices.x * numvertices.y;
float xStep = worldsize.x / (numvertices.x - 1);
float yStep = worldsize.y / (numvertices.y - 1);
VertexFormat* verts = new VertexFormat[numVerts];
for (int y = 0; y < numvertices.y; y++)
{
for (int x = 0; x < numvertices.x; x++)
{
verts[x + (y * numvertices.x)].pos.x = bottomleft.x + (xStep * x);
verts[x + (y * numvertices.x)].pos.y = bottomleft.y + (yStep * y);
verts[x + (y * numvertices.x)].pos.z = 0;
}
}
Mesh* pMesh = new Mesh();
pMesh->Init(verts, numVerts, indices, 6, GL_STATIC_DRAW);
glPointSize(10.0f);
pMesh->m_PrimitiveType = GL_POINTS;
delete[] verts;
return pMesh;}
I'm just unsure how to implement indices into the for loop to be able to know which points to draw.
What I think I need to know:
Each square will be made up of 2 triangles, each square requiring 6 indices
Currently I'm drawing from the bottom left
I need to know how many squares I'll have from the numbers passed in
Maybe something like this:
int width = 4;
int length = 6;
int height = 1;
std::vector<float> planeVertices;
for (int x = 0; x < width - 1; x++) {
for (int z = 0; z < length - 1; z++) {
planeVertices.push_back(x);
planeVertices.push_back(height);
planeVertices.push_back(z);
planeVertices.push_back(x);
planeVertices.push_back(height);
planeVertices.push_back(z + 1);
planeVertices.push_back(x + 1);
planeVertices.push_back(height);
planeVertices.push_back(z + 1);
planeVertices.push_back(x);
planeVertices.push_back(height);
planeVertices.push_back(z);
planeVertices.push_back(x + 1);
planeVertices.push_back(height);
planeVertices.push_back(z);
planeVertices.push_back(x + 1);
planeVertices.push_back(height);
planeVertices.push_back(z + 1);
}
}
...
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, planeVertices.size() * sizeof(float), planeVertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), 0);
glEnableVertexAttribArray(0);
...
glDrawArrays(GL_TRIANGLES, 0, (width - 1) * (length - 1) * 6);
This code creates an std::vector<float> and adds the plane vertices to it. The nested for loops add two triangles for every unit of the plane (so with width as 4 and length as 6 the plane will be 4 units by 6 units, and will be made of 6 * 4 * 2 = 48 triangles). The height of the plane is set by the height variable. This only generates flat planes, but a simple transformation lets you rotate and scale this as you need.
WARNING: this code is untested.
Just to close this question here's how I did it:
Mesh* Mesh::CreateMeshPlane(vec3 bottomleft, ivec2 numvertices, vec2
worldsize, vec2 texturerepetition)
{
int numVerts = numvertices.x * numvertices.y;
int numFaces = (numvertices.x - 1) * (numvertices.y - 1);
int numIndices = numFaces * 6;
float xStep = worldsize.x / (numvertices.x - 1);
float yStep = worldsize.y / (numvertices.y - 1);
float zStep = worldsize.y / (numvertices.y - 1);
float uStep = texturerepetition.x / (numvertices.x - 1);
float vStep = texturerepetition.y / (numvertices.y - 1);
VertexFormat* verts = new VertexFormat[numVerts];
unsigned int* indices = new unsigned int[numIndices];
for (int y = 0; y < numvertices.y; y++)
{
for (int x = 0; x < numvertices.x; x++)
{
verts[x + (y * numvertices.x)].pos.x = bottomleft.x + (xStep * x);
verts[x + (y * numvertices.x)].pos.y = bottomleft.y;
verts[x + (y * numvertices.x)].pos.z = bottomleft.z + (zStep * y);
verts[y * numvertices.x + x].uv.x = uStep * x;
verts[y * numvertices.x + x].uv.y = vStep * y;
}
}
int offset = 0;
for (int i = 0; i < numIndices; i++)
{
// The bottom left index of the current face
// + the offset to snap back when we hit the edge
unsigned int cornerIndex = i/6 + offset;
// If we reach the edge we increase the offset so that it goes to the next bottom left
if ((cornerIndex + 1)%numvertices.x == 0)
{
offset++;
cornerIndex++; // Adding new offset to the bottom left
}
// First triangle
indices[i] = (unsigned int)cornerIndex;
i++;
indices[i] = (unsigned int)cornerIndex + numvertices.x;
i++;
indices[i] = (unsigned int)cornerIndex + numvertices.x + 1;
i++;
// Second triangle
indices[i] = (unsigned int)cornerIndex;
i++;
indices[i] = (unsigned int)cornerIndex + numvertices.x + 1;
i++;
indices[i] = (unsigned int)cornerIndex + 1;
}
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
Mesh* pMesh = new Mesh();
pMesh->Init(verts, numVerts, indices, numIndices, GL_STATIC_DRAW);
delete[] verts;
return pMesh;
}
Workflow:
1. Calculating number of faces I need, then the number of indices
2. Creating an offset that is added to the cornerIndex when we realize we hit the edge of the vertex array (by using modulus numvertices.y)
3. Doing simple math to draw corners in correct order based on the cornerIndex
Notes:
1. Im drawing using GL_TRIANGLES as the primitive type
2. Drawing from bottom left to top right
3. cornerIndex therefore is the bottom left of the current square we're drawing on
Hope someone can find this helpful!
I'm trying to make a grid of triangles for a terrain generation project in DirectX 11, but when it gets drawn to the screen it draws in all three axis, instead of just the x and z.
I do get the correct amount of vertices and indices, but in the vector of indices it has a size of 972, the first 486 of them are set to 0 instead of the actual values.
I was wondering if I could get some clarification on whether I was setting the vertex/index buffers correctly.
Below is an example for a 10 by 10 grid.
GenerateTerrain method
void Application::GenerateTerrain(int vertRows, int vertCols)
{
HRESULT hr;
// ------------------------------------- Create Vertex Buffer --------------------------------------
totalCellRows = vertRows - 1;
totalCellCols = vertCols - 1;
// Width and Total Width
float dx = 1.0f;
float totalWidth = totalCellCols * dx;
// Depth and Total Depth
float dz = 1.0f;
float totalDepth = totalCellRows * dz;
// X and Z Offsets
float xOffset = -totalWidth * 0.5f;
float zOffset = totalDepth * 0.5f;
totalVertices = vertRows * vertCols;
totalTriangles = (totalCellRows * totalCellCols) * 2;
totalIndices = totalTriangles * 3;
terrainVertices = new SimpleVertex[totalVertices];
// Array Version
int k = 0;
for (int i = 0; i < vertRows; i++)
{
for (int j = 0; j < vertCols; j++)
{
SimpleVertex newVertex;
terrainVertices[k].PosL = XMFLOAT3(j * dx + xOffset, 0.0f, -(i * dz) + zOffset);
terrainVertices[k].NormL = XMFLOAT3(0.0f, 1.0f, 0.0f);
terrainVertices[k].Tex = XMFLOAT2(0.0f, 0.0f);
k++;
}
}
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(SimpleVertex) * totalVertices;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = &terrainVertices;
hr = _pd3dDevice->CreateBuffer(&bd, &InitData, &_pGridVertexBuffer);
// ------------------------------------- Create Index Buffer --------------------------------------
// Vector Version
indices.resize(totalIndices);
for (WORD i = 0; i < (WORD)vertRows - 1; i++)
{
for (WORD j = 0; j < (WORD)vertCols - 1; j++)
{
indices.push_back(i * vertCols + j);
indices.push_back(i * vertCols + (j + 1));
indices.push_back((i + 1) * vertCols + j);
indices.push_back((i + 1) * vertCols + j);
indices.push_back((i * vertCols + (j + 1)));
indices.push_back((i + 1) * vertCols + (j + 1));
}
}
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof(WORD) * totalIndices;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
ZeroMemory(&InitData, sizeof(InitData));
InitData.pSysMem = &indices;
hr = _pd3dDevice->CreateBuffer(&bd, &InitData, &_pGridIndexBuffer);
}
indices.resize(totalIndices); <----- !!!!!!ERROR!!!! u mean reserve
for (WORD i = 0; i < (WORD)vertRows - 1; i++)
{
for (WORD j = 0; j < (WORD)vertCols - 1; j++)
{
indices.push_back(i * vertCols + j);
indices.push_back(i * vertCols + (j + 1));
indices.push_back((i + 1) * vertCols + j);
indices.push_back((i + 1) * vertCols + j);
indices.push_back((i * vertCols + (j + 1)));
indices.push_back((i + 1) * vertCols + (j + 1));
}
}
You write resize, so the vector is resized, and then you add more indices with pushback. I think you want to reserve memory "reserve" and add them with pushback.
Also i would recommend to use a pointer to the first value, instead of a pointer to the vector
you:
InitData.pSysMem = &indices;
better:
InitData.pSysMem = &indices[0];
Buffer initialization seems to be ok.
Good luck
I am writing a Quad tree structure for a planet, that decreases and in increases in detail when you are far away from the quad and close to it receptively. However, I am running into some really serious, and annoying bugs.
I have two preprocessor defined constant that determines the size of the Quad tree (QUAD_WIDTH and QUAD_HEIGHT) when I change the value to anything but 32 (16 or 64 for example) I get a blue screen of death. I am using code::blocks as my IDE, another thing: Whenever I try to debug the program in code::blocks I also get a blue screen of death (Doesn't matter if the constants are 32 or not)
Why is this the case? And how can I fix it.
PQuad.cpp
#include "..\include\PQuad.h"
#include "..\include\Color3.h"
#include <iostream>
#include <vector>
#include <cmath>
#include <GL/glew.h>
#include <GL/glu.h>
#include <GL/gl.h>
#define QUAD_WIDTH 32
#define QUAD_HEIGHT 32
#define NUM_OF_CHILDREN 4
#define MAX_DEPTH 4
PQuad::PQuad(FaceDirection face_direction, float planet_radius) {
this->built = false;
this->spherised = false;
this->face_direction = face_direction;
this->radius = planet_radius;
this->planet_centre = glm::vec3(0, 0, 0);
}
PQuad::~PQuad() {
}
std::vector<PQuad> PQuad::get_children() {
return children;
}
bool PQuad::get_built() {
return this->built;
}
int PQuad::get_depth() {
return this->depth;
}
float *PQuad::get_table() {
return tree;
}
float PQuad::get_element_width() {
return element_width;
}
glm::vec3 PQuad::get_position() {
return position;
}
glm::vec3 PQuad::get_centre() {
return centre;
}
void PQuad::get_recursive(glm::vec3 player_pos, std::vector<PQuad*>& out_children) {
for (size_t i = 0; i < children.size(); i++) {
children[i].get_recursive(player_pos, out_children);
}
if (this->should_draw(player_pos) ||
this->depth == 0) {
out_children.emplace_back(this);
}
}
GLuint PQuad::get_vertexbuffer() {
return vbo_vertices;
}
GLuint PQuad::get_colorbuffer() {
return vbo_colors;
}
GLuint PQuad::get_normalbuffer() {
return vbo_normals;
}
GLuint PQuad::get_elementbuffer() {
return ibo_elements;
}
void PQuad::set_parent(PQuad *quad) {
this->parent = quad;
}
void PQuad::set_child_index(int child_index) {
this->child_index = child_index;
}
void PQuad::set_depth(int depth) {
this->depth = depth;
}
void PQuad::set_root(bool root) {
this->root = root;
}
void PQuad::calculate_position() {
this->element_width = depth == 0 ? 1.0f : parent->get_element_width() / 2.0f;
float quad_y = child_index / 2 == 0 ? 0 : element_width * QUAD_HEIGHT - element_width;
float quad_x = child_index % 2 == 0 ? 0 : element_width * QUAD_WIDTH - element_width;
if (this->depth != 0) {
quad_x += parent->get_position().x;
quad_y += parent->get_position().y;
}
this->position = glm::vec3(quad_x, quad_y, 0);
}
void PQuad::construct() {
if (!this->built) {
std::vector<glm::vec3> vertices;
std::vector<glm::vec3> normals;
std::vector<Color3> colors;
std::vector<GLushort> elements;
construct_vertices(&vertices, &colors);
construct_elements(&elements);
spherise(&vertices, &normals);
construct_normals(&vertices, &elements, &normals);
construct_buffers(&vertices, &colors, &elements, &normals);
float distance = radius;
if (!spherised) {
distance = QUAD_WIDTH;
}
construct_depth_table(distance);
this->built = true;
}
}
void PQuad::construct_depth_table(float distance) {
tree[0] = -1;
for (int i = 1; i < MAX_DEPTH; i++) {
tree[i] = distance;
distance /= 2.0f;
}
}
void PQuad::construct_children() {
calculate_position();
if (depth < (int)MAX_DEPTH) {
children.reserve((int)NUM_OF_CHILDREN);
for (int i = 0; i < (int)NUM_OF_CHILDREN; i++) {
children.emplace_back(PQuad(this->face_direction, this->radius));
PQuad *child = &children.back();
child->set_depth(depth + 1);
child->set_child_index(i);
child->set_parent(this);
child->construct_children();
}
} else {
leaf = true;
}
}
void PQuad::construct_vertices(std::vector<glm::vec3> *vertices, std::vector<Color3> *colors) {
vertices->reserve(QUAD_WIDTH * QUAD_HEIGHT);
for (int y = 0; y < QUAD_HEIGHT; y++) {
for (int x = 0; x < QUAD_WIDTH; x++) {
switch (face_direction) {
case YIncreasing:
vertices->emplace_back(glm::vec3(position.x + x * element_width, QUAD_HEIGHT - 1, -(position.y + y * element_width)));
break;
case YDecreasing:
vertices->emplace_back(glm::vec3(position.x + x * element_width, 0, -(position.y + y * element_width)));
break;
case XIncreasing:
vertices->emplace_back(glm::vec3(QUAD_WIDTH - 1, position.y + y * element_width, -(position.x + x * element_width)));
break;
case XDecreasing:
vertices->emplace_back(glm::vec3(0, position.y + y * element_width, -(position.x + x * element_width)));
break;
case ZIncreasing:
vertices->emplace_back(glm::vec3(position.x + x * element_width, position.y + y * element_width, 0));
break;
case ZDecreasing:
vertices->emplace_back(glm::vec3(position.x + x * element_width, position.y + y * element_width, -(QUAD_WIDTH - 1)));
break;
}
// Position the bottom, right, front vertex of the cube from being (0,0,0) to (-16, -16, 16)
(*vertices)[vertices->size() - 1] -= glm::vec3(QUAD_WIDTH / 2.0f, QUAD_WIDTH / 2.0f, -(QUAD_WIDTH / 2.0f));
colors->emplace_back(Color3(255.0f, 255.0f, 255.0f, false));
}
}
switch (face_direction) {
case YIncreasing:
this->centre = glm::vec3(position.x + QUAD_WIDTH / 2.0f, QUAD_HEIGHT - 1, -(position.y + QUAD_HEIGHT / 2.0f));
break;
case YDecreasing:
this->centre = glm::vec3(position.x + QUAD_WIDTH / 2.0f, 0, -(position.y + QUAD_HEIGHT / 2));
break;
case XIncreasing:
this->centre = glm::vec3(QUAD_WIDTH - 1, position.y + QUAD_HEIGHT / 2.0f, -(position.x + QUAD_WIDTH / 2.0f));
break;
case XDecreasing:
this->centre = glm::vec3(0, position.y + QUAD_HEIGHT / 2.0f, -(position.x + QUAD_WIDTH / 2.0f));
break;
case ZIncreasing:
this->centre = glm::vec3(position.x + QUAD_WIDTH / 2.0f, position.y + QUAD_HEIGHT / 2.0f, 0);
break;
case ZDecreasing:
this->centre = glm::vec3(position.x + QUAD_WIDTH / 2.0f, position.y + QUAD_HEIGHT / 2.0f, -(QUAD_HEIGHT - 1));
break;
}
this->centre -= glm::vec3(QUAD_WIDTH / 2.0f, QUAD_WIDTH / 2.0f, -(QUAD_WIDTH / 2.0f));
}
void PQuad::construct_elements(std::vector<GLushort> *elements) {
int index = 0;
elements->reserve((QUAD_WIDTH - 1) * (QUAD_HEIGHT - 1) * 6);
for (int y = 0; y < QUAD_HEIGHT - 1; y++) {
for (int x = 0; x < QUAD_WIDTH - 1; x++) {
GLushort bottom_left = x + y * QUAD_WIDTH;
GLushort bottom_right = (x + 1) + y * QUAD_WIDTH;
GLushort top_left = x + (y + 1) * QUAD_WIDTH;
GLushort top_right = (x + 1) + (y + 1) * QUAD_WIDTH;
elements->emplace_back(top_left);
elements->emplace_back(bottom_right);
elements->emplace_back(bottom_left);
elements->emplace_back(top_left);
elements->emplace_back(top_right);
elements->emplace_back(bottom_right);
}
}
}
void PQuad::construct_normals(std::vector<glm::vec3> *vertices, std::vector<GLushort> *elements, std::vector<glm::vec3> *normals) {
normals->reserve(QUAD_WIDTH * QUAD_HEIGHT);
for (int i = 0; i < elements->size() / 3; i++) {
int index1 = elements->at(i * 3);
int index2 = elements->at(i * 3 + 1);
int index3 = elements->at(i * 3 + 2);
glm::vec3 side1 = vertices->at(index1) - vertices->at(index3);
glm::vec3 side2 = vertices->at(index1) - vertices->at(index2);
glm::vec3 normal = glm::cross(side1, side2);
normal = glm::normalize(normal);
normals->emplace_back(normal);
normals->emplace_back(normal);
normals->emplace_back(normal);
}
}
void PQuad::spherise(std::vector<glm::vec3> *vertices, std::vector<glm::vec3> *normals) {
for (int i = 0; i < QUAD_WIDTH * QUAD_HEIGHT; i++) {
glm::vec3 normal = glm::normalize(vertices->at(i) - planet_centre);
(*vertices)[i] = (float)(radius) * normal;
}
glm::vec3 normal = glm::normalize(centre - planet_centre);
centre = normal * (float)(radius);
this->spherised = true;
}
void PQuad::construct_buffers(std::vector<glm::vec3> *vertices, std::vector<Color3> *colors, std::vector<GLushort> *elements, std::vector<glm::vec3> *normals) {
glGenBuffers(1, &vbo_vertices);
glBindBuffer(GL_ARRAY_BUFFER, vbo_vertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices->size(), &((*vertices)[0]), GL_STATIC_DRAW);
glGenBuffers(1, &vbo_colors);
glBindBuffer(GL_ARRAY_BUFFER, vbo_colors);
glBufferData(GL_ARRAY_BUFFER, sizeof(Color3) * colors->size(), &((*colors)[0]), GL_STATIC_DRAW);
glGenBuffers(1, &vbo_normals);
glBindBuffer(GL_ARRAY_BUFFER, vbo_normals);
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * normals->size(), &((*normals)[0]), GL_STATIC_DRAW);
glGenBuffers(1, &ibo_elements);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_elements);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * elements->size(), &((*elements)[0]), GL_STATIC_DRAW);
}
float distance3(glm::vec3 v1, glm::vec3 v2) {
return sqrt(pow(abs(v1.x - v2.x), 2) + pow(abs(v1.y - v2.y), 2) + pow(abs(v1.z - v2.z), 2));
}
bool PQuad::should_draw(glm::vec3 player_position) {
float distance = distance3(player_position, centre);
if (distance < tree[depth]) {
return true;
}
return false;
}
A blue screen of death should be just impossible to reach from a regular user space program... no matter what you do.
However unfortunately it's easy to bump into this kind of system level bug when writing software that interacts heavily with device drivers because they are software too, and they are not bug free (and a bug in a device driver can take down the whole system with a BSOD).
The meaning is that you are making some call to OpenGL with wrong parameters, and that the driver of your video card has a bug and instead of detecting the problem and returning a failure code, it just takes down the machine.
You may try to use a log of the operations, writing to a file each single step so after you get a BSOD and reboot you can check what was the last command written to the file. Note that you should open the file in append, write the log line and then close the file. Not even this gives you a 100% guarantee the content of the file will have been written really to the disk when you get the BSOD, but IMO in this case the probability should be high. A better alternative would be just sending log messages over the serial line or using the network to another computer.
It may be a difficult problem to track and solve.
Another option would be using a different OpenGL implementation (like Mesa). May be with another implementation calls are checked better and you can spot what is the call with wrong parameters.
It could even be that your code is just triggering a bug in the video driver and your code is not doing anything wrong. This should be your last thought however.
Actually the answer is quite simple. There is something really wrong with the debugger in Code::Blocks on Windows. I have seen it blue screen multiple systems. Switch to using output statements or another IDE.