system: [SYSTEM]

user: 2. 云场景生成算法 2.1. 云场景建模 Diamond-Square算法又称正方形–正方形细分法，可以用来生成云彩、山脉等自然景物。算法描述如下: (a) 在一平面上划分为n×n正方形网格，四个角点的高度(已知)用A，B，C，D表示，图1划分为4 × 4的正方形网格。 (b)计算正方形对角线交点M的高度值：取4个角点的高度平均值，作为中点M的高度。 (c) 计算正方形每条边中点的高度：根据A，B，M点和正方形外一点(高度值任意)，取平均得到AB边中点E的高度；根据B，C，M点和正方形外一点(高度任意)，取平均得到BC边中点F的高度；根据C，D，M点和正方形外一点(高度值任意)，取平均得到CD边中点G的高度；根据A，D，M点正方形外一点(高度值任意)，取平均得到AD边中点H的高度。 (d) 将n × n的正方形细分为四个n/2 × n/2小正方形，重复(b)、(c)步骤。 (e)递归步骤(d)，使其正方形网格不断细化，直至达到递归深度。 图1. Diamond-Square算法 Diamond-Square算法生成矩形域上的高度数据，存放在一高维数组内，这些数据并不能表示云彩。要把高度值转换为颜色值，如用最小数值代表最蓝，最大值代表最白，才能显示出云彩图像(图2)，从图2可以看出，直接映射生成的云彩图像与自然界中真实的云彩差别很大。 图2. Diamond-Square算法建立的云彩模型 2.2. 云场景生成 上述模型还需要天空建模、纹理映射和雾化等操作才能得到真实感的云场景，这些操作用OpenGL编程实现。 2.2.1. 天空模型 自然界的天空看上去是一个苍穹，像个半球笼罩在地面上。用数学中的球面方程得到球上各个顶点坐标并存储于Vertices [i]数组。通过OpenGL的三角形条带(GL_TRIANGLE_STRIP)方式，下面代码可以建立天空模型 [ 7 ] 。 glBegin(GL_TRIANGLE_STRIP); for(i=0;i { if(Vertices[i].flag==1) //最后一圈顶点 glColor3f(0.95f，0.95f，1.0f); else glColor3f(0.2f，0.5f，1.0f); glTexCoord2f(Vertices[i].u， Vertices[i].v); //u， v 纹理坐标 glVertex3f(Vertices[i].x， Vertices[i].y， Vertices[i].z)};// x，y，z球面图形坐标 } glEnd(); //闭合底部 glBegin(GL_POLYGON); for(i=0;i { If (Vertices[i].flag==1) { glTexCoord2f(Vertices[i].u， Vertices[i].v); glVertex3f(Vertices[i].x， Vertices[i].y， Vertices[i].z); } } glEnd(); 2.2.2. 云彩纹理映射 纹理映射过程是把图片(或者说纹理)映射到3D模型的一个或多个面上，纹理可以是任何图片。使用纹理映射可以增加云场景的真实感。在2.1节，用Diamond-Square算法已生成一个云彩模型，现在，通过使用OpenGL的纹理映射功能将矩形域上的高度数据映射为真实感的云彩，使云彩的视觉效果更加真实。设Cloud为纹理图像的指针，用下面的语句可以完成纹理映射过程。 //启用2D纹理 glEnable (GL_TEXTURE_2D); m_textureOne =newCTargaImage; //加载纹理图像 if(!m_textureOne->Load (Cloud.tga)) returnfalse; //创建纹理对象 glGenTextures (1， &m_textureObjectOne); //绑定纹理对象 glBindTexture (GL_TEXTURE_2D， mtextureObjectOne); //设定缩放器的过滤参数 glTexParameteri (GL_TEXTURE_2D， GL_TEXTURE_MAG_FILTER， GL_LINEAR); glTexParameteri (GL_TEXTURE2D， GL_TEXTUREMIN_FILTER， GL_LINEAR); //为纹理对象指定纹理图像数据 glTExImage2D (GL_TEXTURE_2D， 0， GL_RGB， m_textureOne->GetWidth()，0， GL_RGB， GL_UNSIGNED_BYTE， m_textureOne->GetImage()); 2.2.3. 雾化 雾化可以使云场景更为真实，远处的云彩产生朦胧的效果，从而使云彩看起来更加自然。在OpenGL中，雾化处理需要指定雾的属性，包括雾的颜色、强度、远近、雾化效果等，这些可以通过系列雾化函数glFog*()来设置。本文要实现具有深度感的雾化效果，将雾化效果模式默认设置为GL_LINEAR，雾的颜色设置为白色。 GLfloat fog_color[ 4 ]={1.0f， 1.0f， 1.0f， 1.0f}；//雾色为白色 glEnable(GL_FOG);//启动雾化效果 glFogf( GL_FOG_MODE， GL_LINEAR);//设置雾为深度感效果 glFogf(GL_FOG_DENSITY．0.6f);//设置雾浓度 glFogf( GL_FOG_COLOR， fog_color); //设置雾色 glFogf( GL_FOG_START， 10.0); //设置雾化效果起始距离 glFogf( GL_FOG_END， 20.0); //设置雾化效果结束距离 2.2.4. 光照模型设定 自然界中，云彩效果和光照强度、光源位置和材质的关系非常密切，光照强度可以改变云彩的温度，影响云彩的颜色和密度。环境光的特点是没有方向性，可以照射到全部空间；散射光一般来源于某个特定方向，从物体表面向各个方向反射，与太阳光比较接近，本文采用散射光来代替太阳光。光照效果主要有一下几个因素决定： Ø 光源种类 环境光设置： GLfloat ambientLight[ ]={0.8f， 0.3f， 0.3f， 1.0f };//光的颜色为偏红色 glLightfv(LIGHT0， GL_AMBIENT， ambientLight); 其中，LIGHT0是OpenGL提供的八种光源之一，默认情况下提供温和的白光；GL_AMBIENT是环境光强度；如果模拟一个晴朗的天空和白云，需要将ambientLight[ ]设为{1. 0f， 1. 0f， 1. 0f， 1. 0f}；如果模拟晚霞，则将环境光设置为偏红，ambientLight[ ]可以为{0.8f， 0.3f， 0.3f， 1.0f}或相近数值。 散射光设置： GLfloat diffuseLight[ ]={1.0f， 1.0f， 1.0f， 1.0f }; glLightfv(LIGHT0， GL_DIFFUSE， diffuseLight); 其中GL_DIFFUSE是散射光的强度；本文用散射光代替太阳光，diffuseLight[ ]始终取为{1.0f， 1.0f， 1.0f， 1.0f}。 Ø 光源位置 光源的位置和发光方向由下面两行代码设定： GLfloat lightPosition[ ]={0.0f， 0.0f， 1.0f， 0.0f}; glLightfv(LIGHT0， GL_POSITION， lightPosition); 其中GL_POSITION表示光源位置，由四个值(X， Y， Z， W)表示。如果第四个值W为零，则表示该光源位于无限远处，前三个值表示了它所在的方向。这种光源称为方向性光源，通常，太阳可以近似的被认为是方向性光源。如果第四个值W不为零，则X/W， Y/W， Z/W表示了光源的位置。这种光源称为位置性光源。文中选取lightPosition[ ]={0.0f， 1.0f， 0.0f， 0.0f}，即定义了一个来自于y轴正方向的方向性光源。 Ø 材质的选定 为云彩模型的正面设置环境光和散射光的材质属性： glMaterialfv(GL_FRONT， GL_DIFFUSE， matDiff)； glMaterialfv(GL_FRONT， GL_AMBIENT， matAmbient)； 其中GL_FRONT表示云彩模型的正面，matDiff[ ]={1.0f， 1.0f， 1.0f， 1.0f}和matAmbient[ ]={1.0f， 1.0f， 1.0f， 1.0f}表示散射光和环境光中的红、绿、蓝分量将全部被表面反射，即反射白光。 2.2.5. 三维图形变换 现实中风场的变化会影响云团走向及形状，云团形状时刻变化，有时分裂有时聚集。还有许多其它因素影响云彩的形态，比如云团内部微粒间的相互作用。本文只考虑外界因素的影响，将云团运动看作是整体运动，通过系列三维图形变换(平移、旋转、缩放和投影)，模拟云彩动态效果。调用函数glTranslatef (x， y， z)，其中x、y和z分别表示沿坐标轴移动的数值。本文取x轴方向平移值为−1~1之间，y和z轴方向平移值均为0。用表达式x = x ± 0.0001控制云彩沿x轴方向移动的速度，从而获得到云彩水平方向移动的动态效果。