Visual studio 2010 在XNA 4.0中,以给定点为半径着色地形模型

Visual studio 2010 在XNA 4.0中,以给定点为半径着色地形模型,visual-studio-2010,3d,xna,xna-4.0,3d-model,Visual Studio 2010,3d,Xna,Xna 4.0,3d Model,我正在VisualStudio2010中使用XNA4.0框架编写一个游戏。我有一个从高度图生成的三维地形模型。我试图实现的是在给定半径内围绕某个点着色此模型,最终目标是向玩家显示单位在给定回合中可以移动的半径。目前我用于绘制模型的方法如下: void DrawModel(Model model, Matrix worldMatrix) { Matrix[] boneTransforms = new Matrix[model.Bones.Count]; mo

我正在VisualStudio2010中使用XNA4.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();
        }
    }
此外,如果相关的话,我按照本教程创建了我的高度地图和地形


提前感谢您的帮助

您正在寻找的技术称为贴花

您必须提取将绘制圆的地形部分,对该部分应用适当的纹理,并将其与地形混合绘制

对于基于统一栅格的地形,如下所示:

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

在上面的示例中,左上角的红色顶点的纹理坐标约为
(-0.12,-0.05)

然后是地形的子网格。对其应用贴图纹理。设置适当的深度偏差(您必须尝试一些值)。在大多数情况下,负斜率CaledepthBias将起作用。在采样器中禁用纹理坐标换行。绘制子网格

下面是我为此编写的一些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
Public Sub Init()
顶点=(数学天花板(2*半径/三角形宽度)+2)^2
Tris=(数学天花板(2*半径/三角形宽度)+1)^2*2
作为整数的Dim索引(Tris*3-1)
作为整数的Dim curN
作为整数的Dim w
w=(数学天花板(2*半径/三角形宽度)+2)
对于y,作为整数=0到w-2
对于x作为整数=0到w-2
指数(curN)=x+y*w:curN+=1
指数(curN)=x+(y+1)*w:curN+=1
指数(curN)=(x+1)+(y)*w:curN+=1
指数(curN)=x+(y+1)*w:curN+=1
指数(curN)=(x+1)+(y+1)*w:curN+=1
指数(curN)=(x+1)+y*w:curN+=1
下一个
下一个
VB=新缓冲区(D3DDevice,新缓冲区描述(Verts*VertexoColor.Struct.SizeOfBytes,ResourceUsage.Dynamic,BindFlags.VertexBuffer,CpuAccessFlags.Write,ResourceOptionFlags.None,VertexoColor.Struct.SizeOfBytes))
IB=新缓冲区(D3DDevice,新数据流(索引,False,False),新缓冲区描述(4*Tris*3,ResourceUsage.Default,BindFlags.IndexBuffer,CpuAccessFlags.None,ResourceOptionFlags.None,4))
端接头
公共子更新()
将顶点(顶点-1)调暗为VertexColor.Struct
作为整数的Dim curN
将rad调暗为单个“贴花半径”
低矮如单身
将p作为向量2
Dim yx,yz为整数
将t设置为矢量2'纹理坐标
将中心调暗为Vector2'贴花中心
对于y作为整数=数学地板((center.y-rad)/TriAngleWidth)到数学地板((center.y-rad)/TriAngleWidth)+数学天花板(2*rad/TriAngleWidth)+1
对于x作为整数=数学地板((center.x-rad)/TriAngleWidth)到数学地板((center.x-rad)/TriAngleWidth)+数学天花板(2*rad/TriAngleWidth)+1
p、 X=X*三角形宽度
p、 Y=Y*三角形宽度
yx=x:yz=y
如果yx<0,则yx=0
如果yx>HeightMap.GetUpperBound(0),则yx=HeightMap.GetUpperBound(0)
如果yz<0,则yz=0
如果yz>HeightMap.GetUpperBound(1),则yz=HeightMap.GetUpperBound(1)
高度=高度图(yx,yz)
t、 X=(p.X-center.X)/(2*rad)+0.5
t、 Y=(p.Y-center.Y)/(2*rad)+0.5
顶点(curN)=新的Vertexocolor.Struct,带有{.Position=New Vector3(p.X,hoehe,p.Y),.TexCoord=t,.Color=New Color4(1,1,1,1)}:curN+=1
下一个
下一个
Dim data=D3DContext.MapSubresource(VB,MapMode.WriteDiscard,MapFlags.None)
data.data.WriteRange(顶点)
D3DContext.UnmasupbreSource(VB,0)
端接头
这是相应的C代码

public void Init()
{
顶点=数学功率(数学天花板(2*半径/三角形宽度)+2,2);
Tris=数学功率(数学天花板(2*半径/三角形宽度)+1,2)*2;
int[]索引=新的int[Tris*3];
int curN;
int w;
w=(数学天花板(2*半径/三角形宽度)+2);

对于(int y=0;y,您可以使用着色器来实现这一点

只需将圆心和半径的世界位置作为参数传递, 让像素着色器接收从顶点着色器插值的像素世界位置作为纹理坐标。。。
然后只需检查像素位置到中心的距离,如果像素位置在范围内,则用颜色将其着色…

好的,我已经四处寻找如何实现这种技术,但我没有找到好的资源。你能建议一种方法来实现这一点或实现这一目的的资源吗?谢谢,真的很难找到关于这一点,我为你使用常规网格的情况添加了解释。希望有帮助。我支持你创建VertexBuffer,我假设它填充了整个高度图上每个顶点的矢量,对吗?之后你就失去了我X)如何访问模型的纹理坐标?很抱歉,我是3D领域的初学者。另外,我不懂VB,我正在使用c#atm。谢谢你的耐心,你帮了我很大的忙
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);
}