this is the code I use to create and draw an ellipsoid with OpenGL with shader
const float _2pi = 2.0f * M_PI;
std::vector<glm::vec3> positions;
std::vector<glm::vec3> normals;
std::vector<glm::vec2> textureCoords;
for(int i = 0; i <= stacks; ++i) {
// V texture coordinate
float V = i / (float)stacks;
float phi = V * M_PI;
for( int j = 0; j <= slices; ++j) {
// U texture coordinate
float U = j / (float)slices;
float theta = U * _2pi;
float X = a * cos(theta) * cos(phi);
float Y = b * cos(theta) * sin(phi);
float Z = c * sin(theta);
positions.push_back( glm::vec3( X, Y, Z) );
normals.push_back( glm::vec3(X, Y, Z) );
textureCoords.push_back( glm::vec2(U, V) );
}
}
// Now generate the index buffer
std::vector<GLuint> indicies;
for(int i=0; i <slices*stacks+slices; ++i) {
indicies.push_back(i);
indicies.push_back(i + slices + 1);
indicies.push_back(i + slices);
indicies.push_back(i + slices + 1);
indicies.push_back(i);
indicies.push_back(i + 1);
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(4, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(glm::vec3), positions.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_TRUE, 0, nullptr);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, textureCoords.size() * sizeof(glm::vec2), textureCoords.data(), GL_STATIC_DRAW);
glVertexAttribPointer(8, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(8);
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
glBufferData( GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(GLuint), indicies.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
while this is the code that I use to render it:
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
if(style == glObject::STYLE::WIREFRAME) glDrawElements(GL_LINES, (slices * stacks + slices) * 6, GL_UNSIGNED_INT, nullptr);
if(style == glObject::STYLE::SOLID) glDrawElements(GL_TRIANGLES, (slices * stacks + slices) * 6, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
It seems to work but I have some issue.
Looking the image it is possible to see some vertex in the wrong position.
I think that is something related to the indicies but I'm not sure.
I have notice that depends by the number of stacks or slices that I use
UPDATE:
I take into account the suggestion of #Rabbid76 and this is the result.
No more degenerated vertex and triangles in the rendering.
However the rendering is not equal to the one of #Rabbid76 there is like a rotation of the vertex.
FINAL:
This is the creation vertex and indices code:
std::vector<glm::vec3> positions;
std::vector<glm::vec3> normals;
std::vector<glm::vec2> textureCoords;
for(int i = 0; i <= stacks; ++i) {
// V texture coordinate.
float V = i / (float)stacks;
float phi = V * M_PI;
for( int j = 0; j <= slices; ++j) {
// U texture coordinate.
float U = j / (float)slices;
float theta = U * 2.0f * M_PI;
float X = cos(theta) * sin(phi);
float Y = cos(phi);
float Z = sin(theta) * sin(phi);
positions.push_back( glm::vec3( X, Y, Z) * radius );
normals.push_back( glm::vec3(X, Y, Z) );
textureCoords.push_back( glm::vec2(U, V) );
}
}
// Now generate the index buffer
std::vector<GLuint> indicies;
int noPerSlice = slices + 1;
for(int i=0; i < stacks; ++i) {
for (int j=0; j < slices; ++j) {
int start_i = (i * noPerSlice) + j;
indicies.push_back( start_i );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i + noPerSlice );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i );
indicies.push_back( start_i + 1 );
}
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(4, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(glm::vec3), positions.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_TRUE, 0, nullptr);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, textureCoords.size() * sizeof(glm::vec2), textureCoords.data(), GL_STATIC_DRAW);
glVertexAttribPointer(8, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(8);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(GLuint), indicies.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
This is the rendering one:
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
if(style == glObject::STYLE::WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
if(style == glObject::STYLE::SOLID) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDrawElements(GL_TRIANGLES, (slices * stacks + slices) * 6, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
You have confused phi and theta. theta is the angle of the points around the circumference of a slice in range [0, 2*PI]. phi is the angle of the points form the south to the north in range [-PI, PI]:
for (int i = 0; i <= stacks; ++i) {
// V texture coordinate
float V = i / (float)stacks;
float phi = V * M_PI - M_PI/2.0;
for ( int j = 0; j <= slices; ++j) {
// U texture coordinate
float U = j / (float)slices;
float theta = U * _2pi;
float X = a * cos(phi) * cos(theta);
float Y = b * cos(phi) * sin(theta);
float Z = c * sin(phi);
positions.push_back( glm::vec3( X, Y, Z) );
normals.push_back( glm::vec3(X, Y, Z) );
textureCoords.push_back( glm::vec2(U, V) );
}
}
The number of points of a slice (around the circumference) is noPerSlice = slices + 1. The first index of a point of a quad is start_i = (i * noPerSlice) + j, where i is the index of the stack and j the index around the slice. Create slices quads around the circumference and stacks slices form the south to the north:
int noPerSlice = slices + 1;
for(int i=0; i < stacks; ++i) {
for (int j = 0; j < slices; ++j) {
int start_i = (i * noPerSlice) + j;
indicies.push_back( start_i );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i + noPerSlice );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i );
indicies.push_back( start_i + 1 );
}
}
i think
slices*stacks+slices
should be
slices*stacks+stacks
the +stacks is for the extra quads from the duplicate vertex in every stack
although this fixes the number of indices, you still have degenerate triangles along the duplicate vertices where theta equals zero
Related
I am using glBufferSubData to change positions of vertices.
Everything works fine, when I call the code below once.
If I run this whole code two times to add two pointclouds the vertex positions is updated only for the last geometry.
Please look at only following methods of the class, because the rest of the code is just a constructor to initialize the clouds:
void opengl_init()
void opengl_draw()
I think something is wrong with winding to the vao buffer.
Question:
How can I correctly update vertex positions glBufferSubData so that both pointclouds would move?
class pointcloud {
public:
int id = 0;
std::vector<vertex> vertices;
std::vector<unsigned int> indices;//pairs
unsigned int vao, vbo, ibo;
//individual polylines
pointcloud(const std::vector<float>& coord, const std::vector<float>& colors)//, std::vector<Texture> textures
{
vertices.reserve(coord.size());
indices.reserve((coord.size() - 1) * 2);
for (int i = 0; i < coord.size(); i += 3) {
vertex vertex;
vertex.position = glm::vec3(coord[i + 0], coord[i + 1], coord[i + 2]);
vertex.color = glm::vec3(colors[i + 0], colors[i + 1], colors[i + 2]);
vertices.emplace_back(vertex);
}
for (int i = 0; i < (coord.size() / 3) - 1; i++) {
indices.emplace_back(i + 0);
indices.emplace_back(i + 1);
}
// now that we have all the required data, set the vertex buffers and its attribute pointers.
//setup_polyline();
}
//merged polylines
pointcloud(const std::vector<std::vector<float>>& coord, const std::vector<std::vector<float>>& colors)//, std::vector<Texture> textures
{
//reserve memory
int v_count = 0;
int i_count = 0;
for (int i = 0; i < coord.size(); i++) {
v_count += coord[i].size();
i_count += coord[i].size() - 1;
}
vertices.reserve(v_count);
indices.reserve(i_count);
//fill vertics and indices lists
for (int i = 0; i < coord.size(); i++) {
for (int j = 0; j < coord[i].size(); j += 3) {
vertex vertex;
vertex.position = glm::vec3(coord[i][j + 0], coord[i][j + 1], coord[i][j + 2]);
vertex.color = glm::vec3(colors[i][j + 0], colors[i][j + 1], colors[i][j + 2]);
vertices.emplace_back(vertex);
}
}
v_count = 0;
for (int i = 0; i < coord.size(); i++) {
for (int j = 0; j < (coord[i].size() / 3) - 1; j++) {
//std::cout << v_count + j + 0 << " " << v_count + j + 1 << std::endl;
indices.emplace_back(v_count + j + 0);
indices.emplace_back(v_count + j + 1);
}
v_count += (coord[i].size() / 3);
}
//std::cout << vertices.size() << std::endl;
// now that we have all the required data, set the vertex buffers and its attribute pointers.
//setup_polyline();
}
//// initializes all the buffer objects/arrays
void opengl_init(bool draw_dynamic = true, int _id = 0)
{
id = _id + 1;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// init vertex-array and vertex-array-buffer
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//vertex array
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
//bind vertex-array-buffer to the vertex-array
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//declare array with data or empty array depending how data will be displayed
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
auto type = !draw_dynamic ? GL_STATIC_DRAW : GL_STREAM_DRAW;
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex), &vertices[0], type); // target | size | data (poinnting to first element e.g. glm::value_ptr(vertices[0])) | usage
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// set attributes that corresponds to layout id in the vertex shader
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// vertex Positions
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)0);
// vertex normals
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (void*)offsetof(vertex, color));
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//bind buffers vao | vbo | ibo
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//glBindVertexArray(0);
}
// render the mesh
void opengl_draw(opengl_shaders::shader& shader, bool draw_dynamic = true)
{
//update
//https://learnopengl.com/Advanced-OpenGL/Advanced-Data
if (draw_dynamic) {
for (auto& v : vertices)
v.position.y += 0.001;
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(vertex), &vertices[0]);
}
//draw
glBindVertexArray(vao);
glDrawArrays(GL_POINTS, 0, vertices.size());
//glBindVertexArray(0);
}
void opengl_clear(opengl_shaders::shader& shader) {
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
shader.delete_shader();
}
};
glBufferSubData updates a subset of the data store of a buffer object that is currently bound to the specified target. You must bind the buffer before you can modify its data:
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.size() * sizeof(vertex), &vertices[0]);
The GL_ARRAY_BUFFER binding is a global state. This binding is maintained until it is changed. As for your code it works for 1 pointcloud, but it doesn't work if you have more than 1 pointcloud and vertex buffer.
I'm trying to center a square texture on a circle using openGL, I have created a loop that fills an array with my circle coordinates, followed by my +/-normals for lighting, finally followed by my (x,y) for the texture coordinates.
For some reason the image ends up kind of smooshed instead of evenly spreading out around the circle. I'm ot sure if my calculations for the polar to cartesian coordinates are a little off or what.
Below is a section of the code as well as an image of the output.
{
/*FIX STILL NEEDED TO DYNAMICALLY UPDATE THESE VALUES*/
//When changing numberOfSides need to also update indices[] to numberOfSides*3 and allCircleVertices[] to numberOfVertices*numberOfSides
GLfloat x = 0;
GLfloat y = 0;
GLfloat z = 0;
GLfloat radius = 4;
GLuint numberOfSides = 20;
GLuint numberOfVertices = numberOfSides + 1;
GLuint k = 22;
GLuint angle = 360 / numberOfSides;
GLushort indices[60];
GLfloat doublePi = 2.0f * M_PI;
GLfloat* circleVerticesX = new GLfloat[numberOfVertices];
GLfloat* circleVerticesY = new GLfloat[numberOfVertices];
GLfloat* circleVerticesZ = new GLfloat[numberOfVertices];
GLfloat allCircleVertices[420]; /*= new GLfloat[numberOfVertices * numberOfSides];*/
circleVerticesX[0] = x;
circleVerticesY[0] = y;
circleVerticesZ[0] = z;
//Loop to determine angles between vertices
for (int i = 1; i < numberOfVertices; i++)
{
circleVerticesX[i] = x + (radius * cos(i * doublePi / numberOfSides));
circleVerticesY[i] = y;
circleVerticesZ[i] = z + (radius * sin(i * doublePi / numberOfSides));
}
//Loop to fill array with vertices
for (int i = 0; i < numberOfVertices; i++)
{
allCircleVertices[i * 8] = circleVerticesX[i];
allCircleVertices[(i * 8) + 1] = circleVerticesY[i];
allCircleVertices[(i * 8) + 2] = circleVerticesZ[i];
allCircleVertices[(i * 8) + 3] = 0.0f;
allCircleVertices[(i * 8) + 4] = 1.0f;
allCircleVertices[(i * 8) + 5] = 0.0f;
if ((i * 8) + 6 == 6)
{
allCircleVertices[6] = 0.5f;
}
else
{
allCircleVertices[(i * 8 + 6)] = 0.5 * (sin(angle * i));
}
if ((i * 8 + 7) == 7)
{
allCircleVertices[7] = 0.5f;
}
else
{
allCircleVertices[(i * 8 + 7)] = 0.5 * (cos(angle * i));
}
}
//For loop to fill Indices array with correct indices based on number of sides
for (int i = 0; i < numberOfSides; i++)
{
if (i == (numberOfSides - 1))
{
indices[i * 3] = 0;
indices[(i * 3) + 1] = indices[2];
indices[(i * 3) + 2] = numberOfSides;
//cout << indices[i * 3] << ", " << indices[(i * 3) + 1] << ", " << indices[(i * 3) + 2] << endl;
}
else
{
indices[i * 3] = 0;
indices[(i * 3) + 1] = i + 2;
indices[(i * 3) + 2] = i + 1;
//cout << indices[i * 3] << ", " << indices[(i * 3) + 1] << ", " << indices[(i * 3) + 2] << endl;
}
}
const GLuint floatsPerVertex = 3;
const GLuint floatsPerNormal = 3;
const GLuint floatsPerUV = 2;
glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
glBindVertexArray(mesh.vao);
// Create 2 buffers: first one for the vertex data; second one for the indices
glGenBuffers(2, mesh.vbos);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]); // Activates the buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(allCircleVertices), allCircleVertices, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU
mesh.nIndices = sizeof(indices) / sizeof(indices[0]) * (floatsPerVertex + floatsPerNormal + floatsPerUV);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
GLint stride = sizeof(float) * (floatsPerVertex + floatsPerNormal + floatsPerUV);// The number of floats before each
// Create Vertex Attribute Pointers
glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, floatsPerNormal, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float)* floatsPerVertex));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, floatsPerUV, GL_FLOAT, GL_FALSE, stride, (void*)(sizeof(float)* (floatsPerVertex + floatsPerNormal)));
glEnableVertexAttribArray(2);
}
I need to generate procedural terrain using Noise (using Perlin noise) in OpenGL. Each time the application runs a new terrain, it needs to be generated using a new seed. (Do not use external library.) Is there a method/requirement needed when making a class for noise terrains. What functions/calculation i need to call and in which order ?
PS: I use Visual Studio 2019.
// Copy the array data into a float array, and scale and offset the heights.
mHeightmap.resize(NumRows * NumCols, 0);
for( int i = 0; i < NumRows * NumCols; ++i)
{
mHeightmap[i] = (float)in[i] * HeightScale;
}
// A height for each vertex
{
std::vector<unsigned char> in(NumRows * NumCols);
// Open the file.
std::ifstream inFile;
inFile.open(heightmapName.c_str(), std::ios_base::binary);
if (inFile)
{
// Read the RAW bytes.
inFile.read((char*)&in[0], (std::streamsize)in.size());
// Done with file.
inFile.close();
}
// Copy the array data into a float array, and scale and offset the heights.
mHeightmap.resize(NumRows * NumCols, 0);
for( int i = 0; i < NumRows * NumCols; ++i)
{
mHeightmap[i] = (float)in[i] * HeightScale;
}
void Terrain::CreateVAO()
{
std::vector<GLfloat> vertices;
vertices.reserve(NumCols * NumRows * 8);
float invTwoDX = 1.0f / (2.0f * CellSpacing);
float invTwoDZ = 1.0f / (2.0f * CellSpacing);
//vertices
for ( int z = 0; z < NumRows; z++)
{
for ( int x = 0; x < NumCols; x++)
{
//vertex data
int i = z * NumCols + x;
vertices.push_back((float)x*CellSpacing);
vertices.push_back(mHeightmap[i]);
vertices.push_back((float)z * CellSpacing);
//normal data
glm::vec3 _N = { 0.0f,1.0f, 0.0f };
if(z >= 1 && z < NumRows -1 && x >= 1 && z < NumCols - 1)
{
float t = mHeightmap[(z - 1) * NumCols + x];
float b = mHeightmap[(z + 1) * NumCols + x];
float l = mHeightmap[z * NumCols + x - 1];
float r = mHeightmap[z * NumCols + x + 1];
glm::vec3 tanZ(0.0f, (b - t) * invTwoDZ, 1.0f);
glm::vec3 tanX(1.0f, (r - l) * invTwoDX, 0.0f);
glm::vec3 _C, _N;
_C = glm::cross(tanZ, tanX);
_N = glm::normalize(_C);
}
vertices.push_back(_N.x);
vertices.push_back(_N.y);
vertices.push_back(_N.z);
vertices.push_back((float)x);
vertices.push_back((float)z);
}
}
std::vector<GLuint> indices;
vertices.reserve((NumCols-1)*(NumRows -1)*6);
//indices
for ( int z = 0; z < NumRows-1; z++)
{
for ( int x = 0; x < NumCols-1; x++)
{
GLint a = z * NumCols + x;
GLint b = (z +1) * NumCols + x;
GLint c = z * NumCols + (x+1);
GLint d = (z+1) * NumCols + (x+1);
indices.push_back(c);
indices.push_back(a);
indices.push_back(b);
indices.push_back(c);
indices.push_back(b);
indices.push_back(d);
}
}
indexcount = indices.size();
GLuint VBO, EBO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(GLfloat), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
8 * sizeof(GLfloat), //Strude of the single vertex(pos)
(GLvoid*)0); //Offset from beginning of Vertex
glEnableVertexAttribArray(0);
glVertexAttribPointer(
1,
3,
GL_FLOAT,
GL_FALSE,
8 * sizeof(GLfloat), //Strude of the single vertex(pos+color)
(GLvoid*)(3 * sizeof(GLfloat))); //Offset from beginning of Vertex
glEnableVertexAttribArray(1);
glVertexAttribPointer(
2,
2, //2 float component for coordinates
GL_FLOAT,
GL_FALSE,
8 * sizeof(GLfloat), //Strude of the single vertex(pos+color+texture)
(GLvoid*)(6 * sizeof(GLfloat)));//Offset from beginning of Vertex
glEnableVertexAttribArray(2);
I'm not sure if I see usage of Perlin noise in your code. Try this lightweight, easy to integrate library:
https://github.com/Auburn/FastNoise which has Perlin and tons of other useful stuff like a visualizer.
Usage is as simple as
noise.GetNoise((float)x, (float)y); which you can plug into your height function
I am porting old fixed function pipeline code to shaders and for the torus geometry i am not able to create the correct indexes.
The old code
int CTorus::initevVertex2Ds()
{
const float twopi = 2.0 * M_PI;
// factor for texture coordinate per step in X/Y
const float fXtex = 1. / float(m_nCorners);
const float fYtex = 1. / float(m_nTesselation);
int i;
// go around cross section
for (i = 0; i < m_nTesselation; i++) {
register int base = i * m_nCorners;
register int baseTX = i * (m_nCorners+1);
// Y texture coordinate ...
m_texcoord[baseTX].x = fYtex * float(i);
// go around top view
const float f2Pi_i_corners = (twopi * float(i+m_nTesselation/2)) / float(m_nTesselation);
const float evVertex2D_z = m_fRadiusCrossSect * fsin(f2Pi_i_corners);
const float fXY = m_fRadiusTorus + m_fRadiusCrossSect * fcos(f2Pi_i_corners);
for (int j = 0; j < m_nCorners; j++) {
register int index = base + j;
const float fXj = fcos(twopi*float(j)/m_nCorners);
const float fYj = fsin(twopi*float(j)/m_nCorners);
m_GLVertex2D[index].x = fXY * fXj;
m_GLVertex2D[index].y = fXY * fYj;
m_GLVertex2D[index].z = evVertex2D_z;
m_texcoord[baseTX + j].y = 1. - fXtex * float(j);
m_texcoord[baseTX + j].x = m_texcoord[baseTX].x;
const float nx = m_GLVertex2D[index].x - m_fRadiusTorus * fXj;
const float ny = m_GLVertex2D[index].y - m_fRadiusTorus * fYj;
const float nz = m_GLVertex2D[index].z;
const float n = fsqrt(nx*nx + ny*ny + nz*nz);
m_norm[index].x = nx/n;
m_norm[index].y = ny/n;
m_norm[index].z = nz/n;
}
m_texcoord[baseTX + m_nCorners].y = 0.;
m_texcoord[baseTX + m_nCorners].x = m_texcoord[baseTX].x;
}
for (i=0; i<=m_nCorners; i++) {
m_texcoord[(m_nCorners+1)*m_nTesselation+i].y = m_texcoord[i].y;
m_texcoord[(m_nCorners+1)*m_nTesselation+i].x = 1.;
}
return 0;
}
This is the code where i have ported it to the shaders but i am not able to creat indexes for the element array buffer correctly
void Torus::init()
{
const float twopi = 2.0 * M_PI;
// factor for texture coordinate per step in x/y
const float fXtex = 1.0 / float(m_nCorners);
const float fYtex = 1.0 / float(m_nTesselation);
int i;
for (i = 0; i < m_nTesselation; i++)
{
register int base = i * m_nCorners;
register int baseTX = i * (m_nCorners + 1);
// go around top view
const float f2Pi_i_corners = (twopi * float(i + m_nTesselation / 2)) / float(m_nTesselation);
const float evVertex2D_z = m_fRadiusCrossSect * sinf(f2Pi_i_corners);
const float fXY = m_fRadiusTorus + m_fRadiusCrossSect * cosf(f2Pi_i_corners);
for (int j = 0; j < m_nCorners; j++)
{
register int index = base + j;
const float fXj = cosf(twopi*float(j) / m_nCorners);
const float fYj = sinf(twopi*float(j) / m_nCorners);
data.push_back(fXY * fXj);
data.push_back(fXY * fYj);
data.push_back(evVertex2D_z);
const float nx = (fXY * fXj) - m_fRadiusTorus * fXj;
const float ny = (fXY * fYj) - m_fRadiusTorus * fYj;
const float nz = evVertex2D_z;
const float n = sqrt(nx*nx + ny * ny + nz * nz);
data.push_back(nx / n);
data.push_back(ny / n);
data.push_back(nz / n);
// Pushing texture coordinates
data.push_back(0.0);
data.push_back(0.0);
}
}
std::vector<unsigned int> stdvecIndex;
unsigned int index;
// Create the indexes
for (int i = 0; i < m_nTesselation; i++)
{
index = ((i + 1) % m_nTesselation) * m_nCorners;
stdvecIndex.push_back(index);
for (int j = 0; j < m_nCorners; j++)
{
index = i * m_nCorners + j;
stdvecIndex.push_back(index);
index = ((i + 1) % m_nTesselation) * m_nCorners + ((j + 1) % m_nCorners);
stdvecIndex.push_back(index);
}
index = i * m_nCorners;
stdvecIndex.push_back(index);
}
if (!isInited)
{
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenVertexArrays(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(float), &data[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, stdvecIndex.size() * sizeof(unsigned int), &stdvecIndex[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)( 3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)(6 * sizeof(float)));
}
}
I have tried creating the indexes for the buffer but unfortunately i get inter mangled geometry instead of a torus.
The stride (5th) argument to glVertexAttribPointer is wrong. stride specifies the byte offset between consecutive generic vertex attributes.
The size of the attributes is 8 (x, y, z, nx, ny, nz, u, v).
Hence stride has to be 8 * sizeof(float) rather than 3 * sizeof(float):
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
Here is an issue of my project, please look at the screenshots:
problems
original(correct)
My object is build in a wrong way. The vertices are not connected properly.
I suspect that it has something to do with the indices of the model. Anyway here is the code that constructs the mesh for me:
mesh model::processMesh(aiMesh * mesh_, const aiScene * scene)
{
std::vector<vertex> vertices;
std::vector<GLuint> indices;
std::vector<texture> textures;
//vertices
for (GLuint i = 0; i < mesh_->mNumVertices; i++)
{
vertex vert;
glm::vec3 vector;
//positions
vector.x = mesh_->mVertices[i].x;
vector.y = mesh_->mVertices[i].y;
vector.z = mesh_->mVertices[i].z;
vert.position = vector;
//normals
vector.x = mesh_->mNormals[i].x;
vector.y = mesh_->mNormals[i].y;
vector.z = mesh_->mNormals[i].z;
vert.normal = vector;
//texture coords
if (mesh_->mTextureCoords[0])
{
glm::vec2 vector_;
vector_.x = mesh_->mTextureCoords[0][i].x;
vector_.y = mesh_->mTextureCoords[0][i].y;
vert.texCoords = vector_;
}
else vert.texCoords = glm::vec2(0.0f, 0.0f);
vertices.push_back(vert);
}
//indices
for (GLuint i = 0; i < mesh_->mNumFaces; i++)
{
aiFace face = mesh_->mFaces[i];
for (GLuint j = 0; j < mesh_->mNumFaces; j++) indices.push_back(face.mIndices[j]);
}
//textures
if (mesh_->mMaterialIndex >= 0)
{
aiMaterial* material = scene->mMaterials[mesh_->mMaterialIndex];
//diffuse
std::vector<texture> diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, TEX_DIFF_NAME);
textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end());
//specular
std::vector<texture> specularMaps = this->loadMaterialTextures(material, aiTextureType_SPECULAR, TEX_SPEC_NAME);
textures.insert(textures.end(), specularMaps.begin(), specularMaps.end());
}
return mesh(vertices, indices, textures);
}
In this function I set up all objects:
void mesh::setupMesh()
{
//buffers
glGenVertexArrays(1, &this->vao);
glGenBuffers(1, &this->vbo);
glGenBuffers(1, &this->ebo);
glBindVertexArray(this->vao);
glBindBuffer(GL_ARRAY_BUFFER, this->vbo);
glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(vertex), &this->vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(GLuint), &this->indices[0], GL_STATIC_DRAW);
//attributes
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, texCoords));
//unbind
glBindVertexArray(0);
}
And here is the render
void mesh::draw(shader* shader)
{
GLuint tex_diffNumber = 1;
GLuint tex_specNumber = 1;
for (GLuint i = 0; i < this->textures.size() ; i++)
{
//load target texture
glActiveTexture(GL_TEXTURE0 + i);
std::stringstream sstream;
std::string number;
std::string name = this->textures[i].type;
if (name == TEX_DIFF_NAME)
sstream << tex_diffNumber++;
else if (name == TEX_SPEC_NAME)
sstream << tex_specNumber++;
number = sstream.str();
glBindTexture(GL_TEXTURE_2D, this->textures[i].id);
glUniform1i(glGetUniformLocation(shader->shaderProgID, (name + number).c_str()), i);
}
//set shininess
//glUniform1f(glGetUniformLocation(shader->shaderProgID, "material.shininess"), 16.0f);
//draw
glBindVertexArray(this->vao);
glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//release
for (GLuint i = 0; i < this->textures.size(); i++)
{
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
The question is why does my model have wrong built triangles?
Ask any additional info.
Thank you for help in advance, guys!
for (GLuint i = 0; i < mesh_->mNumFaces; i++)
{
aiFace face = mesh_->mFaces[i];
for (GLuint j = 0; j < mesh_->mNumFaces; j++)
indices.push_back(face.mIndices[j]);
}
This looks wrong to me. I don't think the inner loop should run over all faces again. Instead it should iterate over all indices in the face:
for (GLuint i = 0; i < mesh_->mNumFaces; i++)
{
aiFace face = mesh_->mFaces[i];
for (GLuint j = 0; j < face->mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
Note, that the original version was reading outside of the available memory, since the loop was most probably going till j = 5 (six faces), but there are only faces with a maximum of four indices. If one would have attached a debugger and stepped through it, this should have been easily visible.