4

XNA 4.0フレームワークを使用して、VisualStudio2010でゲームを作成しています。高さマップから生成された3D地形モデルがあります。私が達成しようとしているのは、特定のポイントの周りの特定の半径でこのモデルに色を付けることです。最終的な目標は、ユニットが特定のターンで移動できる半径をプレーヤーに表示することです。現在モデルを描画するために使用している方法は次のとおりです。

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に従って、高さマップと地形を作成しました。

助けてくれてありがとう!

4

2 に答える 2

3

シェーダーを使用してそれを実現できます...

中心と半径のワールド位置を引数として渡すだけで、ピクセルシェーダーが頂点シェーダーから補間されたピクセルワールド位置をテクスチャ座標として受け取るようになります...次に、ピクセルの距離をチェックするだけで済みます。ピクセル位置が範囲内にある場合は、中央に配置し、色を付けます。

于 2012-08-08T23:38:36.347 に答える
0

あなたが探しているテクニックはデカールと呼ばれています。

円が描画される地形の部分を抽出し、その部分に適切なテクスチャを適用して、地形とブレンドして描画する必要があります。

均一なグリッドに基づく地形の場合、これは次のようになります。

デカールの中心位置とその半径があります。次に、グリッド内の最小および最大の行/列を決定して、セルにすべての描画領域が含まれるようにします。これらの頂点から新しい頂点バッファを作成します。位置はハイトマップから読み取ることができます。テクスチャが正しい位置に配置されるように、テクスチャの座標を変更する必要があります。(0.5, 0.5)中心位置に座標があり、中心位置+(半径、半径)に座標があると仮定(1, 1)します。これで、各頂点のテクスチャ座標の方程式を見つけることができるはずです。

抽出されたグリッド

上記の例では、左上の赤い頂点のテクスチャ座標は約(-0.12, -0.05)

次に、地形のサブグリッドがあります。デカールテクスチャを適用します。適切な深度バイアスを設定します(いくつかの値を試す必要があります)。ほとんどの場合、負のSlopeScaleDepthBiasが機能します。サンプラーのテクスチャ座標の折り返しをオフにします。サブグリッドを描画します。

これが私がその目的のために書いたいくつかのVBSlimDXコードです:

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);
}
于 2012-08-04T21:17:03.170 に答える