11

电脑游戏如何渲染它们的地盘?我将使用几何高度图(尽管我稍后会对其进行优化)但我想知道最好的技术是什么,例如,“绘制”我的地面;到处都是草,到处都是土路,城镇内的砾石,以及每种材料之间的平滑过渡。

我只使用一个巨大的预烘焙纹理吗?当我可以平铺现有纹理时,这似乎非常低效。那么我是否为每个现有纹理使用一个巨大的 alpha 贴图?从理论上讲,这对我来说听起来不错,但我实际上该如何去做,后果是什么?我真的不知道从哪里开始,而且我的 Google 搜索也不是很有效。

我宁愿不必将纹理“捕捉”到网格(即空间(0,0)是草,空间(0,2)是泥土,空间(0,1)是草土过渡);我宁愿能够随意画,这样看起来更有说服力。当然,这将是一种简单的方法,但它在图形质量和“真实感”方面的牺牲太大了。

我主要只是在这里寻找理论和选择。我正在使用 OpenGL,所以如果你能提供关于 OpenGL 做事方式的提示,以及我可能从未听说过的功能,那就太好了。

只是为了澄清,Oblivion 是我正在寻找的一个很好的参考。我不知道地面的几何形状如何(高度图、静态 3D 模型等),但它们的地形具有不同的地面类型和它们之间的平滑过渡,就像我在说的那样。这是一个示例图像,请注意鹅卵石如何融入草丛中,不切实际但平滑:http ://www.elitistsnob.com/images/Oblivion%202006-05-21%2008-38-25-15.jpg

另外,我想我在一本 Game Programming Gems 书籍中读到了这一点,但当时我并没有太在意它,现在是夏天,我无法访问我大学的图书馆查看!我现在正在寻找目录,如果找到了会进行编辑,但直到 8 月中旬我仍然无法阅读它。

编辑:啊,伙计,Game Programming Gems 7 有一个第 5.8 章,标题为“为户外地形渲染映射大型纹理”,这听起来正是我所需要的,但我的 U 图书馆甚至没有那本书!我在其他 Game Programming Gems 书籍中找不到与此完全相同的内容,尽管有几本有一些地形几何文章。

4

6 回答 6

10

我最近在 OpenGL 中编写了一个小型地形渲染引擎,它的功能与您所说的类似。我使用的技术最好描述为纹理飞溅

我使用五种纹理来实现这一点。其中四个纹理是细节纹理:草、岩石、水和沙子。这些纹理是较小的 512x512 纹理,它们在地形上平铺。第五个纹理是混合贴图。mixmap 是一个覆盖整个地形的巨大纹理,在我的例子中是 4096x4096。

混合地图

此混合图使用所有 4 个颜色通道 (r,g,b,a) 来描述要在该特定位置显示多少细节纹理。我使用红色通道来确定沙子的不透明程度,绿色代表草,蓝色代表水,alpha 代表岩石。这个混合图是根据初始化时的高度图计算出来的,我使用高度来确定这些值。例如,靠近海平面,我最想要水,所以我在蓝色通道中设置高值,在其他通道中设置低值。当我进入山的更高处时,我将 alpha 颜色通道设置为较高的值,因为我想要大量的岩石纹理,但我将所有其他颜色通道设置为较低的值。

片段着色器

然后将此混合贴图用于片段着色器,在其中我获取混合贴图的这些颜色通道并使用它们来组合细节纹理。这是我用于片段着色器的 GLSL 代码:

uniform sampler2D alpha;
uniform sampler2D grass;
uniform sampler2D water;
uniform sampler2D rock;
uniform sampler2D sand;
uniform float texscale;

varying vec3 normal, lightDir ;

void main()
{
   // Get the color information
   vec3 alpha    = texture2D( alpha, gl_TexCoord[0].st ).rgb;
   vec3 texSand  = texture2D( sand, gl_TexCoord[0].st * texscale ).rgb;
   vec3 texGrass = texture2D( grass,  gl_TexCoord[0].st * texscale ).rgb;
   vec3 texWater = texture2D( water, gl_TexCoord[0].st * texscale ).rgb;
   vec3 texRock  = texture2D( rock,  gl_TexCoord[0].st * texscale ).rgb;

   // Mix the colors together
   texSand *= mixmap.r;
   texGrass = mix(texSand,  texGrass, mixmap.g);
   texWater = mix(texGrass, texWater, mixmap.b);
   vec3 tx  = mix(texWater, texRock,  mixmap.a);

   // Lighting calculations
   vec3 dl = gl_LightSource[0].diffuse.rgb;   
   vec3 al = gl_LightSource[0].ambient.rgb;
   vec3 n = normalize(normal);
   vec3 d = tx * (dl * max( dot ( n, lightDir), 0.0 ) + al );   

   // Apply the lighting to the final color   
   vec4 finalColor = vec4( min(d, 1.0), 1.0);
   gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor);
}

统一的 texscale 是一个值,用于确定细节纹理在地形上平铺的次数。较高的值将使细节纹理看起来更清晰,但有可能使它们看起来更重复。

于 2009-07-10T18:05:54.817 回答
1

例如在 source(hl2) 引擎中使用的标准方法之一是使用每个顶点的 alpha 来混合两种材质。材质通常至少包含一个反照率和一个法线贴图。在源引擎中,每个“混合纹理”材质只允许使用 2 个材质,这有点糟糕。

如果您想要超过 2 种材料,则必须通过使用不同纹理对不同位移进行纹理化来模拟它,确保任何单个图块最多仅包含 2 种材料。

每个顶点而不是每个像素都有一个 alpha 会产生非常糟糕的外观。正如您在 Oblivion 中所指出的,例如,鹅卵石可以平滑地融入沙子中。这个缺陷有一个修复;您使用另一种基于每个像素调制 alpha 的纹理,以便鹅卵石之间的裂缝很容易被沙子填充,但鹅卵石的顶部几乎保持 1.0 alpha,直到鹅卵石的插值顶点 alpha 几乎为 0材料。这可以使过渡看起来非常好,而不仅仅是丑陋的拖影。

您还可以使用包含 alpha 的低分辨率纹理(但仍远高于每个顶点 1 个 alpha)。平铺的地形纹理可能是 2048x2048,但用于将它们混合在一起的纹理不需要每个纹理像素的分辨率。一个 256x256 8-bit per texel 纹理只有 96 kB 与 mip 贴图。

于 2011-04-29T20:48:28.423 回答
1

预烘焙肯定不是低效的。事实上,它是最有效的,因为您的运行时代码不必进行任何混合或其他计算。它只是渲染纹理。当然,动态技术提供了工具链的简化和更多选项。

于 2009-07-10T17:25:21.077 回答
1

ID 似乎已经让QuakeWars 中的单个大型“巨型纹理”(我们说的是 32K^2-128K^2)工作。

Carmack 有一个有趣的问答,在

http://web.archive.org/web/20080121072936/http://www.gamerwithin.com/?view=article&article=1319&cat=2

(原始链接目前似乎已失效,但并未将上述链接设为链接,因为 Internet 存档链接似乎存在问题;它们在编辑预览中看起来不错,然后在主页上中断)。

于 2009-07-10T18:07:18.403 回答
0

你不能逃避平铺,但也许如果你使用在地面上产生一点噪音的基础纹理,看起来好像没有平铺......

使用与 alpha 纹理具有相同纹理坐标的基础纹理。基础纹理可以是任何东西......卫星图片或草纹理......如果它与您的地面形状相关,它将完美匹配......

并尝试为你的草、岩石纹理使用无缝纹理......它不能解决但让它看起来没有问题

于 2009-07-12T14:45:53.310 回答
0

通常,过渡区域是预先创建的,尽管可以使用 Alpha 通道和纹理混合来做一些事情。

于 2009-07-10T17:27:00.387 回答