Draw cylinder in shader based opengl - c++

I'm looking for a good way to draw cylinder on opengl, i tried to draw multiple circles
for (GLuint m = 0; m <= segments; ++m) {
for (GLuint n = 0; n <= segments; ++n) {
GLfloat const t = 2 * M_PI * (float) n / (float) segments;
//position
points[num++] = x + sin(t) * r;
points[num++] = .0005 * m;
points[num++] = y + cos(t) * r;
//color
points[num++] = 1;
points[num++] = 1;
points[num++] = 1;
//texture
points[num++] = sin(t) * 0.5 + 0.5;
points[num++] = cos(t) * 0.5 + 0.5;
}
}
and on display function
GLuint pointer = 0;
for (GLuint i = 0; i <= segments; ++i) {
glDrawArrays(GL_TRIANGLE_FAN, pointer, segments + 1);
pointer += segments + 1;
}
I'm asking if there is a direct way to draw this cylinder

drawing many discs one on top of the other is too slow (unless you really want to draw the cylinder as slices of discs)
You should just draw the sides of the cylinder. For example a quad mesh would be
// for (GLuint m = 0; m <= segments; ++m)
float const bottom = .0005f * 0.f;
float const top = .0005f * (segments-1.f);
for(GLuint n = 0; n <= segments; ++n)
{
GLfloat const t0 = 2 * M_PI * (float)n / (float)segments;
GLfloat const t1 = 2 * M_PI * (float)(n+1) / (float)segments;
//quad vertex 0
points[num++] = x + sin(t0) * r;
points[num++] = bottom;
points[num++] = y + cos(t0) * r;
//quad vertex 1
points[num++] = x + sin(t1) * r;
points[num++] = bottom;
points[num++] = y + cos(t1) * r;
//quad vertex 2
points[num++] = x + sin(t1) * r;
points[num++] = top;
points[num++] = y + cos(t1) * r;
//quad vertex 3
points[num++] = x + sin(t0) * r;
points[num++] = top;
points[num++] = y + cos(t0) * r;
}
You can add 2 disks (the bases) to close the cylinder.
You can reduce fetching vertices form memory using a vertex+index buffer.
In new versions of OGL you can eliminate vertex memory read by indexing the mesh using gl_VertexID

Related

How do I add a wave to a curved surface composed of triangle primatives in C++?

I want to preface this post: This is perhaps more of a math question than a coding question.
I am developing a plant (lettuce) model which involves somewhat complex geometry. At this stage I have a surface curved in 2 dimensions but now I want to add waviness to this curved surface but am having a hard time envisioning how to do so. The surface is made of triangle primatives, the primatives take xyz vectors to encode location of vertices. I am using an API termed HELIOS to develop this procedural model of lettuce. I essentially created the surface with for loops and the sine function. Disclaimer: I do not have a strong background in geometry, computer graphics, or C++.
Here is the relevant code:
#include "Context.h"
#include "Visualizer.h"
using namespace helios;
using namespace std;
vector<uint> addLeaf(float leaf_length, float leaf_width, float leaf_bend_x, float leaf_bend_y, float rotation_z, float rotation_x, float displacement, float radius, Context* context ) {
std::vector<uint> UUIDs;
// float leaf_length = 10;
float Nz = 10; // params.s1_leaf_subdivisions ; number of times to split the dimension
float dz = leaf_length / Nz; // length of each subdivision
// float leaf_width = 10;
float Ny = 10; // params.s1_leaf_subdivisions ; number of times to split the dimension
float dy = leaf_width / Ny; // length of each subdivision
// leaf wave
// float A_3 = leaf_length * float(0.5); // Half waves on the leaf 10
// float A_2 = leaf_length * float(0.1); // amplitude 0.25
float A_3 = 1; // Half waves on the leaf 10
float A_2 = 1; // amplitude 0.25
float leaf_amplitude = leaf_length / float(10);
// the 2 * dx extends the sine wave a bit beyond 1/2 wavelength so base of leaves come together
for (int i = 0; i < Nz + (2 * dz); i++) {
for (float j = 0; j < Ny; j++) {
float z = i * dz; //for each subdivision in z define Z coord
float y = j * dy; //for each subdivision in y define y coord
float x = 0; // we will also need an x coord
float sz = dz; // the next step in z will be equal to a subdivision in z
float sy = dy; // the next step in y will be equal to a subdivision in y
float z_i = z * M_PI / (Nz * dz); // the second coord for z is z_i needed to define a triangle primitive
float sz_i = (z + sz) * M_PI / (Nz * dz); //
// this would be y_1 in sorghum model
float y_i = (y * M_PI / (Ny * dy)) / (A_3); // the second coord for y is y_i needed to define a triangle primitive
float sy_i = ((y + sy) * M_PI / (Ny * dy)) / (A_3);
//waviness of leaf
float leaf_wave_1;
float leaf_wave_2;
float leaf_wave_3;
float leaf_wave_4;
if (j == 0) {
leaf_wave_1 = A_2 * sin(z_i);
leaf_wave_2 = A_2 * sin(sz_i);
} else {
leaf_wave_1 = A_2 * sin(z_i);
leaf_wave_2 = A_2 * sin(sz_i);
}
// Now define x based on z,y and add leaf bend in x and y
x = leaf_bend_x * sin(z_i);
x = ((x*radius + displacement + (leaf_bend_y * sin(y_i))) / 2) + leaf_wave_1;
vec3 v0(x*radius + displacement, y, z);
x = leaf_bend_x * sin(sz_i);
x = ((x*radius + displacement + (leaf_bend_y * sin(y_i))) / 2) + leaf_wave_2;
vec3 v1(x*radius + displacement, y, z + sz);
if (j == Nz - 1) {
leaf_wave_3 = sin(sz_i) * A_2;
leaf_wave_4 = sin(z_i) * A_2;
} else {
leaf_wave_3 = sin(sz_i) * A_2;
leaf_wave_4 = sin(z_i) * A_2;
}
x = leaf_bend_x * sin(sz_i);
x = ((x*radius + displacement + (leaf_bend_y * sin(sy_i))) / 2) + leaf_wave_3 ;
vec3 v2(x*radius + displacement, y + sy, z + sz);
x = leaf_bend_x * sin(z_i);
x = ((x*radius + displacement + (leaf_bend_y * sin(sy_i))) / 2) + leaf_wave_4 ;
vec3 v3(x*radius + displacement, y + sy, z);
// set of two triangles which form a rectangle or square as subunits of leaf
UUIDs.push_back(context->addTriangle(v0, v1, v2, RGB::cyan));
UUIDs.push_back(context->addTriangle(v0, v2, v3, RGB::magenta));
}
}
return UUIDs;
}
// call to functions and build lettuce geometries
int main( void ){
Context context;
float leaf_length = 10;
float leaf_width = 10;
float radius = 1; // additional control leaf curvature
// add leaves one by one; 'i' here is # of leaves external to whorl
for (int i = 0; i < 6; i++) {
if (i == 0)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, 0, i/5, radius, &context);
// if (i == 1)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 20, i/5, radius, &context);
// if (i == 2)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 10, i/5, radius, &context);
// if (i == 3)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 9, i/5, radius, &context);
// if (i == 4)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 7, i/5, radius, &context);
// if (i == 5)addLeaf(leaf_length, leaf_width, 0.5*leaf_length, 0.5*leaf_width, 4 * M_PI / 9*i, -M_PI/ 5, i/5, radius, &context);
}
Visualizer visualizer(800);
visualizer.buildContextGeometry(&context);
visualizer.setLightingModel(Visualizer::LIGHTING_PHONG);
visualizer.plotInteractive();
}
I tried to use a sine function and an additional for loop to create a series of values to add to the X coordinate of the triangles but did not obtain the result I was looking for.
This is how you can create a Wave Geometry.
you can keep updating the m_fTime values to animate the wave.
// m_iWaveFlowOut -> value to be either 0 or 1
//m_fFrequency -> Number of waves
//m_fAmplitude -> Amplitude of wave
void Generate()
{
const int n8 = m_iNSegments * 8; // size of VBO gfx data
const int sz0 = m_iMSegments * n8; // size of VBO gfx data
const int sz1 = (m_iMSegments - 1) * (m_iNSegments - 1) * 6;// size of indices
verticesRect.clear();
indicesRect.clear();
int a,i, j, k, b;
float x, y, z, dx, dy, l;
glm::vec3 u, v, nor;
dx = 2.0 * ( m_fWidth / float(m_iNSegments - 1));
dy = 2.0 * ( m_fHeight / float(m_iMSegments - 1));
for (a = 0, y = -m_fHeight, j = 0; j < m_iMSegments; j++, y += dy)
for (x = -m_fWidth, i = 0; i < m_iNSegments; i++, x += dx)
{
float dist = glm::length(glm::vec2(x + m_fxOffset, y + m_fyOffset));
float attenuation, kc, kq;
kc = 1.0; kq = 0.0;
attenuation = 1.0f;
if (m_bUseAttenuation) {
attenuation = 1.0 / (kc + (this->m_fKl * dist) + (kq * pow(dist, 2)));
if (attenuation > 1.0) attenuation = 1.0;
}
switch (m_WAVETYPE)
{
case Sum_Wave2::WAVE2_TYPE::COS:
z = (-m_fAmplitude * attenuation) * cos(((x + m_fxOffset) / m_fFrequency) + m_fTime * m_iWaveFlowOut);
break;
case Sum_Wave2::WAVE2_TYPE::SIN:
z = (-m_fAmplitude * attenuation) * sin(((y + m_fyOffset) / m_fFrequency) + m_fTime * m_iWaveFlowOut);
break;
case Sum_Wave2::WAVE2_TYPE::RING:
z = (-m_fAmplitude * attenuation) * sin((glm::length(glm::vec2(x + m_fxOffset, y + m_fyOffset)) + m_fTime * m_iWaveFlowOut) / m_fFrequency);
break;
default:
z = 0.0;
break;
}
verticesRect.push_back(x); a++;
verticesRect.push_back(y); a++;
verticesRect.push_back(z); a++;
// Normal ( will be recomputed later)
verticesRect.push_back(0.0); a++;
verticesRect.push_back(0.0); a++;
verticesRect.push_back(1.0); a++;
// TexCoord
verticesRect.push_back((x + m_fWidth) / (m_fWidth + m_fWidth)); a++;
verticesRect.push_back((y + m_fHeight) / (m_fHeight + m_fHeight)); a++;
}
// triangulation indices
for(a = 0, j = 1; j < m_iMSegments; j++ )
for (i = 1; i < m_iNSegments; i++)
{
b = ((m_iNSegments * j) + i) * 8;
// First triangle per quad
indicesRect.push_back(b - 8); a++;
indicesRect.push_back(b - 8 - n8); a++;
indicesRect.push_back(b); a++;
// Second triangle per quad
indicesRect.push_back(b - 8 - n8); a++;
indicesRect.push_back(b - n8); a++;
indicesRect.push_back(b); a++;
// recompute inner normals
for (k = 0; k < 3; k++) {
u[k] = verticesRect[indicesRect[a - 6] + k] - verticesRect[indicesRect[a - 4] + k];
v[k] = verticesRect[indicesRect[a - 5] + k] - verticesRect[indicesRect[a - 4] + k];
}
glm::vec3 cross1 = crossProduct(u, v);
cross1 = glm::normalize(cross1);
for (k = 0; k < 3; k++) {
u[k] = verticesRect[indicesRect[a - 3] + k] - verticesRect[indicesRect[a - 1] + k];
v[k] = verticesRect[indicesRect[a - 2] + k] - verticesRect[indicesRect[a - 1] + k];
}
glm::vec3 cross2 = crossProduct(u, v);
cross2 = glm::normalize(cross2);
for (k = 0; k < 3; k++) {
verticesRect[indicesRect[a - 1] + 3 + k] = 0.5 * (cross1[k] + cross2[k]);
}
}
for (i = 0; i < sz1; i++) {
indicesRect[i] = indicesRect[i] /= 8;
}
}

"rotation algorithm" in opngl not working

I'm trying "rotation algorithm" in opngl but it's not working I'm getting a blank page when I run my program
. should I put POINT* verts or Point verts[6]
is there something wrong with my code?
void rotate(POINT* verts, GLint nverts, POINT fixedv, GLdouble theta) {
POINT newverts[6]; //POINT fixedv
GLint k;
for (k = 0; k < nverts; k++) {
newverts[k].x = fixedv.x + (verts[k].x - fixedv.x) * cos(theta) - (verts[k].y - fixedv.y) * sin(theta);
newverts[k].y = fixedv.y + (verts[k].x - fixedv.x) * sin(theta) + (verts[k].y - fixedv.y) * cos(theta);
newverts[k].x = (verts[k].x) * cos(theta) - (verts[k].y) * sin(theta);
newverts[k].y = (verts[k].x) * sin(theta) + (verts[k].y) * cos(theta);
}
glBegin(GL_TRIANGLE_FAN);
for (k = 0; k < nverts; k++)
glVertex2f(newverts[k].x, newverts[k].y);
glEnd();
glFlush();
}
display code:
void display() {
glColor3f(r, g, b);
if (check == 3) {
double theta = 3.14 * 0.5;
POINT verts[6],fixedpivot;
fixedpivot.x = x;
fixedpivot.y = y;
verts[0].x = x + 25;
verts[0].y = y + 50;
verts[1].x = x;
verts[1].y = y;
verts[2].x = x+50;
verts[2].y = y;
verts[3].x = x + 25;
verts[3].y = y + 50;
verts[4].x = x + 50;
verts[4].y = y + 100;
verts[5].x = x;
verts[5].y = y + 100;
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(r, g, b);
rotate(verts, 6, fixedpivot, theta);
glFlush();

Terrain drawing over itself at larger sizes

I have had a terrain generation algorithm for a while and have had a lot of success with it. However when I decided to start work on Level of Detail (Has not been implemented), I started to notice that my terrain would begin to draw underneath itself as it got larger (when it gets to around 257 by 257). I'm not too sure why it starts to do this however I have a feeling its either due to me converting the 2d vector into a 1d or when i generate my indices but i am not 100 percent. If someone could have a look that would be amazing
Terrain at 100 by 100
Terrain at 1000 by 1000
Code used to Generate Vertices
void TerrainObject::LoadFlatTerrain()
{
float F_terrainDimentions = terrainDimentions; //used to stop integer division
m_vertexCount = terrainDimentions * terrainDimentions; //terrainDimentions = the width and depth of the terrain
float halfWidth = 0.5f * F_terrainDimentions;
float halfDepth = 0.5f * F_terrainDimentions;
// project the grid into xz plane
float dx = F_terrainDimentions / (F_terrainDimentions - 1);
float dz = F_terrainDimentions / (F_terrainDimentions - 1);
float du = 1.0f / (F_terrainDimentions - 1); // texture co-ordinates
float dv = 1.0f / (F_terrainDimentions - 1);
//Resizes Vectors for Vertices
vertices.resize(m_vertexCount);
verts2d.resize(terrainDimentions);
for (int i = 0; i < verts2d.size(); i++)
{
verts2d[i].resize(terrainDimentions);
}
//Generates Vertices for 2d array
for (int i = 0; i < terrainDimentions; i++)
{
float z = halfDepth - i * dz;
for (int j = 0; j < terrainDimentions; j++)
{
float x = -halfWidth + j * dx;
float y = 0;
verts2d[i][j].Position.x = x;
verts2d[i][j].Position.y = y;
verts2d[i][j].Position.z = z;
verts2d[i][j].Normal = XMFLOAT3(0.0f, 1.0f, 0.0f);
verts2d[i][j].Tangent = XMFLOAT3(1.0f, 0.0f, 0.0f);
verts2d[i][j].TexCoord.x = j * du;
verts2d[i][j].TexCoord.y = i * dv;
}
}
//Converts to 1d array
for (int i = 0; i < terrainDimentions; i++)
{
for (int j = 0; j < terrainDimentions; j++)
{
vertices[i * terrainDimentions + j].Position = verts2d[i][j].Position;
vertices[i * terrainDimentions + j].TexCoord = verts2d[i][j].TexCoord;
vertices[i * terrainDimentions + j].Normal = verts2d[i][j].Normal;
vertices[i * terrainDimentions + j].Tangent = verts2d[i][j].Tangent;
}
}
// Create vertex buffer
D3D11_BUFFER_DESC vbd;
vbd.Usage = D3D11_USAGE_IMMUTABLE;
vbd.ByteWidth = sizeof(ComplexVertex) * m_vertexCount;
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = &(vertices[0]);
m_pd3dDevice->CreateBuffer(&vbd, &vinitData, &m_pVertexBuffer);
CreateIndices();
//Sets terrains Current position in the world to be the top corner
m_position = verts2d[terrainDimentions - 1][terrainDimentions - 1].Position;
}
Code to Generate Indices
HRESULT TerrainObject::CreateIndices()
{
UINT faceCount = (terrainDimentions - 1) * (terrainDimentions - 1) * 2; // each quad consists of two triangles
int index = 0;
indices.resize(faceCount * 3);
for (UINT i = 0; i < terrainDimentions - 1; ++i)
{
for (UINT j = 0; j < terrainDimentions - 1; ++j)
{
indices[index] = i * terrainDimentions + j;
indices[index + 1] = i * terrainDimentions + j + 1;
indices[index + 2] = (i + 1) * terrainDimentions + j;
indices[index + 3] = (i + 1) * terrainDimentions + j;
indices[index + 4] = i * terrainDimentions + j + 1;
indices[index + 5] = (i + 1) * terrainDimentions + j + 1;
index += 6; // next quad
}
}
m_indexCount = indices.size();
// Creates index buffer
D3D11_BUFFER_DESC ibd;
ibd.Usage = D3D11_USAGE_DEFAULT;
ibd.ByteWidth = sizeof(WORD) * m_indexCount;
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = &indices[0];
return m_pd3dDevice->CreateBuffer(&ibd, &iinitData, &m_pIndexBuffer);
}

3D Cylinder how to calculate vertexSize, indicesSize and textCoordinateSize In openGl

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.

Heightmap generation finishes halfway through

Currently, I'm trying to make a noise generated heightmap and display it with opengl. I'm following this tutorial, but my heightmap doesn't seem to work. It seems like it generates (or displays) only half of what it is supposed to.
This is the heightmap with normals for color:
As you can see, even though this is supposed to be a square, it appears rectangular with an unfinished edge.
This is my heightmap generation code:
public class HeightMap extends GameModel {
private static final float START_X = -0.5f;
private static final float START_Z = -0.5f;
public HeightMap(float minY, float maxY, float persistence, int width, int height) {
super(createMesh(minY, maxY, persistence, width, height));
}
protected static Mesh createMesh(final float minY, final float maxY, final float persistence, final int width,
final int height) {
SimplexNoise noise = new SimplexNoise(128, persistence, 2);// Utils.getRandom().nextInt());
float xStep = Math.abs(START_X * 2) / width;
float zStep = Math.abs(START_Z * 2) / height;
List<Float> positions = new ArrayList<>();
List<Integer> indices = new ArrayList<>();
for (int x = 0; x < width; x++) {
for (int z = 0; z < height; z++) {
// scale from [-0.5, 0.5] to [minY, maxY]
float heightY = (float) ((noise.getNoise(x, z) + 0.5f) * (maxY - minY) + minY);
positions.add(START_X + x * xStep);
positions.add(heightY);
positions.add(START_Z + z * zStep);
// Create indices
if (x < width - 1 && z < height - 1) {
int leftTop = z * width + x;
int leftBottom = (z + 1) * width + x;
int rightBottom = (z + 1) * width + x + 1;
int rightTop = z * width + x + 1;
indices.add(leftTop);
indices.add(leftBottom);
indices.add(rightTop);
indices.add(rightTop);
indices.add(leftBottom);
indices.add(rightBottom);
}
}
}
float[] verticesArr = Utils.listToArray(positions);
float[] colorArr = new float[positions.size()];
for (int i = 0; i < colorArr.length; i += 3) {
colorArr[i] = (float) i / colorArr.length;
colorArr[i + 1] = (float) .25f;
colorArr[i + 2] = (float) 0;
}
int[] indicesArr = indices.stream().mapToInt((i) -> i).toArray();
float[] normalArr = calcNormals(verticesArr, width, height);
return new Mesh(verticesArr, colorArr, normalArr, indicesArr);
}
private static float[] calcNormals(float[] posArr, int width, int height) {
Vector3f v0 = new Vector3f();
Vector3f v1 = new Vector3f();
Vector3f v2 = new Vector3f();
Vector3f v3 = new Vector3f();
Vector3f v4 = new Vector3f();
Vector3f v12 = new Vector3f();
Vector3f v23 = new Vector3f();
Vector3f v34 = new Vector3f();
Vector3f v41 = new Vector3f();
List<Float> normals = new ArrayList<>();
Vector3f normal = new Vector3f();
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
if (row > 0 && row < height - 1 && col > 0 && col < width - 1) {
int i0 = row * width * 3 + col * 3;
v0.x = posArr[i0];
v0.y = posArr[i0 + 1];
v0.z = posArr[i0 + 2];
int i1 = row * width * 3 + (col - 1) * 3;
v1.x = posArr[i1];
v1.y = posArr[i1 + 1];
v1.z = posArr[i1 + 2];
v1 = v1.sub(v0);
int i2 = (row + 1) * width * 3 + col * 3;
v2.x = posArr[i2];
v2.y = posArr[i2 + 1];
v2.z = posArr[i2 + 2];
v2 = v2.sub(v0);
int i3 = (row) * width * 3 + (col + 1) * 3;
v3.x = posArr[i3];
v3.y = posArr[i3 + 1];
v3.z = posArr[i3 + 2];
v3 = v3.sub(v0);
int i4 = (row - 1) * width * 3 + col * 3;
v4.x = posArr[i4];
v4.y = posArr[i4 + 1];
v4.z = posArr[i4 + 2];
v4 = v4.sub(v0);
v1.cross(v2, v12);
v12.normalize();
v2.cross(v3, v23);
v23.normalize();
v3.cross(v4, v34);
v34.normalize();
v4.cross(v1, v41);
v41.normalize();
normal = v12.add(v23).add(v34).add(v41);
normal.normalize();
} else {
normal.x = 0;
normal.y = 1;
normal.z = 0;
}
normal.normalize();
normals.add(normal.x);
normals.add(normal.y);
normals.add(normal.z);
}
}
return Utils.listToArray(normals);
}
}
Wild guess: You're using 16bit indices but specify the size of the index buffer as if it were 8bit indices (by setting the size of the buffer to number of elements in the buffer)?
Judging from the screenshot, it clearly looks like only the first half is drawn, so I would assume the problem lies in the creation of the index buffer or the draw call.
Maybe you used the wrong number of indices in the draw call? Like you used the number of triangles instead? Or assumes the number for a triangle fan instead of triangles?
You'll have to post the actual draw call and generation of the buffer objects to get more information.
Or at least tag your question according to the rendering library you are using, as it is not plain OpenGL.