2012-08-04 118 views
4

调色在半径的地形模型围绕给定一点上,我在Visual Studio 2010中写一个游戏,使用XNA 4.0框架。我有一个从高度图生成的3D地形模型。我正在试图完成的是着色这款机型在给定半径围绕某一点,最终目标是要显示给玩家,其中一个单元可以在给定的转弯移动半径。我使用提请此刻的模型的方法是这样的:在XNA 4.0

void DrawModel(Model model, Matrix worldMatrix) 
    { 
     Matrix[] boneTransforms = new Matrix[model.Bones.Count]; 
     model.CopyAbsoluteBoneTransformsTo(boneTransforms); 

     foreach (ModelMesh mesh in model.Meshes) 
     { 
      foreach (BasicEffect effect in mesh.Effects) 
      { 
       effect.World = boneTransforms[mesh.ParentBone.Index] * worldMatrix; 
       effect.View = camera.viewMatrix; 
       effect.Projection = camera.projectionMatrix; 


       effect.EnableDefaultLighting(); 
       effect.EmissiveColor = Color.Green.ToVector3(); 
       effect.PreferPerPixelLighting = true; 

       // Set the fog to match the black background color 
       effect.FogEnabled = true; 
       effect.FogColor = Color.CornflowerBlue.ToVector3(); 
       effect.FogStart = 1000; 
       effect.FogEnd = 3200; 
      } 

      mesh.Draw(); 
     } 
    } 

此外,如果是相关的,我跟着这个教程http://create.msdn.com/en-US/education/catalog/sample/collision_3d_heightmap创建我的高度图和地形。

在此先感谢您的帮助!

回答

2

可以使用着色器来实现这一目标?

你只需要通过为参数的圆心和半径, 的世界上的地位,让像素着色器接收像素世界从顶点着色器插入的位置作为纹理坐标... 然后只需检查像素位置到中心的距离,并在像素位置在范围内时用颜色着色...

+0

我以前没有使用着色器。你能通过传递像素着色器来说明你的意思吗?着色器是一个对象吗?谢谢 – Dangerbunny 2012-08-09 00:56:25

+0

着色器是在GPU中执行的代码,并与效果相关联,您可以编写自己的效果...虽然您应该先学习着色器基础知识,但您可以在此处找到关于着色器的一些信息,由我自己http://stackoverflow.com/questions/8000164/how-to-draw-a-circle-on-3d-terrain-in-xna – Blau 2012-08-09 10:30:30

+0

这完美的作品,谢谢你!我也不敢相信我没有看到其他帖子,这几乎是我的问题X) – Dangerbunny 2012-08-09 21:02:35

0

你正在寻找被称为贴花的技术。

你要提取的地形,在这里圆将绘制的部分,应用适当的纹理那部分并绘制它与地形共混。

对于基于一个统一的网格地形的情况下,这将如下所示:

你有贴花和其半径的中心位置。然后,您可以确定网格中的最小和最大行/列,以便单元格包含每个绘制的区域。从这些顶点创建一个新的顶点缓冲区。位置可以从高度图中读取。你必须改变纹理坐标,所以纹理将被放置在正确的位置。假定的中心位置具有坐标(0.5, 0.5),中心位置+(半径,半径)已经坐标(1, 1)等。有了这个,你应该能够找到每个顶点纹理坐标的方程。

Extracted grid

在上面的例子中,左上角红色的顶点约为(-0.12, -0.05)

纹理坐标然后你有地形的亚格子。将贴花纹理应用于它。设置适当的深度偏差(您必须尝试一些值)。在大多数情况下,负SlopeScaleDepthBias将起作用。关闭采样器中的纹理坐标环绕。绘制子网格。

这里的一些VB代码SlimDX我为此写道:

Public Sub Init() 
    Verts = (Math.Ceiling(2 * Radius/TriAngleWidth) + 2)^2 
    Tris = (Math.Ceiling(2 * Radius/TriAngleWidth) + 1)^2 * 2 

    Dim Indices(Tris * 3 - 1) As Integer 
    Dim curN As Integer 
    Dim w As Integer 
    w = (Math.Ceiling(2 * Radius/TriAngleWidth) + 2) 
    For y As Integer = 0 To w - 2 
     For x As Integer = 0 To w - 2 
      Indices(curN) = x + y * w : curN += 1 
      Indices(curN) = x + (y + 1) * w : curN += 1 
      Indices(curN) = (x + 1) + (y) * w : curN += 1 
      Indices(curN) = x + (y + 1) * w : curN += 1 
      Indices(curN) = (x + 1) + (y + 1) * w : curN += 1 
      Indices(curN) = (x + 1) + y * w : curN += 1 
     Next 
    Next 

    VB = New Buffer(D3DDevice, New BufferDescription(Verts * VertexPosTexColor.Struct.SizeOfBytes, ResourceUsage.Dynamic, BindFlags.VertexBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, VertexPosTexColor.Struct.SizeOfBytes)) 
    IB = New Buffer(D3DDevice, New DataStream(Indices, False, False), New BufferDescription(4 * Tris * 3, ResourceUsage.Default, BindFlags.IndexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 4)) 
End Sub 

Public Sub Update() 
    Dim Vertex(Verts - 1) As VertexPosTexColor.Struct 
    Dim curN As Integer 
    Dim rad As Single 'The decal radius 
    Dim height As Single 
    Dim p As Vector2 
    Dim yx, yz As Integer 
    Dim t As Vector2 'texture coordinates 
    Dim center As Vector2 'decal center 
    For y As Integer = Math.Floor((center.Y - rad)/TriAngleWidth) To Math.Floor((center.Y - rad)/TriAngleWidth) + Math.Ceiling(2 * rad/TriAngleWidth) + 1 
     For x As Integer = Math.Floor((center.X - rad)/TriAngleWidth) To Math.Floor((center.X - rad)/TriAngleWidth) + Math.Ceiling(2 * rad/TriAngleWidth) + 1 
      p.X = x * TriAngleWidth 
      p.Y = y * TriAngleWidth 

      yx = x : yz = y 
      If yx < 0 Then yx = 0 
      If yx > HeightMap.GetUpperBound(0) Then yx = HeightMap.GetUpperBound(0) 
      If yz < 0 Then yz = 0 
      If yz > HeightMap.GetUpperBound(1) Then yz = HeightMap.GetUpperBound(1) 
      height = HeightMap(yx, yz) 
      t.X = (p.X - center.X)/(2 * rad) + 0.5 
      t.Y = (p.Y - center.Y)/(2 * rad) + 0.5 
      Vertex(curN) = New VertexPosTexColor.Struct With {.Position = New Vector3(p.X, hoehe, p.Y), .TexCoord = t, .Color = New Color4(1, 1, 1, 1)} : curN += 1 
     Next 
    Next 
    Dim data = D3DContext.MapSubresource(VB, MapMode.WriteDiscard, MapFlags.None) 
    data.Data.WriteRange(Vertex) 
    D3DContext.UnmapSubresource(VB, 0) 
End Sub 

而这里的根据C#代码。

public void Init() 
{ 
    Verts = Math.Pow(Math.Ceiling(2 * Radius/TriAngleWidth) + 2, 2); 
    Tris = Math.Pow(Math.Ceiling(2 * Radius/TriAngleWidth) + 1, 2) * 2; 

    int[] Indices = new int[Tris * 3]; 
    int curN; 
    int w; 
    w = (Math.Ceiling(2 * Radius/TriAngleWidth) + 2); 
    for(int y = 0; y <= w - 2; ++y) 
    { 
     for(int x = 0; x <= w - 2; ++x) 
     { 
      Indices[curN] = x + y * w ; curN += 1; 
      Indices[curN] = x + (y + 1) * w ; curN += 1; 
      Indices[curN] = (x + 1) + (y) * w ; curN += 1; 
      Indices[curN] = x + (y + 1) * w ; curN += 1; 
      Indices[curN] = (x + 1) + (y + 1) * w ; curN += 1; 
      Indices[curN] = (x + 1) + y * w ; curN += 1; 
     } 
    } 

    VB = new Buffer(D3DDevice, new BufferDescription(Verts * VertexPosTexColor.Struct.SizeOfBytes, ResourceUsage.Dynamic, BindFlags.VertexBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, VertexPosTexColor.Struct.SizeOfBytes)); 
    IB = new Buffer(D3DDevice, new DataStream(Indices, False, False), new BufferDescription(4 * Tris * 3, ResourceUsage.Default, BindFlags.IndexBuffer, CpuAccessFlags.None, ResourceOptionFlags.None, 4)); 
} 

public void Update() 
{ 
    VertexPosTexColor.Struct[] Vertex = new VertexPosTexColor.Struct[Verts] ; 
    int curN; 
    float rad; //The decal radius 
    float height; 
    Vector2 p; 
    int yx, yz; 
    Vector2 t; //texture coordinates 
    Vector2 center; //decal center 
    for(int y = Math.Floor((center.Y - rad)/TriAngleWidth); y <= Math.Floor((center.Y - rad)/TriAngleWidth) + Math.Ceiling(2 * rad/TriAngleWidth) + 1; ++y) 
     for(int x = Math.Floor((center.X - rad)/TriAngleWidth); x <= Math.Floor((center.X - rad)/TriAngleWidth) + Math.Ceiling(2 * rad/TriAngleWidth) + 1; ++x) 
     { 
      p.X = x * TriAngleWidth; 
      p.Y = y * TriAngleWidth; 

      yx = x ; yz = y; 
      if(yx < 0) 
       yx = 0; 
      if (yx > HeightMap.GetUpperBound(0)) 
       yx = HeightMap.GetUpperBound(0); 
      if (yz < 0) 
       yz = 0; 
      if (yz > HeightMap.GetUpperBound(1)) 
       yz = HeightMap.GetUpperBound(1); 
      height = HeightMap[yx, yz]; 
      t.X = (p.X - center.X)/(2 * rad) + 0.5; 
      t.Y = (p.Y - center.Y)/(2 * rad) + 0.5; 
      Vertex[curN] = new VertexPosTexColor.Struct() {Position = new Vector3(p.X, hoehe, p.Y), TexCoord = t, Color = New Color4(1, 1, 1, 1)}; curN += 1; 
     } 
    } 
    var data = D3DContext.MapSubresource(VB, MapMode.WriteDiscard, MapFlags.None); 
    data.Data.WriteRange(Vertex); 
    D3DContext.UnmapSubresource(VB, 0); 
} 
+0

好的,我已经四处寻找如何完成这样的技术,但我还没有找到一个好的资源。你能否提出一种实现这一目标的方法或资源?由于 – Dangerbunny 2012-08-05 20:58:55

+0

这真的很难找到这方面的消息。我为您使用常规网格的情况添加了解释。希望能帮助到你。 – 2012-08-05 23:04:00

+0

只要创建一个VertexBuffer,我认为其中的每个顶点的Vector3都填充了整个heightmap,我就和你一起?之后,你失去了我X)我如何访问模型的纹理坐标?对不起,我是3D领域的初学者。另外我不知道VB,我正在使用C#atm。感谢您的耐心,您已经得到了很大的帮助 – Dangerbunny 2012-08-06 21:27:18