2012-08-04 115 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