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.
I have a circle with these two methods in qt:
void MyGLWidget::drawCircle() {
int n = vertices.count();
qglColor(Qt::white);
glBegin(GL_POLYGON);
for(int i = 0; i < n; i++) {
glVertex2f(vertices[i].first, vertices[i].second);
}
glEnd();
}
void MyGLWidget::calculateVetices()
{
double a = 3.14 / 90;
vertices.append(QPair<double, double> (0,0));
for(int i = 0; i <= 360; i++) {
vertices.append(QPair<double, double> (cos(i * a) * radius, sin(i * a) * radius));
}
}
Now I want to get the current position of this circle. How can I do that?
I'm trying to draw a grid of triangles for the first part of my terrain mapping but there is a slight error and I'm not sure where I'm going wrong. Could someone please point out my error or explain how to correctly construct this grid.
To clarify, look at the right side of the grid, that shouldn't happen.
Vertices:
vector<Vertex> Terrain::generateVertices(int width, int height) {
vector<Vertex> vertices;
Vertex v;
float du = 1.0f / (width - 1);
float dv = 1.0f / (height - 1);
for (int r = 0; r < width; ++r) {
for (int c = 0; c < height; ++c) {
v.Pos = XMFLOAT3((float)c, (float)r, 0.0f);
v.Normal = XMFLOAT3(0.0f, 0.0f, 0.0f);
v.TextureCoordinate = XMFLOAT2(c * du, r * dv);
vertices.push_back(v);
}
}
return vertices;
}
Indices:
vector<WORD> Terrain::generateIndices(int width, int height) {
vector<WORD> indices;
for (int r = 0; r < width; ++r) {
for (int c = 0; c < height; ++c) {
indices.push_back(r * height + c);
indices.push_back(r * height + (c + 1));
indices.push_back((r + 1)*height + c);
indices.push_back((r + 1) * height + c);
indices.push_back((r * height + (c + 1)));
indices.push_back((r + 1) * height + (c + 1));
}
}
return indices;
}
Outcome:
When I draw a small grid, for example, 10x10, it comes out exactly how it should
When I draw a larger grid, 512x512 to cover my terrain, that's when the issues occur with the indices/vertices
Edit: I believe I have found the problem, but I'm not sure how to solve it. I can draw a grid up to 256x256, but anything over that will give me these graphical issues.
WORD is a 16-bit unsigned integer with a maximum value of 65535. With a 300x300 grid you have 90,000 vertices, so you can't index them all with a WORD.
I have implemented a tree data structure in which every node holds (recursivly) a list of pointers to it's children.
I am trying to calculate the (x,y) coordinates for visualizing the tree.
I went through this article:
http://gbook.org/projects/RadialTreeGraph.pdf
Cut I can't figure out how to gest past the first level, i.e This is what I have written so far:
for (int i = 0; i < GetDepth()+1; i++)
{
if (i == 0)
{
GetNodesInDepth(i).at(0)->SetXRadial(MIDDLE(m_nWidth));
GetNodesInDepth(i).at(0)->SetYRadial(MIDDLE(m_nHeight));
continue;
}
double dNodesInDepth = GetNodesInDepth(i).size();
double dAngleSpace = 2 * PI / dNodesInDepth;
for (int j = 0; j < dNodesInDepth; j++)
{
Node * pCurrentNode = GetNodesInDepth(i).at(j);
pCurrentNode->SetXRadial((SPACING * i) * qCos(j * dAngleSpace) + MIDDLE(m_nWidth));
pCurrentNode->SetYRadial((SPACING * i) * qSin(j * dAngleSpace) + MIDDLE(m_nHeight));
pCurrentNode->m_dAngle = dAngleSpace * j;
if (pCurrentNode->IsParent())
{
//..(I'm stuck here)..//
}
}
}
I am not sure how to calculate the limits, bisectors etc.
this is what my drawer did so far:
which is obviously not what i'm looking for since the second (0 based) level.
I have access to every info that I need in order to obtain what I'm looking for.
Probably by now you figured it out yourself. If not, here
double dNodesInDepth = GetNodesInDepth(i).size();
double dAngleSpace = 2 * PI / dNodesInDepth;
you're setting the angle space to PI (180 degreees) at your second level, as there are only two nodes at that level, dNodesInDepth = 2. That's why after drawing the node 20, the node 30 is 180 degrees away. That method would be fine for very dense trees because that angle will be small. But in your case you want to keep the angle as close as possible to the angle of the parent. So I suggest you get the angle of the parent for nodes at level 2 and higher, and spread the children so they have an angle space of sibilingAngle = min(dAngleSpace, PI/10). So the first child will have the exact angle of the parent, and the remaining children are sibilingAngle away from one another. You get the idea and probably come with a better method. I'm using min in case you have got too many nodes at that level you want to squeeze the nodes closer to each other.
The article you've linked to, uses a solution that is illustrated in Figure 2 – Tangent and bisector limits for directories. I don't like that method much because if you determine the absolute angle of the children rather than relative to the parent you can have a simpler/cleaner solution that does exactly what that method tries to do with so many operations.
Update:
The following code produces this image:
I think you can easily figure out how to center the child nodes and etc.
#include <cairo/cairo.h>
#include <math.h>
#include <vector>
using namespace std;
class Node {
public:
Node() {
parent = 0;
angle = 0;
angleRange = 2*M_PI;
depth = 0;
}
void addChildren(int n) {
for (int i=0; i<n; i++) {
Node* c = new Node;
c->parent = this;
c->depth = depth+1;
children.push_back(c);
}
}
vector<Node*> children;
float angle;
float angleRange;
Node* parent;
int depth;
int x, y;
};
void rotate(float x, float y, float angle, float& nx, float& ny) {
nx = x * cos(angle) - y * sin(angle);
ny = x * sin(angle) + y * cos(angle);
}
void draw(Node* root, cairo_t *cr) {
if (root->parent == 0) {
root->x = root->y = 300;
cairo_arc(cr, root->x, root->y, 3, 0, 2 * M_PI);
}
int n = root->children.size();
for (int i=0; i<root->children.size(); i++) {
root->children[i]->angle = root->angle + root->angleRange/n * i;
root->children[i]->angleRange = root->angleRange/n;
float x, y;
rotate(40 * root->children[i]->depth, 0, root->children[i]->angle, x, y);
root->children[i]->x = 300+x;
root->children[i]->y = 300+y;
cairo_move_to(cr, root->x, root->y);
cairo_line_to(cr, root->children[i]->x, root->children[i]->y);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_stroke(cr);
cairo_arc(cr, 300+x, 300+y, 3, 0, 2 * M_PI);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_stroke_preserve(cr);
cairo_set_source_rgb(cr, 0, 0, 0);
cairo_fill(cr);
draw(root->children[i], cr);
}
}
int main(void) {
Node root;
root.addChildren(4);
root.children[0]->addChildren(3);
root.children[0]->children[0]->addChildren(2);
root.children[1]->addChildren(5);
root.children[2]->addChildren(5);
root.children[2]->children[1]->addChildren(2);
root.children[2]->children[1]->children[1]->addChildren(2);
cairo_surface_t *surface;
cairo_t *cr;
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 600, 600);
cr = cairo_create(surface);
cairo_rectangle(cr, 0.0, 0.0, 600, 600);
cairo_set_source_rgb(cr, 1, 1, 1);
cairo_fill(cr);
cairo_set_line_width(cr, 2);
for (int i=0; i<6; i++) {
cairo_arc(cr, 300, 300, 40*i, 0, 2 * M_PI);
cairo_set_source_rgb(cr, .5, .5, .5);
cairo_stroke(cr);
}
draw(&root, cr);
cairo_surface_write_to_png(surface, "image.png");
cairo_destroy(cr);
cairo_surface_destroy(surface);
return 0;
}
Update 2:
Just to make it easier for you, here is how to center the nodes:
for (int i=0; i<root->children.size(); i++) {
float centerAdjust = 0;
if (root->parent != 0) {
centerAdjust = (-root->angleRange + root->angleRange / n) / 2;
}
root->children[i]->angle = root->angle + root->angleRange/n * i + centerAdjust;
root->children[i]->angleRange = root->angleRange/n;
Showing a more populated tree:
Here is an implementation of the algorithm from the article that should work (note: I didn't compile it since I don't have other parts of your program):
void Tree::CalculateAngles()
{
// IsEmpty() returns true if the tree is empty, false otherwise
if (!IsEmpty())
{
Node* pRoot = GetNodesInDepth(0).at(0);
pRoot->SetAngle(0);
// Relative to the current angle
pRoot->SetTangentLimit(PI);
// Absolute limit
pRoot->SetLowerBisector(-PI);
pRoot->SetHigherBisector(PI);
}
for (int depth = 1; depth < GetDepth() + 1; depth++)
{
double dDepth = (double)depth;
// The last non-leaf node in of the current depth (i.e. node with children)
Node* pPreviousNonleafNode = NULL;
// The first non-leaf node
Node* pFirstNonleafNode = NULL;
// The parent of the previous node
Node* pPreviousParent = NULL;
int indexInCurrentParent = 0;
double dTangentLimt = acos( dDepth / (dDepth + 1.0) );
for (int i = 0; i < GetNodesInDepth(depth).size(); i++)
{
Node* pCurrentNode = GetNodesInDepth(depth).at(i);
Node* pParent = pCurrentNode->GetParent();
if (pParent != pPreviousParent)
{
pPreviousParent = pParent;
indexInCurrentParent = 0;
}
// (GetMaxChildAngle() - GetMinChildAngle()) / GetChildCount()
double angleSpace = pParent->GetAngleSpace();
pCurrentNode->SetAngle(angleSpace * (indexInCurrentParent + 0.5));
pCurrentNode->SetTangentLimit(dTangentLimt);
if (pCurrentNode->IsParent())
{
if (!pPreviousNonleafNode)
{
pFirstNonleafNode = pCurrentNode;
}
else
{
double dBisector = (pPreviousNonleafNode->GetAngle() + pCurrentNode->GetAngle()) / 2.0;
pPreviousNonleafNode->SetHigherBisector(dBisector);
pCurrentNode->SetLowerBisector(dBisector);
}
pPreviousNonleafNode = pCurrentNode;
}
indexInCurrentParent++;
}
if (pPreviousNonleafNode && pFirstNonleafNode)
{
if (pPreviousNonleafNode == pFirstNonleafNode)
{
double dAngle = pFirstNonleafNode->GetAngle();
pFirstNonleafNode->SetLowerBisector(dAngle - PI);
pFirstNonleafNode->SetHigherBisector(dAngle + PI);
}
else
{
double dBisector = PI + (pPreviousNonleafNode->GetAngle() + pFirstNonleafNode->GetAngle()) / 2.0;
pFirstNonleafNode->SetLowerBisector(dBisector);
pPreviousNonleafNode->SetHigherBisector(dBisector);
}
}
}
}
void Tree::CalculatePositions()
{
for (int depth = 0; depth < GetDepth() + 1; depth++)
{
double redius = SPACING * depth;
for (int i = 0; i < GetNodesInDepth(depth).size(); i++)
{
Node* pCurrentNode = GetNodesInDepth(depth).at(i);
double angle = pCurrentNode->GetAngle();
pCurrentNode->SetXRadial(redius * qCos(angle) + MIDDLE(m_nWidth));
pCurrentNode->SetYRadial(redius * qSin(angle) + MIDDLE(m_nHeight));
}
}
}
void Tree::CalculateLayout ()
{
CalculateAngles();
CalculatePositions();
}
double Node::GetAngleSpace()
{
return (GetMaxChildAngle() - GetMinChildAngle()) / GetChildCount();
}
Note: I tried to mimic your code style so you won't have to refactor it to match other parts of your program.
P.S. If you spot any bugs, please notify me in the comments - I'll edit my answer.
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