Skip to content

Commit 75f2bd5

Browse files
committed
Getting lines rendering correctly
1 parent 7ca2e84 commit 75f2bd5

3 files changed

Lines changed: 143 additions & 4 deletions

File tree

RenderGl/WorldViewExtensions.cs

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,24 @@ public static void Render3DLineNoPrep(this WorldView world,
177177
}
178178
}
179179

180-
// render the line mesh directly
180+
// When the D3D scene pipeline is active, create a fresh mesh with baked
181+
// world-space vertices and route it through the same pipeline as other
182+
// control geometry (opaque or overlay depending on current depth test state).
183+
if (GL.Instance is INativeSceneRenderer nativeSceneRenderer
184+
&& nativeSceneRenderer.IsSceneRenderingActive)
185+
{
186+
var lineMesh = CreateTransformedLineMesh(lineTransform);
187+
188+
if (startArrow || endArrow)
189+
{
190+
AppendArrowHeads(lineMesh, start, end, startScale, normal, arrowWidth, arrowLength, startArrow, endArrow);
191+
}
192+
193+
RenderHelper.Render(lineMesh, color, Matrix4X4.Identity, RenderTypes.Shaded, forceCullBackFaces: false);
194+
return;
195+
}
196+
197+
// GL compat fallback: render the line mesh directly
181198
GL.Color4(color.Red0To255, color.Green0To255, color.Blue0To255, color.Alpha0To255);
182199
GL.Enable(EnableCap.Blend);
183200

@@ -214,6 +231,78 @@ public static void Render3DLineNoPrep(this WorldView world,
214231
}
215232
}
216233

234+
/// <summary>
235+
/// Creates a fresh mesh from scaledLineMesh with vertices pre-transformed by lineTransform.
236+
/// Each line needs its own mesh because scaledLineMesh is shared and modified per-call.
237+
/// </summary>
238+
private static Mesh CreateTransformedLineMesh(Matrix4X4 lineTransform)
239+
{
240+
var mesh = new Mesh();
241+
for (int i = 0; i < scaledLineMesh.Vertices.Count; i++)
242+
{
243+
var pos = Vector3Ex.Transform(new Vector3(scaledLineMesh.Vertices[i]), lineTransform);
244+
mesh.Vertices.Add(new Vector3Float(pos));
245+
}
246+
247+
for (int faceIndex = 0; faceIndex < scaledLineMesh.Faces.Count; faceIndex++)
248+
{
249+
mesh.Faces.Add(scaledLineMesh.Faces[faceIndex]);
250+
}
251+
252+
mesh.CalculateNormals();
253+
return mesh;
254+
}
255+
256+
/// <summary>
257+
/// Appends arrow head cone geometry to an existing mesh.
258+
/// </summary>
259+
private static void AppendArrowHeads(Mesh mesh, Vector3 start, Vector3 end, double startScale, Vector3 normal, double arrowWidth, double arrowLength, bool startArrow, bool endArrow)
260+
{
261+
if (startArrow)
262+
{
263+
AppendCone(mesh, start, startScale, -normal, arrowWidth, arrowLength);
264+
}
265+
266+
if (endArrow)
267+
{
268+
AppendCone(mesh, end, startScale, normal, arrowWidth, arrowLength);
269+
}
270+
}
271+
272+
private static void AppendCone(Mesh mesh, Vector3 basePos, double scale, Vector3 normal, double arrowWidth, double arrowLength)
273+
{
274+
var sides = 12;
275+
var perpendicular = normal.GetPerpendicular().GetNormal();
276+
var rotation = Matrix4X4.CreateRotation(normal, MathHelper.Tau / sides);
277+
var offset = perpendicular * arrowWidth * scale;
278+
var tipPos = basePos + (normal * arrowLength * scale);
279+
280+
int baseVertexIndex = mesh.Vertices.Count;
281+
// Add tip vertex
282+
mesh.Vertices.Add(new Vector3Float(tipPos));
283+
// Add base center vertex
284+
mesh.Vertices.Add(new Vector3Float(basePos));
285+
286+
// Add ring vertices
287+
for (int side = 0; side <= sides; side++)
288+
{
289+
mesh.Vertices.Add(new Vector3Float(basePos + offset));
290+
offset = offset.Transform(rotation);
291+
}
292+
293+
int tipIndex = baseVertexIndex;
294+
int baseCenterIndex = baseVertexIndex + 1;
295+
int ringStart = baseVertexIndex + 2;
296+
297+
for (int side = 0; side < sides; side++)
298+
{
299+
// Side triangle (tip to ring edge)
300+
mesh.Faces.Add(ringStart + side, tipIndex, ringStart + side + 1, mesh.Vertices);
301+
// Base triangle (center to ring edge)
302+
mesh.Faces.Add(baseCenterIndex, ringStart + side, ringStart + side + 1, mesh.Vertices);
303+
}
304+
}
305+
217306
private static void RenderHead(Vector3 basePos, double startScale, Vector3 normal, double arrowWidth, double arrowLength, bool invert)
218307
{
219308
if (invert)

VorticeD3D/NativeSceneEffects.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public partial class VorticeD3DGl
5555
public int DepthPeelingLayers { get; set; } = 6;
5656

5757
private readonly List<MeshRenderCommand> queuedSceneCommands = new();
58+
private readonly List<MeshRenderCommand> queuedOverlayCommands = new();
5859
private BedRenderCommand queuedBedCommand;
5960
private readonly List<SelectionOutlineCommand> queuedSelectionOutlines = new();
6061
private readonly NativeSceneRenderPlanner renderPlanner = new();
@@ -403,6 +404,7 @@ private void RenderQueuedSceneEffects()
403404
}
404405

405406
if (queuedSceneCommands.Count == 0
407+
&& queuedOverlayCommands.Count == 0
406408
&& queuedSelectionOutlines.Count == 0
407409
&& queuedBedCommand == null)
408410
{
@@ -428,7 +430,7 @@ private void RenderQueuedSceneEffects()
428430
RenderOpaqueCommands(renderPlan.OpaqueCommands);
429431
RenderSceneDepth(renderPlan, queuedBedCommand);
430432
RenderTransparentLayers(renderPlan.TransparentCommands, queuedBedCommand);
431-
RenderTransparentOverlays(renderPlan.TransparentCommands);
433+
RenderTransparentOverlays();
432434
CompositeSceneTargets();
433435
BlitResolvedSceneToScreen();
434436
RenderSelectionOutlines();
@@ -964,10 +966,46 @@ private void BlitResolvedSceneToScreen()
964966
UnbindSceneTextures();
965967
}
966968

967-
private void RenderTransparentOverlays(IReadOnlyList<MeshRenderCommand> transparentCommands)
969+
private void RenderTransparentOverlays()
968970
{
969971
BindColorTarget(transparentOverlayTarget);
970972
ClearColorTarget(transparentOverlayTarget, new Color4(0, 0, 0, 0));
973+
974+
if (queuedOverlayCommands.Count == 0)
975+
{
976+
return;
977+
}
978+
979+
// Render overlay commands with no depth test and alpha blending.
980+
// These are 3D controls drawn as semi-transparent ghosts, always visible on top.
981+
var noDepthState = GetOrCreateDepthStencilState(false, ComparisonFunction.Always, false);
982+
var alphaBlend = GetOrCreateBlendState(
983+
true,
984+
(int)BlendingFactorSrc.SrcAlpha,
985+
(int)BlendingFactorDest.OneMinusSrcAlpha,
986+
ColorWriteEnable.All);
987+
988+
foreach (var command in queuedOverlayCommands)
989+
{
990+
if (!SceneRenderModeUtilities.RequiresSceneMeshPass(command.RenderType))
991+
{
992+
continue;
993+
}
994+
995+
RenderMeshCommand(
996+
command,
997+
null,
998+
enableWireframe: false,
999+
wireframeOnly: false,
1000+
offsetFill: false,
1001+
enableDepthPeeling: false,
1002+
firstPeelPass: false,
1003+
opaqueDepthView: null,
1004+
nearDepthView: null,
1005+
colorWritesEnabled: true,
1006+
blendStateOverride: alphaBlend,
1007+
depthStencilStateOverride: noDepthState);
1008+
}
9711009
}
9721010

9731011
private void InitializeDualDepthPeel(IReadOnlyList<MeshRenderCommand> transparentCommands, BedRenderCommand bedCommand, ID3D11DepthStencilState depthState)
@@ -1547,6 +1585,7 @@ private void UnbindSceneTextures()
15471585
private void ClearQueuedSceneEffects()
15481586
{
15491587
queuedSceneCommands.Clear();
1588+
queuedOverlayCommands.Clear();
15501589
queuedBedCommand = null;
15511590
queuedSelectionOutlines.Clear();
15521591
}

VorticeD3D/NativeSceneRenderer.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,18 @@ public bool TryRender(MeshRenderCommand command)
7575
return false;
7676
}
7777

78-
QueueSceneCommand(command);
78+
// When depth test is disabled, the caller wants this rendered as an
79+
// always-visible overlay (e.g., 3D control ghost pass with alpha < 255).
80+
bool depthTestEnabled = enableCapState.TryGetValue((int)EnableCap.DepthTest, out var d) && d;
81+
if (depthTestEnabled)
82+
{
83+
QueueSceneCommand(command);
84+
}
85+
else
86+
{
87+
queuedOverlayCommands.Add(command);
88+
}
89+
7990
return true;
8091
}
8192

0 commit comments

Comments
 (0)