Rendering terrains with Managed DirectX翻译

《翻译》 原文链接:http://www.codeproject.com/Articles/8195/Rendering-terrains-with-Managed-DirectX

(忽然发现自己翻译的自己都不知道说的什么。。。也罢,一个小时的产物,不要要求太高)

(丫的,翻译完也不不知道怎么实现的,还是老老实实去看代码吧,话说我还没用过c#,容我编程c++的,龙书第13章不就讲的地形么,只不过没用HLSL而已。。。)

DirectX地形渲染

没有一个3D游戏不使用地形的,创建和渲染一个地形以及相关的物理模型,例如,在其上面开车是非常困难的。这篇文章将会demo一个创建地形的技术:非常简单的方式,但非常有效。

为了编译这篇文章的code,你需要:

C#编译器,最好是VS.NET

D3D9.0c SDK

支持像素着色器2.0的显卡,否则将会变的非常慢,大约10fps

我建议读者有会C#及相关DirectX经验

BEGINNING

渲染一个地形,首先需要用一种方式描述它,通常使用灰度高度图。这篇文章将会使用灰度图,这是一种简便的方式。(作者好啰嗦:P)。下图是我使用的一个灰度图,你可以改变成任意你喜欢的样子。

我们将使用两种纹理。一种是草地的,另一种是石头的。地形中较高的位置使用石头,较低的地方使用草地。(作者说的是pixel)。我们根据pixel的高度决定采用哪种纹理。

HLSL

为了达到这样的效果,我们使用HLSL。使用这种语言,它可以写入它们自己的顶点和像素着色器,更好控制定点和像素进行渲染。HLSL非常接近C。所以并不用花太多时间学习HLSL。下面是我们渲染地形用的顶点着色器。

 1 float4x4 WorldViewProj;float4 light;
 2 void Transform(
 3     in float4 inPos     : POSITION0,
 4     in float2 inCoord     : TEXCOORD0,
 5     in float4 blend     : TEXCOORD1,
 6     in float3 normal     : NORMAL, float4x4 WorldViewProj;float4 light;
 7 void Transform(
 8     in float4 inPos     : POSITION0,
 9     in float2 inCoord     : TEXCOORD0,
10     in float4 blend     : TEXCOORD1,
11     in float3 normal     : NORMAL,
12     out float4 outPos     : POSITION0,
13     out float2 outCoord     : TEXCOORD0,
14     out float4 Blend     : TEXCOORD1,
15     out float3 Normal     : TEXCOORD2,
16     out float3 lightDir     : TEXCOORD3 )
17 {
18     outPos = mul(inPos, WorldViewProj);
19     outCoord = inCoord;
20     Blend = blend;
21     Normal = normalize(mul(normal,WorldViewProj));
22     lightDir = inPos.xyz - light;
23 }
24
25     out float4 outPos     : POSITION0,
26     out float2 outCoord     : TEXCOORD0,
27     out float4 Blend     : TEXCOORD1,
28     out float3 Normal     : TEXCOORD2,
29     out float3 lightDir     : TEXCOORD3 )
30 {
31     outPos = mul(inPos, WorldViewProj);
32     outCoord = inCoord;
33     Blend = blend;
34     Normal = normalize(mul(normal,WorldViewProj));
35     lightDir = inPos.xyz - light;
36 }

它非常接近C函数,除了语法中的Input、output变量名字。通过应用程序传入顶点数据,顶点着色器输出output。你可能已经注意到TEXCOORD被用了好多次,那是因为TEXCOORD可以被用来传输应用程序的特殊数据,并非是位置和顶点法线(不就是纹理坐标啦,作者好啰嗦)。HLSL包含许多数学算法,如mul(),normalize()。完整的列表详见MSDN。欲知更多HLSL的细节,我建议你自己百度,因为网上有很多好东西,如果我说的过多,这篇文章就会变的too long。(:p,忍不住吐槽,作者真的好啰嗦)。

我将简单的说明顶点着色器是干嘛的。首先,传入的顶点乘以模型视图投影矩阵。这样顶点就从局部坐标系转换到视图坐标系下了。输入的纹理坐标和blend变量将会传入像素着色器。顶点法线同样需要变换并变成单位向量。最后,(这句话好长,容我好好理解) At last, the direction of the light is calculated by subtracting the position of the light from the position of the vector in world space (in this case, world space is the same as object space since there isn’t any translation, rotation, or scaling) to pass it to the pixelshader.。

下面是像素着色器:

 1 Texture Texture1;
 2 Texture Texture2;
 3
 4 sampler samp1 = sampler_state { texture = <Texture1>;
 5 minfilter = LINEAR; mipfilter = LINEAR; magfilter = LINEAR;};
 6 sampler samp2 = sampler_state { texture = <Texture2>;
 7 minfilter = LINEAR; mipfilter = LINEAR; magfilter = LINEAR;};
 8 float4 TextureColor(
 9     in float2 texCoord     : TEXCOORD0,
10     in float4 blend     : TEXCOORD1,
11     in float3 normal     : TEXCOORD2,
12     in float3 lightDir     : TEXCOORD3) : COLOR0
13 {
14     float4 texCol1 = tex2D(samp1, texCoord*4) * blend[0];
15     float4 texCol2 = tex2D(samp2, texCoord) * blend[1];
16     return (texCol1 + texCol2) * (saturate(dot(normalize(normal),
17                       normalize(light)))* (1-ambient) + ambient);
18 }

如你所见,像素着色器从顶点着色器接收了几乎全部变量,除了POSITION0变量。那是因为这个变量是所有顶点着色器都会输出的变量,但是我们的像素着色器并不使用它。首先,两个纹理颜色是由tex2D()计算的,tex2D并不直接操作纹理,而是采样器(sampler)。像素颜色信息是由blend变量、光源强度、采样器所决定的(估计翻译错了。。。)。像素着色器返回float4类型的COLOR0.每个像素着色器必须返回一个COLOR0变量,否则将不会编译。

Back to C#

为了使你的应用程序与shader交互,你必须先声明一个顶点,这将告诉DirectC顶点缓存中有什么数据及它是如何与顶点着色器的输入变量关联的。下面是地形中使用的顶点声明。

 1 VertexElement[] v = new VertexElement[]
 2 {
 3     new VertexElement(0,0,DeclarationType.Float3,DeclarationMethod.Default,
 4         DeclarationUsage.Position,0),
 5     new VertexElement(0,12,DeclarationType.Float3,DeclarationMethod.Default,
 6         DeclarationUsage.Normal,0),
 7     new VertexElement(0,24,DeclarationType.Float2,DeclarationMethod.Default,
 8         DeclarationUsage.TextureCoordinate,0),
 9     new VertexElement(0,32,DeclarationType.Float4,DeclarationMethod.Default,
10         DeclarationUsage.TextureCoordinate,1),
11     VertexElement.VertexDeclarationEnd
12 };
13
14 decl = new VertexDeclaration(device,v);

顶点声明包括VertexElements向量,它描述了我使用的struct。说到struct,我们并不能用传统的顶点成员,因为我们想添加具有相关纹理的顶点。(我去,啥意思?),所以下面就是我们使用的struct。

 1 public struct Vertex
 2 {
 3     Vector3 pos;
 4     Vector3 nor;
 5     float tu,tv;
 6     float b1,b2,b3,b4;
 7     public Vertex(Vector3 p,Vector3 n,
 8         float u,float v,float B1,float B2,
 9         float B3, float B4, bool normalize)
10     {
11         pos = p;nor = n;tu = u;tv = v;
12         b1=B1; b2=B2; b3=B3;b4 = B4;
13         float total = b1 + b2 + b3 + b4;
14         if ( normalize)
15         {
16             b1 /= total;
17             b2 /= total;
18             b3 /= total;
19             b4 /= total;
20         }
21     }
22     public static VertexFormats Format =
23        VertexFormats.Position | VertexFormats.Normal |
24        VertexFormats.Texture0 | VertexFormats.Texture1;
25 }

这个结构包包含了vector3类型的位置、顶点法线,float类型的坐标和blend变量。为了给这个struct分配成员,它同样需要一个constructor。它包括了format变量到顶点缓存。

为了使DirectX与effect交互,我们还需要一个东西,Effect类,下面我们创建一个effect。

1 String s = null;
2
3 effect = Effect.FromFile(device, @"..\..\simple.fx", null,
4 ShaderFlags.None, null, out s);
5 if ( s != null)
6 {
7     MessageBox.Show(s);
8     return;
9 }

因为我们不能debug一个shader,所以当你有个地方type incorrectly,你可能需要好久才能找到what’s wrong。避免我们使用重载的effect constructor,因为那将会引起编译错误。因此,除非你编译shader失败,重载将会成功。(我勒个去,什么玩意啊)。总之,如果这个地方有个问题,MESSAGEBOX将会显示这些错误。

Well 除了有关点的类之外,app同样还有地形类,这个类读取所有的位图数据并创建顶点缓存和索引缓存,我们规定地形的最小和最大值to the constructor。并且弄清能达到的最小和最大值。我们得到最亮和最暗的像素。每个位图的像素就是一个顶点,将顶点连接起来就会将四边形划分为三角形,形成一个三角形list。DRAW函数被调用的时候effect.beginscene已经被调用了。Effect.BeginScene告诉effect我们要开始接收东西渲染了。Effect.EndScene将会停止处理顶点数据。另外,the VertexDeclaration, VertexBuffer, and IndexBuffer are set, and theDrawPrimitives is finally called.。

为了更改你的shader中的全局变量,effect类包含setvalue函数,你可以传入你先更改的变量。

1 effect.SetValue("Texture1", t1);

另外我们这样创建effect句柄。

1 EffectHandle handle = effect.GetParameter(null,"ambient"); 2 effect.SetValue(handle,0.5f);

这样你就不用给函数传入数据了,更快哦。

So, variables that have to be assigned only once, can be assigned using the first way, but if a variable is changed multiple times, it would be better to use the second way. Note that this doesn’t only work with variables but also on techniques. With a technique, you choose which shaders you want to use; since an Effect file can contain multiple vertex- and pixelshaders, every HLSL file must have at least one technique. A technique is declared as follows:

 1 technique TransformTexture
 2
 3 {
 4
 5     pass P0
 6
 7     {
 8
 9         VertexShader = compile vs_2_0 Transform();
10
11         PixelShader = compile ps_2_0 TextureColor();
12
13     }
14
15 }

A technique consists of one or more passes, in this case, only one with the name P0; and for each pass, you assign a Vertex- and Pixelshader. The compilation target is set (there are quite a lot of versions of HLSL compilers: 1_1, 2_0, 3_0. The higher the version numbers, the more possibilities they offer but the less support there will be among the graphics cards). Transform() and TextureColor() are the names of the vertex- and pixelshaders.

In a pass, you can also set RenderState values. If you would like to set the Device.RenderState.Cullmode toCull.None, you would have to insert this line as the first line of the pass:

1 CullMode = None;

时间: 2024-10-17 18:42:24

Rendering terrains with Managed DirectX翻译的相关文章

关于VS2010 C#使用DirectX的问题[英]

转载的,就不翻译了…微软把精力放到xna去了.所以推荐大家用XNA,如果非要用托管的DirectX也可以,只不过版本一直是2006年的了. 具体方法: 安装SDK之后 他默认的位置在C:\WINDOWS\Microsoft.NET\Managed DirectX把里面相应版本的Microsoft.DirectX.Direct3DX.Dll都复制到C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0

[转]DirectX and .NET[英]

With the DirectX SDK (June 2010) release and the addition of support for Visual Studio 2010, I’ve been seeing a lot of questions of the form: How do I create a DirectX .NET application in Visual Studio 2010? I can’t find Microsoft.DirectX to add to m

DirectX 3D 之C#开发

C#下进行directX的3D开发,一个旋转的4棱锥的例子. 建议看两个文档<Managed DirectX 9图形和游戏编程简略中文文档>和<Managed DirectX 9 SDK 中文文档>. 另外最好下载个DirectX SDK (August 2007).rar.里面有些范例还是非常好的. 一.首先在电脑上装了DirectX. 二.建立一个C#的Windows应用程序,添加两个引用Microsoft.DirectX和Microsoft.DirectX.Direct3D;

unity内部:内存 和 性能(以及Unity5的升级优化)

      我们的脚本代码里经常会需要访问gameObject引用或者某个组件的引用,最好的方式当然是在脚本Awake的时候就把这些可能访问的东西都缓存下来:如果需要访问临时gameObject实例的某属性或者临时某组件的gameObject实例,在能够确保组件一定存在(可以使用[RequireComponent( typeof(AudioSource ))] 如果没有自动添加移除不了!)的情况下,可以用属性访问,毕竟属性访问比GetComponent要快上一倍,但是如果不能确定组件是否存在,甚

3d引擎列表

Agar - 一个高级图形应用程序框架,用于2D和3D游戏. Allegro library - 基于 C/C++ 的游戏引擎,支持图形,声音,输入,游戏时钟,浮点,压缩文件以及GUI. Axiom 引擎 - OGRE的衍生引擎. Baja 引擎 - 专业品质的图像引擎,用于The Lost Mansion. Boom - Doom代码的一部分.由TeamTNT开发 Build 引擎 - 一个第一人称射击游戏引擎,用于Duke Nukem 3D. BYOND - “Build Your Own

优秀游戏程序员学习资料推荐

这两天给单位的技术做的一次学习材料推荐培训,直接ppt上拷过来的. 优秀游戏程序员学习资料推荐 主讲人:臧旭 前言 今天提到的纯粹是我个人心得和理解,可能片面,可能以偏概全. 目的是给大家做一定的指引作用,想让大家知道自己还有哪些可以去学习,还有哪些不足,我们距离优秀还有多远. 对我今天提到的东西,如果大家有时间,一定要去深入了解,在技术的道路上才有可能看得远.走得稳.飞得高. 另外有一句对所有技术人员想说的话: 学无止境.切忌坐井观天.有一点小小的成就就沾沾自喜.止足不前. 扎实的基础 万丈高

OPENGL架构

第2章 OpenGL 简介 每台计算机都有专门处理图形的硬件,它们控制着屏幕上显示的内容.OpenGL向这种硬件发出命令,告诉它们执行什么操作.计算机游戏或者其他任意软件借助制造商提供的设备驱动程序,使用OpenGL向图形硬件发出命令,如图2-1所示.   图2-1  OpenGL的典型应用 OpenGL(Open Graphics Library,开放图形库)是游戏开发商使用最早.最流行的图形库之一.OpenGL是Silicon Graphics公司(SGI)在1992年开发的,但是直到199

WPF 基础到企业应用系列2——WPF前世今生

1.开篇前言       很多时候了解一项新技术的历史和趋势往往比这项技术的本身价值还要重要.WPF作为一项新技术(已经三年多了,或者应该叫老技术了),我们都有必要了解它的来龙去脉,尤其是公司的CTO.技术总监.架构师等决策层,因为他们对技术的选型及应用具有决定权.对于开发者来说,了解自己正在从事的这个技术的前世今生,有助于我们更好的认识技术本身的价值,也可以避免我们少走一些弯路(圣殿骑士 就走过很多弯路,所以对此比较感慨).从IT技术发展的这些年可以看出,技术对于各大公司只是竞争的一种手段,而

【转】PC GPU Performance Hot Spots

From:https://developer.nvidia.com/pc-gpu-performance-hot-spots Introduction Game developers shipping titles for PC and consoles are faced with many interesting rendering optimization challenges. The GPU cost of techniques like tile-based lighting or