OpenGL中实现天空顶(SkyDome)的类: CSkyDome

http://hi.baidu.com/codefish/blog/item/438e2f6e0e0865d980cb4a4f.html

 还是那句老话,自己动手丰衣足食!SkyDome在许多的书中都有提及,有的还提供了源代码,可以我就是喜欢自己的东西。拿上手术刀,对其进行了一番改造!

     OpenGL中实现天空的方法不少,如直接的,背景涂成蓝色;好点的,使用天空盒,可是寻找合适的贴图会把你累坏;较好的,我想还是使用天空顶吧(SkyDome)。当我为天空的效果感到无助的时候,在某处遇到了SkyDome,它可以实现我需要的效果。如可以均匀雾化,不会在某个点上有堆积;可以实现地平线上的过渡色,这一直是我想要的。你需要对SkyDome有一些了解,但是不需要了解具体的过程。我在程序中没有使用纹理贴在SkyDome上,而是另外创建了一个云层,这样的效果决定会比直接在SkyDome上贴图好,因为我还没有解决纹理不变形;况且独立的云层可以实现多种效果。废话少说,在我的程序中实现的天空顶的效果如图1,图2是加有云层的效果。后面是代码,希望可以作为您的参考。



#ifndef SKYDOME_H_
#define SKYDOME_H_

#ifndef PI
#define PI 3.1415926535897f
#endif

#ifndef DTOR
#define DTOR (PI/180.0f)
#endif

#ifndef SQR
#define SQR(x) (x*x)
#endif

typedef 
struct {
    
float x,y,z;
    unsigned 
int color;
    
float u, v;
    
int   flag;
}VERTEX_SKY;

class CSkyDome
{
    
public:
    CSkyDome();
    
~CSkyDome();

    
void GenerateDome(float radius, float dtheta, float dphi, float hTile, float vTile);
    
int RenderSkyDome(float ,float ,float);

    
protected:
    
void ReleaseDome(); 

    
private:
    VERTEX_SKY 
*Vertices;
    
int NumVertices;
    
float mY;
};
#endif

skydome.cpp
#include 
"stdafx.h"
#include 
<math.h>
#include 
"SkyDome.h"

CSkyDome::CSkyDome()
{
}
CSkyDome::
~CSkyDome()
{
    
//ReleaseDome();
}

void CSkyDome::GenerateDome(float radius, float dtheta, float dphi, float hTile, float vTile)
{
    
int theta, phi;
    
// Make sure our vertex array is clear
    /*if (Vertices) 
    {
       delete Vertices;
       Vertices = NULL;
       NumVertices = 0;
    }
*/

    
// Initialize our Vertex array
    NumVertices = (int)((360/dtheta)*(90/dphi)*4);
    Vertices 
= new VERTEX_SKY[NumVertices];
    ZeroMemory(Vertices, 
sizeof(VERTEX_SKY)*NumVertices);

    
// Used to calculate the UV coordinates
    float vx, vy, vz, mag;

    
// Generate the dome
    int n = 0;
    
for (phi=0; phi <= 90 - dphi; phi += (int)dphi)
    {
       
for (theta=0; theta <= 360 - dtheta; theta += (int)dtheta)
       {
            
// Calculate the vertex at phi, theta
            Vertices[n].x = radius * sinf(phi*DTOR) * cosf(DTOR*theta);
            Vertices[n].y 
= radius * sinf(phi*DTOR) * sinf(DTOR*theta);
            Vertices[n].z 
= radius * cosf(phi*DTOR);

            
// Create a vector from the origin to this vertex
            vx = Vertices[n].x;
            vy 
= Vertices[n].y;
            vz 
= Vertices[n].z;

            
// Normalize the vector
            mag = (float)sqrt(SQR(vx)+SQR(vy)+SQR(vz));
            vx 
/= mag;
            vy 
/= mag;
            vz 
/= mag;

            
// Calculate the spherical texture coordinates
            Vertices[n].u = hTile * (float)(atan2(vx, vz)/(PI*2)) + 0.5f;
            Vertices[n].v 
= vTile * (float)(asinf(vy) / PI) + 0.5f;  
            n
++;

            
// Calculate the vertex at phi+dphi, theta
            Vertices[n].x = radius * sinf((phi+dphi)*DTOR) * cosf(theta*DTOR);
            Vertices[n].y 
= radius * sinf((phi+dphi)*DTOR) * sinf(theta*DTOR);
            Vertices[n].z 
= radius * cosf((phi+dphi)*DTOR);
   
            
// Calculate the texture coordinates
            vx = Vertices[n].x;
            vy 
= Vertices[n].y;
            vz 
= Vertices[n].z;
            mag 
= (float)sqrt(SQR(vx)+SQR(vy)+SQR(vz));
            vx 
/= mag;
            vy 
/= mag;
            vz 
/= mag;
            Vertices[n].u 
= hTile * (float)(atan2(vx, vz)/(PI*2)) + 0.5f;
            Vertices[n].v 
= vTile * (float)(asinf(vy) / PI) + 0.5f;  
            n
++;

            
// Calculate the vertex at phi, theta+dtheta
            Vertices[n].x = radius * sinf(DTOR*phi) * cosf(DTOR*(theta+dtheta));
            Vertices[n].y 
= radius * sinf(DTOR*phi) * sinf(DTOR*(theta+dtheta));
            Vertices[n].z 
= radius * cosf(DTOR*phi);
       
            
// Calculate the texture coordinates
            vx = Vertices[n].x;
            vy 
= Vertices[n].y;
            vz 
= Vertices[n].z;
            mag 
= (float)sqrt(SQR(vx)+SQR(vy)+SQR(vz));
            vx 
/= mag;
            vy 
/= mag;
            vz 
/= mag;
            Vertices[n].u 
= hTile * (float)(atan2(vx, vz)/(PI*2)) + 0.5f;
            Vertices[n].v 
= vTile * (float)(asinf(vy) / PI) + 0.5f;  
            n
++;
            
if (phi > -90 && phi < 90)
            {
                 
// Calculate the vertex at phi+dphi, theta+dtheta
                 Vertices[n].x = radius * sinf((phi+dphi)*DTOR) * cosf(DTOR*(theta+dtheta));
                 Vertices[n].y 
= radius * sinf((phi+dphi)*DTOR) * sinf(DTOR*(theta+dtheta));
                 Vertices[n].z 
= radius * cosf((phi+dphi)*DTOR);
    
                 
// Calculate the texture coordinates
                 vx = Vertices[n].x;
                 vy 
= Vertices[n].y;
                 vz 
= Vertices[n].z;
                 mag 
= (float)sqrt(SQR(vx)+SQR(vy)+SQR(vz));
                 vx 
/= mag;
                 vy 
/= mag;
                 vz 
/= mag;
                 Vertices[n].u 
= hTile * (float)(atan2(vx, vz)/(PI*2)) + 0.5f;
                 Vertices[n].v 
= vTile * (float)(asinf(vy) / PI) + 0.5f;  
                 n
++;
            }
       }
    }

    
//得到最低点
    float minZ = Vertices[0].z;
    
for(int j=1;j<NumVertices;j++)
    {
       Vertices[j].flag 
= 0;
       
if(Vertices[j].z < minZ)    minZ = Vertices[j].z;
    }
    mY 
= minZ;

    
for(j=0;j<NumVertices;j++)
    {
       
if(Vertices[j].z == minZ)   Vertices[j].flag=1;
    }

    
// Fix the problem at the seam
    for (int i=0; i < NumVertices-3; i++)
    {
       
if (Vertices[i].u - Vertices[i+1].u > 0.9f)
        Vertices[i
+1].u += 1.0f;
       
if (Vertices[i+1].u - Vertices[i].u > 0.9f)
        Vertices[i].u 
+= 1.0f;
       
if (Vertices[i].u - Vertices[i+2].u > 0.9f)
        Vertices[i
+2].u += 1.0f;
       
if (Vertices[i+2].u - Vertices[i].u > 0.9f)
        Vertices[i].u 
+= 1.0f;
       
if (Vertices[i+1].u - Vertices[i+2].u > 0.9f)
        Vertices[i
+2].u += 1.0f;
       
if (Vertices[i+2].u - Vertices[i+1].u > 0.9f)
        Vertices[i
+1].u += 1.0f;
       
if (Vertices[i].v - Vertices[i+1].v > 0.8f)
        Vertices[i
+1].v += 1.0f;
       
if (Vertices[i+1].v - Vertices[i].v > 0.8f)
        Vertices[i].v 
+= 1.0f;
       
if (Vertices[i].v - Vertices[i+2].v > 0.8f)
        Vertices[i
+2].v += 1.0f;
       
if (Vertices[i+2].v - Vertices[i].v > 0.8f)
        Vertices[i].v 
+= 1.0f;
       
if (Vertices[i+1].v - Vertices[i+2].v > 0.8f)
        Vertices[i
+2].v += 1.0f;
       
if (Vertices[i+2].v - Vertices[i+1].v > 0.8f)
        Vertices[i
+1].v += 1.0f;
    }
    }

int CSkyDome::RenderSkyDome(float x,float y,float z)
{
    glPushMatrix();
    
//glTranslatef(0.0f, -100.0f, 0.0f);
    glTranslatef(x, y-100, z);
    
//glRotatef(timeGetTime()/2000.0f,0.0f, 1.0f, 0.0f);
    glRotatef(2701.0f0.0f0.0f);

    glColor4f(
1,1,1,1);
    glBegin(GL_TRIANGLE_STRIP);

    
//glBegin(GL_LINE_STRIP);
    for (int i=0; i < NumVertices; i++)
    {
       
if(Vertices[i].flag==1//最后一圈顶点
        
//glColor3f(0.9f,0.9f,1.0f);
        glColor3f(0.95f,0.95f,1.0f);
       
else
        
//glColor3f(0.5f, 0.7f, 0.8f);
        glColor3f(0.2f0.5f1.0f);  
  
       glTexCoord2f(Vertices[i].u, Vertices[i].v);
       glVertex3f(Vertices[i].x, Vertices[i].y, Vertices[i].z);
    }
    glEnd();

    
//闭合底部
    glColor3f(0.9f,0.9f,1.0f);
    glBegin(GL_POLYGON);
    
for(i=0;i<NumVertices;i++)
    {
       
if(Vertices[i].flag == 1)
       {
        glTexCoord2f(Vertices[i].u, Vertices[i].v);
        glVertex3f(Vertices[i].x, Vertices[i].y, Vertices[i].z);
       }
    }
    glEnd();

    glPopMatrix();
    
return 1;
}

void CSkyDome::ReleaseDome()
{
    
if (Vertices)
    {
       delete Vertices;
       Vertices 
= NULL;
    }
}

 

posted @ 2009-08-31 14:02  Revive and Strive  阅读(4001)  评论(0编辑  收藏  举报