I have coded a flat terrain made up of triangles, but it seems like there some mirroring occurs. I want it to imitate grass, but it is blurried in some spots. Do I need to add some params in glTexParameteri? Or maybe it is an error which is associated with the drawing code?
A function which reads in a texture:
GLuint Terrain::write_model_texture(const char* filename)
{
GLuint tex;
// Activate texture 0
glActiveTexture(GL_TEXTURE0);
// Read into computers memory
std::vector<unsigned char> image;
unsigned width, height;
// Read the image
unsigned error = lodepng::decode(image, width, height, filename);
// Import to graphics card memory
glGenTextures(1, &tex); //Initialize one handle
glBindTexture(GL_TEXTURE_2D, tex); //Activate handle
// Copy image to graphics cards memory represented by the active handle
glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, (unsigned char*)image.data());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return tex;
}
Also code which draws triangles:
this->P = glm::mat4(1.0f);
this->V = glm::mat4(1.0f);
this->M = glm::mat4(1.0f);
P = in.P;
V = in.V;
//M = glm::rotate(M, glm::radians(90.0f), glm::vec3(1.0f, 0.0f, 0.0f));
M = glm::translate(M, glm::vec3(-5.0f, -5.0f, 0.0f));
//M = glm::scale(M, glm::vec3(10.0f, 10.0f, 10.0f));
for (int row = 0; row < terrain_height; row++)
{
int col;
// adding a row of vertices
for (col = 0; col < terrain_width; col++) {
// x, y, z, 1
//std::cout << random_num << std::endl;
terrain_verts.emplace_back(col, row, 0, 1);
terrain_norms.emplace_back(0.0f, 0.0f, 1.0f, 0);
}
// adding a row of indices
for (col = 0; col < terrain_width; col++)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + row * terrain_width + 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
}
for (col = terrain_width - 1; col >= 0; col--)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1));
}
// adding a row of texture coordinates
if (row % 2 == 0)
{
for (col = 0; col < terrain_width; col += 2)
{
terrain_texture_coordinates.emplace_back(0, 0);
terrain_texture_coordinates.emplace_back(1, 0);
}
}
else
{
for (col = 0; col < terrain_width; col += 2)
{
terrain_texture_coordinates.emplace_back(0, 1);
terrain_texture_coordinates.emplace_back(1, 1);
}
}
}
spTextured->use();
glUniformMatrix4fv(spTextured->u("P"), 1, false, glm::value_ptr(P));
glUniformMatrix4fv(spTextured->u("V"), 1, false, glm::value_ptr(V));
glEnableVertexAttribArray(spTextured->a("vertex"));
glEnableVertexAttribArray(spTextured->a("texCoord"));
glEnableVertexAttribArray(spTextured->a("normal"));
glUniformMatrix4fv(spTextured->u("M"), 1, false, glm::value_ptr(M));
glVertexAttribPointer(spTextured->a("vertex"), 4, GL_FLOAT, false, 0, terrain_verts.data());
glVertexAttribPointer(spTextured->a("texCoord"), 2, GL_FLOAT, false, 0, terrain_texture_coordinates.data());
glVertexAttribPointer(spTextured->a("normal"), 4, GL_FLOAT, false, 0, terrain_norms.data());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
glUniform1i(spTextured->u("tex"), 0);
glDrawElements(GL_TRIANGLES, terrain_indices_count(), GL_UNSIGNED_INT, terrain_indices.data());
glDisableVertexAttribArray(spTextured->a("vertex"));
glDisableVertexAttribArray(spTextured->a("color"));
glDisableVertexAttribArray(spTextured->a("normal"));
Your indices do not make the slightest sense:
for (col = 0; col < terrain_width; col++)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + row * terrain_width + 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
}
for (col = terrain_width - 1; col >= 0; col--)
{
terrain_indices.emplace_back(col + row * terrain_width);
terrain_indices.emplace_back(col + terrain_width * (row + 1) - 1);
terrain_indices.emplace_back(col + terrain_width * (row + 1));
}
If you look at your grid of data:
row = 0: 0 --- 1 --- 2 --- 3
| | | |
| | | |
row = 1: 4 --- 5 --- 6 ----7
^ ^ ^ ^
col=0 1 2 3
For row 0, column 0, you generate two triangles with the following vertices:
0, 1, 3 which is a deformed triangle with zero area
0, 3, 4 which goes completely across your grid:
For inner cells like row=0, col=1, you get:
1, 2, 4 which crosses 2 grid cells
1, 4, 5 which is at least belonging to a grid cell (although not the one it should)
You can actually see these patterns in your screenshot, you just need to take into account that you draw lots of weirdly overlapping triangles.
Your tex coords also won't work that way. You generate tex coords for alternating rows like this:
row = 0: (0,0) --- (1,0)
| |
| |
row = 1: (0,1) --- (1,1)
| |
| |
row = 2: (0,0) --- (1,0)
If you map texcoords that way, the cells between row 1 and row 2 will have the image vertically mirrored to those between row 0 and 1. You can't share the vertices of a row for the grid cella below and above it that way, you would have to duplicate the row vertices with different texcoords to make that work.
However, that is not necessary as you can use GL_REPEAT texture wrap mode and simply use texoords outside the [0,1] range like:
row = 0: (0,0) --- (1,0) --- (2,0)
| | |
| | |
row = 1: (0,1) --- (1,1) --- (2,1)
| | |
| | |
row = 2: (0,2) --- (1,2) --- (2,2)
Related
I am currently building a height map terrain generator using OpenGL. It's a simple program that loads a height map image, iterates over the image data and generates vertices, indices and normals. At its current state it can render a height map with a single colour based on the normals.
My problem is generating correct UV coordinates for the diffuse map. It just comes out wrong:
This is the diffuse map I am trying to load:
Here is what I currently have:
Generate Vertices, Normals and Indices
// Generate Vertices and texture coordinates
for (int row = 0; row <= this->imageHeight; row++)
{
for (int column = 0; column <= this->imageWidth; column++)
{
float x = (float)column / (float)this->imageWidth;
float y = (float)row / (float)this->imageHeight;
float pixel = this->imageData[this->imageWidth * row + column];
float z;
if (row == this->imageHeight || column == this->imageWidth || row == 0 || column == 0)
{
z = 0.0f;
}
else
{
z = float(pixel / 256.0)*this->scale;
}
MeshV3 mesh;
mesh.position = glm::vec3(x, y, z);
mesh.normal = glm::vec3(0.0, 0.0, 0.0);
mesh.texture = glm::vec2(x, y);
this->mesh.push_back(mesh);
}
}
// Generate indices
for (int row = 0; row < this->imageHeight; row++)
{
for (int column = 0; column < this->imageWidth; column++)
{
int row1 = row * (this->imageWidth + 1);
int row2 = (row + 1) * (this->imageWidth + 1);
// triangle 1
this->indices.push_back(glm::uvec3(row1 + column, row1 + column + 1, row2 + column + 1));
// triangle 2
this->indices.push_back(glm::uvec3(row1 + column, row2 + column + 1, row2 + column));
}
}
// Generate normals
for (int i = 0; i < this->indices.size(); i++)
{
glm::vec3 v1 = this->mesh[this->indices[i].x].position;
glm::vec3 v2 = this->mesh[this->indices[i].y].position;
glm::vec3 v3 = this->mesh[this->indices[i].z].position;
glm::vec3 edge1 = v1 - v2;
glm::vec3 edge2 = v1 - v3;
glm::vec3 normal = glm::normalize(glm::cross(edge1, edge2));
this->mesh[this->indices[i].x].normal += normal;
this->mesh[this->indices[i].y].normal += normal;
this->mesh[this->indices[i].z].normal += normal;
}
I load the diffuse map with the following method
void Terrein::getDIffuseMap()
{
glGenTextures(1, &this->texture);
glBindTexture(GL_TEXTURE_2D, this->texture); // all upcoming GL_TEXTURE_2D operations now have effect on this texture object
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
int width, height, nrChannels;
std::string path = "assets/diffuse.jpg";
this->diffuseData = stbi_load(path.c_str(), &width, &height, &nrChannels, 0);
if (this->diffuseData)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, this->diffuseData);
glGenerateMipmap(GL_TEXTURE_2D);
}
else
{
std::cout << "Failed to load diffuse texture" << std::endl;
}
}
I can't seem to figure out what might be wrong here. Is there an issue with how I am loading the image? Or am I not calculating the texture coordinates coorectly? Please let me know if there is anything else I should provide. I have been stuck at this for a few days now. Thanks!
By default OpenGL assumes that the start of each row of an image is aligned to 4 bytes.
This is because the GL_UNPACK_ALIGNMENT parameter by default is 4.
Since the image has 3 color channels (GL_RGB), and is tightly packed the size of a row of the image may not be aligned to 4 bytes.
When a RGB image with 3 color channels is loaded to a texture object, then GL_UNPACK_ALIGNMENT has to be set to 1:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, this->diffuseData);
The diffuse image in the question has a dimension of 390x390. So each row of the image has a size of 390 * 3 = 1170 bytes.
Since 1170 is not divisible by 4 (1170 / 4 = 292,5), the start of a row is not aligned to 4 bytes.
Related question: Failing to map a simple unsigned byte rgb texture to a quad
I can't figure out how DirectX11 understands which values in the vertex buffer are Vertices, which ones are Normals, and which ones are Texcoords
For example:
The following code works, but it draws the model as all white. But the normals and vertices are drawn correctly
std::vector<float> vertex_buffer;
for (int i = 0, j = 0; i < num_vertices; i+=3, j+=2)
{
vertex_buffer.push_back(attrib.vertices[i + 0]);
vertex_buffer.push_back(attrib.vertices[i + 1]);
vertex_buffer.push_back(attrib.vertices[i + 2]);
vertex_buffer.push_back(attrib.normals[i + 0]);
vertex_buffer.push_back(attrib.normals[i + 1]);
vertex_buffer.push_back(attrib.normals[i + 2]);
vertex_buffer.push_back(0.0F);
vertex_buffer.push_back(0.0F);
vertex_buffer.push_back(0.0F);
}
std::vector<UINT> index_buffer;
for (int i = 0, j = 0; i < num_indices; i+=3, j+=2)
{
index_buffer.push_back(shapes[0].mesh.indices[i + 0].vertex_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 1].vertex_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 2].vertex_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 0].normal_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 1].normal_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 2].normal_index);
index_buffer.push_back(0);
index_buffer.push_back(0);
index_buffer.push_back(0);
}
For example, the code above produces this:
But if I start changing anything in the index buffer in the last 3 values of the 9 values, the model draws the vertices incorrectly.
Here I modify it to use texcoords
(I use TinyObjLoader for importing obj files and I have no idea why it has 3 texcoords per vertex, instead of 2)
std::vector<float> vertex_buffer;
for (int i = 0, j = 0; i < num_vertices; i += 3, j += 2)
{
vertex_buffer.push_back(attrib.vertices[i + 0]);
vertex_buffer.push_back(attrib.vertices[i + 1]);
vertex_buffer.push_back(attrib.vertices[i + 2]);
vertex_buffer.push_back(attrib.normals[i + 0]);
vertex_buffer.push_back(attrib.normals[i + 1]);
vertex_buffer.push_back(attrib.normals[i + 2]);
vertex_buffer.push_back(attrib.texcoords[i + 0]);
vertex_buffer.push_back(attrib.texcoords[i + 1]);
vertex_buffer.push_back(attrib.texcoords[i + 2]);
}
std::vector<UINT> index_buffer;
for (int i = 0, j = 0; i < num_indices; i += 3, j += 2)
{
index_buffer.push_back(shapes[0].mesh.indices[i + 0].vertex_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 1].vertex_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 2].vertex_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 0].normal_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 1].normal_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 2].normal_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 0].texcoord_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 1].texcoord_index);
index_buffer.push_back(shapes[0].mesh.indices[i + 2].texcoord_index);
}
I get this result:
Clearly, here its not just the textures that are affected, the vertex order is messed up. But Im only changing the fields in the buffer which are supposed to be for texcoords. Why does it affect vertices. Why do vertex and normal coordinates/values work, but texcoords do not.
How does DirectX know which indeces in IndexBuffer refer to Vertices, which ones refer to Normals, and which ones refer to Texcoords
Also, for this model I had to use a Vertex Stride of 36, when I moved the entries from 9 to 8 and changed vetex stride to 32, it was even worse.
Does DirectX automatically assign the first 3 values within stride to vertex, next3 to normal, and next 2 to texcoordinates? Is this how it works?
Thanks,
The Direct3D Input Assembler is not nearly as flexible as you are assuming. It takes a single index from an index buffer and uses that value to look up the same vertex from 1 or more bound vertex buffers. The entire vertex is then sent to a single invocation of a vertex shader.
The input layout tells you everything you need to know. For example, here is a very simple input layout:
{ "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
This corresponds to a Vertex structure like:
struct Vertex
{
XMFLOAT3 position;
XMFLOAT3 normal;
XMFLOAT2 textureCoordinate;
};
In this case, you'd bind a single Vertex Buffer to the system, and of course a single Index Buffer. The stride of the VB would be sizeof(Vertex) or 32-bytes, which is consider an optimal size for most hardware.
It would use something like this pseudo-code:
// StartIndexLocation, BaseVertexLocation, IndexCount are DrawIndexed parameters
// stride and offset are IASetVertexBuffers parameters
for(I = 0; I < IndexCount; I++)
{
uint16_t/uint32_t index = IndexBuffer[I + StartIndexLocation];
Vertex v = VertexBuffer_Bytes[((index + BaseVertexLocation) * stride) + offset];
VertexShader(v);
}
You can also create a multi-stream input layout which takes more than one VB. Here is an example of a 3 stream input layout:
{ "SV_Position", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 1, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 2, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
Here this would correspond to three Vertex structures:
struct Vertex1
{
XMFLOAT3 position;
};
struct Vertex2
{
XMFLOAT3 normal;
};
struct Vertex3
{
XMFLOAT2 textureCoordinate;
};
You'd use strides of 12, 12, and 8 for three bound Vertex Buffers. There is still only a single Index Buffer so all the data for a specific vertex must be in the same index for all three VBs.
It would use something like this pseudo-code:
for(I = 0; I < IndexCount; I++)
{
uint16_t/uint32_t index = IndexBuffer[I + StartIndexLocation];
Vertex1 v1 = VertexBuffer0_Bytes[((index + BaseVertexLocation) * stride0) + offset0];
Vertex2 v2 = VertexBuffer1_Bytes[((index + BaseVertexLocation) * stride1) + offset1];
Vertex3 v3 = VertexBuffer2_Bytes[((index + BaseVertexLocation) * stride2) + offset2];
VertexShader(v1, v2, v3);
}
While geometry file formats like WaveFront OBJ and internal data structures for CAD/3D art programs often use multiple indices per vertex for a more compact memory structure, you can't directly render such data using Direct3D or OpenGL. You have to convert it to the interleaved form by duplication of data.
std::vector<XMFLOAT3> positions;
std::vector<XMFLOAT3> normals;
std::vector<XMFLOAT2> texcoords;
// Load these three from the file
std::vector<Vertex> vertexBuffer;
std::vector<uint32_t> indexBuffer;
for each face in WaveFront OBJ:
for each vertex in the face:
Vertex v;
v.position = positions[vertexIndex];
v.normal = normal[normalIndex];
v.textureCoordinate = texcoords[textureIndex];
uint32_t index = AddVertex(vertexIndex, &vertex, vertexCache);
indexBuffer.push_back(index);
// Helper function to try to minimize vertex duplication
typedef std::unordered_multimap<UINT, UINT> VertexCache;
uint32_t AddVertex(UINT hash, const Vertex* pVertex, VertexCache& cache)
{
auto f = cache.equal_range(hash);
for (auto it = f.first; it != f.second; ++it)
{
auto& tv = vertexBuffer[it->second];
if (0 == memcmp(pVertex, &tv, sizeof(Vertex)))
{
return it->second;
}
}
uint32_t index = static_cast<uint32_t>(vertices.size());
vertexBuffer.emplace_back(*pVertex);
VertexCache::value_type entry(hash, index);
cache.insert(entry);
return index;
}
See WaveFrontReader.h. While my reader implementation isn't perfect, it does handle a number of issues your code is ignoring like negative index values, converting n-gons to triangles, etc.
I have just begun learning OpenGL, and I think there is a problem with my index array formula.
I'm trying to render a square terrain using IBO. When I draw with glDrawElements, the result would only appear on the bottom half of the screen, all tightly packed in a rectangular shape, while when I use glDrawArrays it works out perfectly with a square shaped and centered mesh.
I load my vertex height values from a grayscale, here is how I load vertices and create indices:
For vertices: right to left, bottom to top
int numVertices = image.width() * image.height() * 3;
float rowResize = image.width() / 2;
float colResize = image.height() / 2;
GLfloat* vertexData;
vertexData = new GLfloat[numVertices];
int counter = 0;
for (float j = 0; j < col; j++){
for (float i = 0; i < row; i++){
vertexData[counter++] = (i - rowResize) / rowResize;
vertexData[counter++] = (j - colResize) / colResize;
vertexData[counter++] = image.getColor(i,j) / 255.0f;
}
}
For indices: Trying to follow the order of {0, 1, 2, 1, 3, 2...}
2 3
-------
|\ |
| \ |
| \ |
| \ |
| \|
-------
0 1
int numIndices = (row - 1) * (col - 1) * 2 * 3;
unsigned short* indexData = new unsigned short[numIndices];
counter = 0;
for (short y = 0; y < col - 1; y++){
for (short x = 0; x < row - 1; x++){
// lower triangle
short L_first = y*row + x;
short L_second = L_first + 1;
short L_third = L_first + row;
//upper triangle
short U_first = L_first + 1;
short U_second = U_first + row;
short U_third = U_second - 1;
indexData[counter++] = L_first;
indexData[counter++] = L_second;
indexData[counter++] = L_third;
indexData[counter++] = U_first;
indexData[counter++] = U_second;
indexData[counter++] = U_third;
}
}
I initialized VAO, VBO and IBO, and then gen, bind, link data for each buffer object, and then unbind all.
In the game loop I have:
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 3, 0);
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glDrawArrays(GL_POINTS, 0, numVertices);
//glDrawElements(GL_TRIANGLE_STRIP, numIndices, GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0);
glfwSwapBuffers(window);
Since drawing from vertices works and drawing from indices doesn't, what could be wrong with my indices generation?
Thank you for your help!
(Weird thing: I just tried with another grayscale image, and it worked well with both drawing from verticesGL_POINTS and indicesGL_TRIANGLE_STRIP...welp)
Pictures
Using glDrawArrays
Using glDrawElements
So I'm putting together a height map renderer that will do most of the work int he vertex shader, but first of course I generate a mesh to render, at the moment I'm playing around with upper limits of openGL and C++ to see how dense a mesh I can render (so I later have something to go by in terms of LoD mesh dividing)
ANYWAY! to cut to the issue;
the issue I noticed after testing a meshResolution of 32, 64 and at 128 I experienced runtime crashes, I stopped them by using the a self made class "indexFace" which holds 6 indices to lower the array length, problem is at 128 resolution only a 3rd of the mesh actually displays, I was wondering if there was a limit to how many indices openGL can render or hold using 1 set of BufferObjects or if its an issue with my handling of the C++ side of things.
I'm generating the mesh via the following:
void HeightMapMesh::GenerateMesh(GLfloat meshScale, GLushort meshResolution)
{
GLushort vertexCount = (meshResolution + 1) * (meshResolution + 1);
Vertex_Texture* vertexData = new Vertex_Texture[vertexCount];
GLushort indexCount = (meshResolution * meshResolution) * 6;
//indexFace holds 6 GLushort's in an attempt to overcome the array size limit
indexFace* indexData = new indexFace[meshResolution * meshResolution];
GLfloat scalar = meshScale / ((GLfloat)meshResolution);
GLfloat posX = 0;
GLfloat posY = 0;
for (int x = 0; x <= meshResolution; x++)
{
posX = ((GLfloat)x) * scalar;
for (int y = 0; y <= meshResolution; y++)
{
posY = ((GLfloat)y) * scalar;
vertexData[y + (x * (meshResolution + 1))] = Vertex_Texture(posX, posY, 0.0f, x, y);
}
}
GLint indexPosition;
GLint TL, TR, BL, BR;
for (int x = 0; x < meshResolution; x++)
{
for (int y = 0; y < meshResolution; y++)
{
indexPosition = (y + (x * (meshResolution)));
BL = y + (x * (meshResolution + 1));
TL = y + 1 + (x * (meshResolution + 1));
BR = y + ((x + 1) * (meshResolution + 1));
TR = y + 1 + ((x + 1) * (meshResolution + 1));
indexData[indexPosition] = indexFace(
BL, TR, TL,
BL, BR, TR
);
}
}
mesh.Fill(vertexData, vertexCount, (void *)indexData, indexCount, GL_STATIC_DRAW, GL_STATIC_DRAW);
delete [] vertexData;
delete [] indexData;
}
//This is for mesh.Fill()
void Fill(T* vertData, GLushort vertCount, void* indData, GLushort indCount, GLenum vertUsage, GLenum indUsage)
{
indexCount = indCount;
vertexCount = vertCount;
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObjectID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferObjectID);
glBufferData(GL_ARRAY_BUFFER, sizeof(T) * vertexCount, vertData, vertUsage);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * indexCount, indData, indUsage);
}
its because you made your indices shorts.
For example this: GLushort indexCount = (meshResolution * meshResolution) * 6; is hitting USHRT_MAX at a value of 105 for meshResolution. (105*105*6 = 66150 > 65535)
Use ints as indices. So change your indices everywhere to unsigned ints and do the final draw call like this:
glDrawElements( GL_QUADS, indCount, GL_UNSIGNED_INT, indices); //do this
//glDrawElements( GL_QUADS, indCount, GL_UNSIGNED_SHORT, indices); //instead of this
//also GL_QUADS is deprecated but it seems your data is in that format so I left it that way
You could save a bunch of indices if you drew GL_TRIANGLE_STRIPs instead or better yet do tesselation on the GPU, since this is like the perfect use-case for it.
So I'm working with a 2d array, and I'm trying to display it on a widget using opengl. It seems to work fine, but it does not fill the widget properly. Rather than filling it evenly it's moved to the top right as seen in the image below. How can I get this to be centered?
int x = -0.1;
int y = -0.1;
float lengthX = 0.9 / ROW;
float lengthY = 0.9 / COLM;
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < COLM; j++) {
if (arr[i][j] == 1) {
glColor3f(1.0f, 1.0f, 1.0f);
} else {
glColor3f(0.0f, 0.0f, 0.0f);
}
glBegin(GL_QUADS);
// Q3 Q4 Q1 Q2
glVertex2f((-x) + 2 * i * lengthX, (-y) + 2 * j * lengthY);
glVertex2f(x + (2 * i + 1) * lengthX, (-y) + (2 * j + 1) * lengthX);
glVertex2f(x + (2 * i + 1) * lengthX, y + (2 * j + 1) * lengthY);
glVertex2f((-x) + 2 * i * lengthX, y + 2 * j * lengthY);
glEnd();
}
}
First off, your code is wrong with it's variables; Such as int x = -0.1.
Now, to fix the problem just add this to the beginning of your code:
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 1, 1, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
The problem was that you're using the default matrix setup. Basically, it ranges from -1, -1 to 1, 1, instead of 0, 0, to 1, 1. I can't quite read your code, but if you can edit the glOrtho function's first 4 parameters (the last two shouldn't effect anything) to change the visible range of what you're drawing.
Just to explain a bit more, the first parameter sets the left side, the second right, the third bottom, and the fourth top. So glOrtho(0, 600, 800, 0) means setting a vertex to 0, 0 means it's showing on the top left, while a vertex set to 800, 600 will be showing on the bottom right.
Your setup was only showing a part of what it was supposed to show because the center of it, was the corner of your screen.