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);
}
Author: user1118321, 2011-05-06

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: introduzca la descripción de la imagen aquí

Y aquí estoy modificando alguna altura de vértice: introduzca la descripción de la imagen aquí

 26
Author: NIGO,
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.

 14
Author: Jay Conrod,
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]);
}
 6
Author: Dima,
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.

 1
Author: Justicle,
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