将 Triton 与地形和浅水相结合
如果你的应用包括地形以及开放的海洋,有几种方法可以在海岸线取得良好的效果。
最好的方法是向Triton提供地形的高度图,其中包括测深数据。如果使用Triton::Environment::SetHeightMap()提供一个高度图,水在海岸附近将自动变得更加透明,波浪将被减弱以减少任何深度精度的伪影。注意只在高度贴图发生变化时才调用SetHeightMap;Triton需要将纹理复制到系统内存中,而你并不想每一帧都这样做。请确保在创建海洋对象时启用破浪标志,以充分利用高度图的数据。
如果你已经提供了一个有效的高度图,你也可以使用Triton::Environment::SetBreakingWavesParameters()来模拟海浪在海岸线上的破裂。这将产生高波长的海浪,当它们接近海岸线时,海浪的速度会减慢,并带有泡沫和位移效果。从空中看,它们看起来很不错,但是由于性能的原因,海浪在破碎时不会真正地卷曲在自己身上并产生水雾颗粒。你需要指定世界对当地海岸线的方向,这样海浪就会沿着正确的方向前进;一般来说,你把其他参数设置为默认值就可以了。重要的是,你在高度图中的水深数据是真实的;当水变得越来越浅时,海浪就会开始出现,真实的深度信息将导致海浪出现在离岸边适当的距离,并遵循海岸线的轮廓。
除了浮点高度地图纹理,Triton::Environment::SetHeightMap()还需要一个矩阵来将世界坐标转换为纹理坐标。下面是一个计算这个矩阵并使用OpenGL创建适当格式的高度地图纹理的例子;它创建了一个正交投影,从10000米的高度俯视整个地形,坐标系中Y是 "向上",地形的范围从(minX,minZ)到(maxX,maxZ)。
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &heightMap);
glBindTexture(GL_TEXTURE_2D, heightMap);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE32F_ARB, HEIGHT_MAP_DIM, HEIGHT_MAP_DIM, 0, GL_LUMINANCE, GL_FLOAT, (void*)heightData);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glLoadIdentity();
const GLdouble bias[16] = {
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0};
glLoadMatrixd(bias);
double xrange = maxX - minX;
double zrange = maxZ - minZ;
glOrtho(-(xrange * 0.5), xrange * 0.5, -(zrange * 0.5), zrange * 0.5, -1.0, 1.0);
double eyex = minX + xrange * 0.5;
double eyey = 10000.0;
double eyez = minZ + zrange * 0.5;
double centerx = eyex;
double centery = 0;
double centerz = eyez;
double upx = 0;
double upz = -1.0;
double upy = 0;
gluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz);
glGetDoublev(GL_TEXTURE_MATRIX, heightMapMatrix);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
然后你会像这样把产生的高度贴图纹理和矩阵传递给Triton:
tritonEnvironment->SetHeightMap((Triton::TextureHandle)heightMap, Triton::Matrix4(heightMapMatrix));
DirectX9用户应该参考Triton::Envrionment::SetHeightMap()的文档,以了解关于Triton期望的纹理类型的重要信息。
OpenSceneGraph用户可以参考SDK中的OSGDynamicHeightMap样本。这个样本从摄像机周围的场景中自动生成一个高度图,并将其反馈给Triton以实现平滑的海岸线混合。这个样本还包括一个顶点程序的代码,可以为地心或ECEF地形计算出精确的高度图数据。
如果你的地形没有可用的高度图,如果你的相机在海岸线附近,一定要调用Triton::Ocean::SetDepth()。这个方法允许你指定摄像机位置的海底深度和表面法线。在浅水区,这个信息被用来使海岸附近的海浪更加明显,并使海岸线附近的水更加透明。如果你的地形包括在水面下延伸到近海一段距离的纹理几何体,你的海底会影响海岸附近的海洋颜色。我们网站提供的Triton演示程序说明了启用 "海滩 "复选框时的这种效果。
对于处理没有高度地图的水/陆边界,最简单的方法是依靠深度缓冲区。你需要确保你的深度缓冲区有足够的精度,这样才能很好地工作。如果你的系统支持的话,使用32位的深度缓冲器,并确保你的近景和远景剪辑平面设置得尽可能接近。如果深度缓冲区的精度问题在远处是个问题,你也可以使用Triton::Ocean::SetDepthOffset()方法来强制水的深度值更接近摄像机。一般来说,0.01的值似乎可以让事情变得清晰。
如果你有一个深度缓冲区的副本,其中包括地形,但不包括海卫一的水,你也可以看看Triton::Environment::SetDepthMap()方法,作为SetHeightMap()的替代。然而,这个方法有几个注意事项,最好使用SetHeightMap()。
如果你现有的地形数据库包括海洋表面的几何图形,你可能最好使用Triton::Ocean::SetPatchShader()将Triton的着色器应用到你现有的水面几何图形上。同样的技术可以用来渲染较小的水体,而不是由Triton::Ocean::Draw()渲染的无限大的海洋。更多信息请参见渲染用户定义的几何体斑块。
如果你的地形包括低于模拟海平面的陆地区域,你将需要防止Triton在这些区域渲染海浪。一个简单的解决方案是在向模版缓冲区写入时渲染你的地形,然后在调用Triton::Ocean::Draw()时启用模版测试。或者,使用Triton::Ocean::SetPatchShader()和你自己的水网,对场景中水的渲染位置进行更多选择。另一个解决方案是一种叫做 "深度遮蔽 "的技术,在绘制海洋之前,在你希望保持无水的海平面以下区域绘制一个透明的多边形,但要写上深度。例如,深度遮蔽是防止水出现在船体内部的一个好方法。
你可以用Triton::Environment::SetSeaLevel()来调整Triton的海平面。
渝公网安备50010702505508