多个纹理图像混合在一起到3D地面上

时间:2022-09-10 16:49:41

How do computer games render their ground? I will be using a heightmap for geometry (though I will later optimize it) but I am wondering what the best technique is, for example, to 'paint' my ground; grass most everywhere, dirt paths here and there, gravel inside towns, and smooth transitions between each type of material.

电脑游戏如何发挥作用?我将使用几何高度图(虽然我稍后会对其进行优化)但我想知道最好的技术是什么,例如,“绘制”我的地面;到处都是草地,这里和那里的泥路,城镇内的砾石,以及每种材料之间的平滑过渡。

Do I just use a huge pre-baked texture? That seems very inefficient, when I could tile existing textures. So then do I use a huge alpha map for each existing texture? In theory it sounds okay to me but how do I actually go about doing that and what are the consequences? I really don't know where to start, and my Google searches aren't proving very effective.

我只是使用一个巨大的预烘烤纹理?当我可以平铺现有纹理时,这看起来非常低效。那么我是否为每个现有纹理使用一个巨大的alpha贴图?从理论上讲,这对我来说听起来不错,但我如何实际做到这一点以及后果是什么?我真的不知道从哪里开始,我的谷歌搜索并没有证明是非常有效的。

I'd rather not have to 'snap' the texture to the grid (i.e. space (0,0) is grass, space (0,2) is dirt, space (0,1) is grass-dirt transition); I'd rather be able to arbitrarily paint so that it looks more convincing. Of course that would be the easy way but it's too much of a sacrifice in graphics quality and 'realism'.

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

I'm mostly just looking for theory and options here. I'm using OpenGL so if you can provide tips as far as OpenGL's way of doing things, and functions that I may never have heard of, that would be great.

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

Just for clarification, Oblivion is a good reference as to what I'm looking for. I don't know how the ground's geometry is (heightmap, static 3D models, etc) but their terrain has different ground types and smooth transitions between them, like I'm talking about. Here's an example image, notice how the cobblestone blends into the grass, unrealistically but smoothly: http://www.elitistsnob.com/images/Oblivion%202006-05-21%2008-38-25-15.jpg

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

Also I think I read about this in one of the Game Programming Gems books, but I didn't pay much attention to it at the time, and now that it's summer I don't have access to my university's library to check! I'm looking for tables of contents right now and will edit if I find it, but I will still not be able to read it until mid August.

另外我想我在其中一本游戏编程宝石书中读过这篇文章,但当时我并没有太注意它,现在是夏天我无法访问我大学的图书馆!我现在正在寻找目录,如果我发现它会编辑,但直到8月中旬我仍然无法阅读。

EDIT: Ah man, Game Programming Gems 7 has a chapter 5.8 titled "Mapping Large Textures for Outdoor Terrain Rendering", that sounds like exactly what I need, but my U's library doesn't even have that book! I couldn't find anything exactly like this in the other Game Programming Gems books, though a couple had some terrain geometry articles.

编辑:啊,游戏编程宝石7有一个标题为“为室外地形渲染绘制大纹理”的章节5.8,这听起来就像我需要的,但是我的U的图书馆甚至没有那本书!我在其他Game Programming Gems书籍中找不到任何完全相同的东西,尽管有一些人有一些地形几何文章。

6 个解决方案

#1


I have recently written a small terrain rendering engine in OpenGL that does something similar to what you are talking about. The technique I use is best described as texture splatting.

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

I use five textures to accomplish this. Four of these textures are detail textures: grass, rock, water, and sand. These textures are smallish, 512x512 textures, and they are tiled across the terrain. The fifth texture is a mixmap. The mixmap is a giant texture that covers the entire terrain, in my case is 4096x4096.

我使用五种纹理来实现这一目标。这些纹理中有四种是细节纹理:草,岩石,水和沙子。这些纹理很小,512x512纹理,并且它们在地形上平铺。第五个纹理是mixmap。 mixmap是一个覆盖整个地形的巨大纹理,在我的例子中是4096x4096。

MixMap

This mixmap uses all 4 color channels (r,g,b,a) to describe how much of a detail texture to display at that specific location. I am using the red color channel to determine how opaque the sand is, green is for grass, blue is for water, and alpha is for rock. This mixmap is calculated based off of the heightmap at initialization and I use altitudes to determine these values. For instance, close to the sea level, I mostly want water, so I set a high value in the blue channel and low values in the other channels. As I get higher into the mountains, I set the alpha color channel to a high value since I want a lot of rock texture, but I set all of the other color channels to lower values.

此mixmap使用所有4个颜色通道(r,g,b,a)来描述在该特定位置显示多少细节纹理。我使用红色通道来确定沙子是多么不透明,绿色是草,蓝色是水,阿尔法是岩石。此mixmap是在初始化时根据高度图计算的,我使用高度来确定这些值。例如,靠近海平面,我主要想要水,所以我在蓝色通道中设置了较高的值,在其他通道中设置了较低的值。随着我越来越高入山区,我将alpha颜色通道设置为高值,因为我需要大量的岩石纹理,但我将所有其他颜色通道设置为较低的值。

Fragment Shader

This mixmap is then put to use in the fragment shader, where I take these color channels of the mixmap and use them to combine the detail textures. Here is the GLSL code I am using for the fragment shader:

然后在片段着色器中使用此mixmap,我在其中使用mixmap的这些颜色通道并使用它们来组合细节纹理。这是我用于片段着色器的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);
}

The uniform texscale is a value that determines how many times the detail textures are tiled across the terrain. Higher values will make the detail textures look more crisp at the risk of making them look more repetitious.

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

#2


prebaking is most certainly not inefficient. it's the most efficient in fact because your runtime code doesn't have to do any blending or other calculations. it just renders the texture. Of course, the dynamic techniques offer a simplification of the toolchain and more options.

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

#3


ID seem to have made the single large "megatexture" (we're talking 32K^2-128K^2) work in QuakeWars.

ID似乎使QuakeWars中的单个大型“megatexture”(我们说的是32K ^ 2-128K ^ 2)工作。

There's an interesting Q&A with Carmack about it at

Carmack对此有一个有趣的问答

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

(original link seems dead currently, but not not making the above a link because SO seems to have problems with Internet Archive links; they look good in the edit preview, then break on the main page).

(原始链接目前似乎已经死了,但不是没有使上面的链接,因为SO似乎有Internet Archive链接的问题;它们在编辑预览中看起来很好,然后在主页面上中断)。

#4


One of the standard ways, used for instance in the source(hl2) engine, is to have a per vertex alpha to blend between two materials. The materials usually consist of at least an albedo and a normal map. In the source engine only 2 materials per "blend texture" material is is allowed, which is kind of crappy.

用于例如源(hl2)引擎的标准方法之一是使每个顶点α在两种材料之间混合。材料通常至少包括反照率和法线图。在源引擎中,每个“混合纹理”材料只允许使用2种材料,这有点蹩脚。

If you want more than 2 materials you have to simulate it by texturing different displacements with different textures, making sure that any individual tile only contains 2 materials at most.

如果您需要两种以上的材料,则必须通过使用不同纹理纹理化不同的位移来模拟它,确保任何单个图块最多只包含2种材质。

Having an alpha per-vertex rather than per pixel gives a pretty bad appearance. As you noted in Oblivion you get cobblestones blending smoothly into sand for instance. There's a fix for this defect; you use another texture which modulates the alpha on a per pixel basis, so that the cracks between the cobble stones fill with sand readily, but the tops of the cobble stones remain at almost 1.0 alpha until the interpolated vertex alpha is almost 0 for the cobble material. This can make the transition look really nice instead of just an ugly smear.

每个顶点而不是每个像素都有一个非常糟糕的外观。正如你在Oblivion中所提到的那样,你可以将鹅卵石平滑地混合成沙子。有一个解决这个缺陷的方法;你使用另一个纹理来调整每个像素的alpha,这样鹅卵石之间的裂缝很容易填满沙子,但是鹅卵石的顶部几乎保持在1.0 alpha,直到内插的顶点alpha几乎为0材料。这可以使过渡看起来非常好,而不仅仅是一个丑陋的涂抹。

You could also use a low res texture that contains the alphas(but still much higher than 1 alpha per vertex). The tiled terain textures may be 2048x2048, but the texture used to blend them toghether does not need per-texel resolution. A 256x256 8-bit per texel texture is only 96 kB with mip maps.

您还可以使用包含alpha的低res纹理(但仍然远高于每个顶点1个alpha)。平铺的terain纹理可能是2048x2048,但用于将它们混合到一起的纹理不需要每纹理分辨率。每个纹理素的256x256 8位纹理只有96 kB,带有mip贴图。

#5


Generally, transition areas are precreated, although it's possible to do some things with alpha channels and blending of textures.

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

#6


you cant run away from tiling but maybe if you use a base texture which makes a little noise on ground, it looks like there is no tiling...

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

use base texture with the same texture coordinates of alpha texture. base texture can be anything.. a sattelite picture, or a grass texture.. it would match perfect if it is related to your ground shape..

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

and try to use seamless textures for your grass, rock textures... it does not solve but makes it look as there is no problem

并尝试使用无缝纹理为您的草,岩石纹理...它没有解决,但使它看起来没有问题

#1


I have recently written a small terrain rendering engine in OpenGL that does something similar to what you are talking about. The technique I use is best described as texture splatting.

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

I use five textures to accomplish this. Four of these textures are detail textures: grass, rock, water, and sand. These textures are smallish, 512x512 textures, and they are tiled across the terrain. The fifth texture is a mixmap. The mixmap is a giant texture that covers the entire terrain, in my case is 4096x4096.

我使用五种纹理来实现这一目标。这些纹理中有四种是细节纹理:草,岩石,水和沙子。这些纹理很小,512x512纹理,并且它们在地形上平铺。第五个纹理是mixmap。 mixmap是一个覆盖整个地形的巨大纹理,在我的例子中是4096x4096。

MixMap

This mixmap uses all 4 color channels (r,g,b,a) to describe how much of a detail texture to display at that specific location. I am using the red color channel to determine how opaque the sand is, green is for grass, blue is for water, and alpha is for rock. This mixmap is calculated based off of the heightmap at initialization and I use altitudes to determine these values. For instance, close to the sea level, I mostly want water, so I set a high value in the blue channel and low values in the other channels. As I get higher into the mountains, I set the alpha color channel to a high value since I want a lot of rock texture, but I set all of the other color channels to lower values.

此mixmap使用所有4个颜色通道(r,g,b,a)来描述在该特定位置显示多少细节纹理。我使用红色通道来确定沙子是多么不透明,绿色是草,蓝色是水,阿尔法是岩石。此mixmap是在初始化时根据高度图计算的,我使用高度来确定这些值。例如,靠近海平面,我主要想要水,所以我在蓝色通道中设置了较高的值,在其他通道中设置了较低的值。随着我越来越高入山区,我将alpha颜色通道设置为高值,因为我需要大量的岩石纹理,但我将所有其他颜色通道设置为较低的值。

Fragment Shader

This mixmap is then put to use in the fragment shader, where I take these color channels of the mixmap and use them to combine the detail textures. Here is the GLSL code I am using for the fragment shader:

然后在片段着色器中使用此mixmap,我在其中使用mixmap的这些颜色通道并使用它们来组合细节纹理。这是我用于片段着色器的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);
}

The uniform texscale is a value that determines how many times the detail textures are tiled across the terrain. Higher values will make the detail textures look more crisp at the risk of making them look more repetitious.

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

#2


prebaking is most certainly not inefficient. it's the most efficient in fact because your runtime code doesn't have to do any blending or other calculations. it just renders the texture. Of course, the dynamic techniques offer a simplification of the toolchain and more options.

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

#3


ID seem to have made the single large "megatexture" (we're talking 32K^2-128K^2) work in QuakeWars.

ID似乎使QuakeWars中的单个大型“megatexture”(我们说的是32K ^ 2-128K ^ 2)工作。

There's an interesting Q&A with Carmack about it at

Carmack对此有一个有趣的问答

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

(original link seems dead currently, but not not making the above a link because SO seems to have problems with Internet Archive links; they look good in the edit preview, then break on the main page).

(原始链接目前似乎已经死了,但不是没有使上面的链接,因为SO似乎有Internet Archive链接的问题;它们在编辑预览中看起来很好,然后在主页面上中断)。

#4


One of the standard ways, used for instance in the source(hl2) engine, is to have a per vertex alpha to blend between two materials. The materials usually consist of at least an albedo and a normal map. In the source engine only 2 materials per "blend texture" material is is allowed, which is kind of crappy.

用于例如源(hl2)引擎的标准方法之一是使每个顶点α在两种材料之间混合。材料通常至少包括反照率和法线图。在源引擎中,每个“混合纹理”材料只允许使用2种材料,这有点蹩脚。

If you want more than 2 materials you have to simulate it by texturing different displacements with different textures, making sure that any individual tile only contains 2 materials at most.

如果您需要两种以上的材料,则必须通过使用不同纹理纹理化不同的位移来模拟它,确保任何单个图块最多只包含2种材质。

Having an alpha per-vertex rather than per pixel gives a pretty bad appearance. As you noted in Oblivion you get cobblestones blending smoothly into sand for instance. There's a fix for this defect; you use another texture which modulates the alpha on a per pixel basis, so that the cracks between the cobble stones fill with sand readily, but the tops of the cobble stones remain at almost 1.0 alpha until the interpolated vertex alpha is almost 0 for the cobble material. This can make the transition look really nice instead of just an ugly smear.

每个顶点而不是每个像素都有一个非常糟糕的外观。正如你在Oblivion中所提到的那样,你可以将鹅卵石平滑地混合成沙子。有一个解决这个缺陷的方法;你使用另一个纹理来调整每个像素的alpha,这样鹅卵石之间的裂缝很容易填满沙子,但是鹅卵石的顶部几乎保持在1.0 alpha,直到内插的顶点alpha几乎为0材料。这可以使过渡看起来非常好,而不仅仅是一个丑陋的涂抹。

You could also use a low res texture that contains the alphas(but still much higher than 1 alpha per vertex). The tiled terain textures may be 2048x2048, but the texture used to blend them toghether does not need per-texel resolution. A 256x256 8-bit per texel texture is only 96 kB with mip maps.

您还可以使用包含alpha的低res纹理(但仍然远高于每个顶点1个alpha)。平铺的terain纹理可能是2048x2048,但用于将它们混合到一起的纹理不需要每纹理分辨率。每个纹理素的256x256 8位纹理只有96 kB,带有mip贴图。

#5


Generally, transition areas are precreated, although it's possible to do some things with alpha channels and blending of textures.

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

#6


you cant run away from tiling but maybe if you use a base texture which makes a little noise on ground, it looks like there is no tiling...

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

use base texture with the same texture coordinates of alpha texture. base texture can be anything.. a sattelite picture, or a grass texture.. it would match perfect if it is related to your ground shape..

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

and try to use seamless textures for your grass, rock textures... it does not solve but makes it look as there is no problem

并尝试使用无缝纹理为您的草,岩石纹理...它没有解决,但使它看起来没有问题