La technique que vous recherchez s'appelle la décalcomanie.
Vous devez extraire la partie du terrain où le cercle sera dessiné, appliquer une texture appropriée à cette partie et la dessiner en la mélangeant avec le terrain.
Pour le cas d'un terrain basé sur une grille uniforme, cela ressemblera à ceci:
Vous avez la position centrale de l'autocollant et son rayon. Vous pouvez ensuite déterminer min/max row/col dans la grille, afin que les cellules incluent chaque région dessinée. Créez un nouveau tampon de vertex à partir de ces sommets. Les positions peuvent être lues à partir de la heightmap. Vous devez modifier les coordonnées de la texture, de sorte que la texture sera placée à la bonne position. Supposons que la position centrale ait la coordonnée (0.5, 0.5)
, la position centrale + (rayon, rayon) a la coordonnée (1, 1)
et ainsi de suite. Avec cela, vous devriez être capable de trouver une équation pour les coordonnées de texture pour chaque sommet.
Dans l'exemple ci-dessus, le sommet rouge en haut à gauche a les coordonnées de texture d'environ (-0.12, -0.05)
Ensuite, vous avez la sous-grille du terrain. Appliquez la texture du décalque. Définissez un biais de profondeur approprié (vous devez essayer certaines valeurs). Dans la plupart des cas, un SlopeScaleDepthBias négatif fonctionnera. Désactivez l'habillage des coordonnées de texture dans l'échantillonneur. Dessinez le sous-réseau.
Voici quelques code VB SlimDX je l'ai écrit à cet effet:
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
Et voici le suivant code 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);
}
Je n'ai pas travaillé avec les shaders auparavant. Pourriez-vous expliquer ce que vous voulez dire en passant un pixel shader? Le shader est-il un objet? Merci – Dangerbunny
Un shader est le code exécuté dans le GPU et associé à l'effet, vous pouvez coder votre propre effet ... bien que vous deviez apprendre les bases du shader auparavant, ici vous pouvez trouver quelques infos sur un shader pour faire ce que vous voulez par moi-même http://stackoverflow.com/questions/8000164/how-to-draw-a-circle-on-3d-terrain-in-xna – Blau
Cela fonctionne parfaitement, merci! Aussi je ne peux pas croire que je n'ai pas vu l'autre poste, c'est à peu près exactement la même question que j'avais X) – Dangerbunny