Generar un plano con tiras triangulares
¿Cuál sería el mejor algoritmo para generar una lista de vértices para dibujar un plano usando tiras triangulares?
Estoy buscando una función que reciba el ancho y alto del plano y devuelva una matriz flotante que contenga vértices correctamente indexados.
Width representa el número de vértices por fila.
Height representa el número de vértices por columna.
float* getVertices( int width, int height ) {
...
}
void render() {
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, getVertices(width,heigth));
glDrawArrays(GL_TRIANGLE_STRIP, 0, width*height);
glDisableClientState(GL_VERTEX_ARRAY);
}
4 answers
Gracias a todos. He codificado esto. Es correcto? ¿O es la tira generada de alguna manera incorrecta?
int width;
int height;
float* vertices = 0;
int* indices = 0;
int getVerticesCount( int width, int height ) {
return width * height * 3;
}
int getIndicesCount( int width, int height ) {
return (width*height) + (width-1)*(height-2);
}
float* getVertices( int width, int height ) {
if ( vertices ) return vertices;
vertices = new float[ getVerticesCount( width, height ) ];
int i = 0;
for ( int row=0; row<height; row++ ) {
for ( int col=0; col<width; col++ ) {
vertices[i++] = (float) col;
vertices[i++] = 0.0f;
vertices[i++] = (float) row;
}
}
return vertices;
}
int* getIndices( int width, int height ) {
if ( indices ) return indices;
indices = new int[ iSize ];
int i = 0;
for ( int row=0; row<height-1; row++ ) {
if ( (row&1)==0 ) { // even rows
for ( int col=0; col<width; col++ ) {
indices[i++] = col + row * width;
indices[i++] = col + (row+1) * width;
}
} else { // odd rows
for ( int col=width-1; col>0; col-- ) {
indices[i++] = col + (row+1) * width;
indices[i++] = col - 1 + + row * width;
}
}
}
if ( (mHeight&1) && mHeight>2 ) {
mpIndices[i++] = (mHeight-1) * mWidth;
}
return indices;
}
void render() {
glEnableClientState( GL_VERTEX_ARRAY );
glVertexPointer( 3, GL_FLOAT, 0, getVertices(width,height) );
glDrawElements( GL_TRIANGLE_STRIP, getIndicesCount(width,height), GL_UNSIGNED_INT, getIndices(width,height) );
glDisableClientState( GL_VERTEX_ARRAY );
}
Con width = 4 y height = 4 esto es lo que tengo:
Y aquí estoy modificando alguna altura de vértice:
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-28 10:35:47
Aquí hay un código que hace esto (no probado, pero al menos tienes la idea):
void make_plane(int rows, int columns, float *vertices, int *indices) {
// Set up vertices
for (int r = 0; r < rows; ++r) {
for (int c = 0; c < columns; ++c) {
int index = r*columns + c;
vertices[3*index + 0] = (float) c;
vertices[3*index + 1] = (float) r;
vertices[3*index + 2] = 0.0f;
}
}
// Set up indices
int i = 0;
for (int r = 0; r < rows - 1; ++r) {
indices[i++] = r * columns;
for (int c = 0; c < columns; ++c) {
indices[i++] = r * columns + c;
indices[i++] = (r + 1) * columns + c;
}
indices[i++] = (r + 1) * columns + (columns - 1);
}
}
El primer bucle establece la matriz de vértices en una cuadrícula rectangular estándar. Hay vértices R * C.
El segundo bucle establece los índices. En general, hay dos vértices por cuadrado en la cuadrícula. Cada vértice hará que se dibuje un nuevo triángulo (con los dos vértices anteriores), por lo que cada cuadrado se dibuja con dos triángulos.
El primer y último vértice al principio y al final de cada fila está duplicada. Esto significa que hay dos triángulos de área cero (triángulos degenerados) entre cada fila. Esto nos permite dibujar toda la cuadrícula en una gran franja triangular. Esta técnica se llama costura.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-06 22:31:15
Ninguno de los códigos anteriores da una generación de malla correcta. Un muy buen artículo sobre cómo hacer una tira de triángulos en un plano simple: http://www.learnopengles.com/android-lesson-eight-an-introduction-to-index-buffer-objects-ibos/
Aquí está mi código de prueba que realmente probó y funciona completamente:
int plane_width = 4; // amount of columns
int plane_height = 2; // amount of rows
int total_vertices = (plane_width + 1) * (plane_height + 1);
planeVert = new CIwFVec2[total_vertices];
memset(planeVert, 0, sizeof(CIwFVec2) * total_vertices);
int numIndPerRow = plane_width * 2 + 2;
int numIndDegensReq = (plane_height - 1) * 2;
int total_indices = numIndPerRow * plane_height + numIndDegensReq;
planeInd = new uint16[total_indices];
make_plane(plane_width, plane_height, planeVert, planeInd);
...
void make_plane(int width, int height, CIwFVec2 *vertices, uint16 *indices)
{
width++;
height++;
int size = sizeof(CIwFVec2);
// Set up vertices
for(int y = 0; y < height; y++)
{
int base = y * width;
for(int x = 0; x < width; x++)
{
int index = base + x;
CIwFVec2 *v = vertices + index;
v->x = (float) x;
v->y = (float) y;
Debug::PrintDebug("%d: %f, %f", index, v->x, v->y);
}
}
Debug::PrintDebug("-------------------------");
// Set up indices
int i = 0;
height--;
for(int y = 0; y < height; y++)
{
int base = y * width;
//indices[i++] = (uint16)base;
for(int x = 0; x < width; x++)
{
indices[i++] = (uint16)(base + x);
indices[i++] = (uint16)(base + width + x);
}
// add a degenerate triangle (except in a last row)
if(y < height - 1)
{
indices[i++] = (uint16)((y + 1) * width + (width - 1));
indices[i++] = (uint16)((y + 1) * width);
}
}
for(int ind=0; ind < i; ind++)
Debug::PrintDebug("%d ", indices[ind]);
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-09 03:18:30
Estaba haciendo algo similar y usando las dos primeras respuestas se me ocurrió esto (tested, C#, XNA)
// center x,z on origin
float offset = worldSize / 2.0f, scale = worldSize / (float)vSize;
// create local vertices
VertexPositionColor[] vertices = new VertexPositionColor[vSize * vSize];
for (uint z = 0; z < vSize; z++) {
for (uint x = 0; x < vSize; x++) {
uint index = x + (z * vSize);
vertices[index].Position = new Vector3((scale*(float)x) - offset,
heightValue,
(scale*(float)z) - offset);
vertices[index].Color = Color.White;
}
}
// create local indices
var indices = new System.Collections.Generic.List<IndexType>();
for (int z = 0; z < vSize - 1; z++) {
// degenerate index on non-first row
if (z != 0) indices.Add((IndexType)(z * vSize));
// main strip
for (int x = 0; x < vSize; x++) {
indices.Add((IndexType)(z * vSize + x));
indices.Add((IndexType)((z + 1) * vSize + x));
}
// degenerate index on non-last row
if (z != (vSize-2)) indices.Add((IndexType)((z + 1) * vSize + (vSize - 1)));
}
Esto es fácilmente convertible a c++, simplemente haga indices
un vector std::.
Las características notables de mi solución son que: a) No es necesario cambiar el orden de bobinado por substrip - agregar dos puntos crea dos triángulos degenerados, por lo que el orden es correcto para la siguiente substrip. b) Debe agregar condicionalmente el primer y el último vértice del triángulo dg.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-09-12 18:27:45