Reputation: 21
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.
Upvotes: 1
Views: 64
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