Jonny Bliss
Jonny Bliss

Reputation: 21

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++.

Curved surface shown here

Curved surface shown here in another view

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.

Upvotes: 1

Views: 64

Answers (1)

Summit
Summit

Reputation: 2268

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;
    }   
}

Upvotes: 2

Related Questions