2015-03-30 85 views
-2

我想使用三角形和细分模拟椭球体。 下面的代码,从OpenGL的编程指南,车型范围引用,但我不知道我怎么能修改此为椭圆体轴线对齐的椭球如何使用多边形在opengl中模拟椭球体

#define X .525731112119133606 
#define Z .850650808352039932 
static GLfloat vdata[12][3] = { 
  { -X, 0.0, Z }, { X, 0.0, Z }, { -X, 0.0, -Z }, { X, 0.0, -Z }, 
  { 0.0, Z, X }, { 0.0, Z, -X }, { 0.0, -Z, X }, { 0.0, -Z, -X }, 
  { Z, X, 0.0 }, { -Z, X, 0.0 }, { Z, -X, 0.0 }, { -Z, -X, 0.0 } 
}; 
static GLuint tindices[20][3] = { 
{ 1, 4, 0 }, { 4, 9, 0 }, { 4, 5, 9 }, { 8, 5, 4 }, { 1, 8, 4 }, 
 { 1, 10, 8 }, { 10, 3, 8 }, { 8, 3, 5 }, { 3, 2, 5 }, { 3, 7, 2 }, 
 { 3, 10, 7 }, { 10, 6, 7 }, { 6, 11, 7 }, { 6, 0, 11 }, { 6, 1, 0 }, 
 { 10, 1, 6 }, { 11, 0, 9 }, { 2, 11, 9 }, { 5, 2, 9 }, { 11, 2, 7 }, 
}; 

//draws triangle at the specified coordinate 
void drawtriangle(float *v1, float *v2, float *v3){ 
    printf("v1 = %f, v3 = %f,v3 = %f\n", *v1, *v2, *v3); 
    glBegin(GL_TRIANGLES); 
     glNormal3fv(v1); 
     glVertex3fv(v1); 
     glNormal3fv(v2); 
     glVertex3fv(v2); 
     glNormal3fv(v3); 
     glVertex3fv(v3); 
    glEnd(); 
} 
void normalize(float v[3]){ 
    GLfloat d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 
    if (d == 0.0){ 
     printf("zero length vector\n"); 
     return; 
    } 
    v[0] /= d; 
    v[1] /= d; 
    v[2] /= d; 
} 

void subdivide(float *v1, float *v2, float *v3, long depth){ 
    GLfloat v12[3], v23[3], v31[3]; 
    GLint i; 

    //end recursion 
    if (depth == 0){ 
     drawtriangle(v1, v2, v3); 
     return; 
    } 
    for (i = 0; i < 3; i++){ 
     v12[i] = (v1[i] + v2[i])/2.0; 
     v23[i] = (v2[i] + v3[i])/2.0; 
     v31[i] = (v3[i] + v1[i])/2.0; 
    } 

    normalize(v12); 
    normalize(v23); 
    normalize(v31); 
    subdivide(v1, v12, v31, depth - 1); 
    subdivide(v2, v23, v12, depth - 1); 
    subdivide(v3, v31, v23, depth - 1); 
    subdivide(v12, v23, v31, depth - 1); 
} 

void display(void){ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    glShadeModel(GL_FLAT); 
    glRotatef(300.0, 0.5, 1.0, 0.5); 

    for (int i = 0; i < 20; i++){ 
     subdivide(&vdata[tindices[i][0]][0], &vdata[tindices[i][1]][0], &vdata[tindices[i][2]][0], 1); 
    } 

    glFlush(); 
} 

回答

3

只要建模,它并不比困难得多领域。你有计算单位球体上的顶点的代码。对于具有半径r球体,你乘那些单元球点(vx, vy, vz)与半径:

sx = r * vx 
sy = r * vy 
sz = r * vz 

椭球是一个一般化,其中在3个坐标方向半径可以是不同的。随着3个半径rxry,并且rz的点,然后计算公式为:

sx = rx * vx 
sy = ry * vy 
sz = rz * vz 

它变得稍微更有趣与法线。球体具有位置和法向矢量相同的便利特性。这不适用于椭球。对于法线,您必须除以相应的半径(数学背景请参见normal matrix for non uniform scaling)。所以对于椭球法线的计算公式为:

nx = vx/rx 
ny = vy/ry 
nz = vz/rz 

以适应最小的变化代码这一点,你可以改变drawtriangle()功能:

glBegin(GL_TRIANGLES); 
glNormal3f(v1[0]/rx, v1[1]/ry, v1[2]/rz); 
glVertex3f(v1[0] * rx, v1[1] * ry, v1[2] * rz); 
glNormal3f(v2[0]/rx, v2[1]/ry, v2[2]/rz); 
glVertex3f(v2[0] * rx, v2[1] * ry, v2[2] * rz); 
glNormal3f(v3[0]/rx, v3[1]/ry, v3[2]/rz); 
glVertex3f(v3[0] * rx, v3[1] * ry, v3[2] * rz); 
glEnd(); 

这些计算,正常的载体将一般不再标准化。你可以问的OpenGL加入这个调用初始化代码正常化他们为你:

glEnable(GL_NORMALIZE); 

如果你关心性能可言,计算要渲染一个球体将是非常低效的每个时间点。您将需要计算一次,然后将它们存储起来进行渲染。当你在它的时候,你可以将它们存储在一个顶点缓冲区中,并摆脱即时模式渲染。