Skip to content

Commit ad879b6

Browse files
committed
Initial
0 parents  commit ad879b6

File tree

5 files changed

+422
-0
lines changed

5 files changed

+422
-0
lines changed

LinePlugin.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#if TOOLS
2+
using Godot;
3+
4+
[Tool]
5+
public partial class LinePlugin : EditorPlugin
6+
{
7+
public override void _EnterTree()
8+
{
9+
var script = GD.Load<Script>("res://addons/LineRendererCSharp/LineRenderer.cs");
10+
var texture = GD.Load<Texture2D>("res://addons/LineRendererCSharp/line_render_icon.svg");
11+
AddCustomType("LineRenderer3D", "MeshInstance3D", script, texture);
12+
}
13+
14+
public override void _ExitTree()
15+
{
16+
RemoveCustomType("LineRenderer3D");
17+
}
18+
}
19+
#endif

LineRenderer.cs

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
using Godot;
2+
using System;
3+
4+
public partial class LineRenderer : MeshInstance3D {
5+
[Export]
6+
public Vector3[] points = [new Vector3(0, 0, 0), new Vector3(0, 5, 0)];
7+
8+
[Export]
9+
public float start_thickness = 0.1f;
10+
11+
[Export]
12+
public float end_thickness = 0.1f;
13+
14+
[Export]
15+
public int corner_resolution = 5;
16+
17+
[Export]
18+
public int cap_resolution = 5;
19+
20+
[Export]
21+
public bool draw_caps = true;
22+
23+
[Export]
24+
public bool draw_corners = true;
25+
26+
[Export]
27+
public bool use_global_coords = true;
28+
29+
[Export]
30+
public bool tile_texture = true;
31+
32+
private Camera3D camera;
33+
private Vector3 cameraOrigin;
34+
35+
public override void _EnterTree()
36+
{
37+
Mesh = new ImmediateMesh();
38+
}
39+
40+
public override void _Ready()
41+
{
42+
// Initialization code here
43+
}
44+
45+
public override void _PhysicsProcess(double delta)
46+
{
47+
ImmediateMesh immediateMesh = (ImmediateMesh)Mesh;
48+
if (points.Length < 2)
49+
{
50+
return;
51+
}
52+
53+
camera = GetViewport().GetCamera3D();
54+
if (camera == null)
55+
{
56+
return;
57+
}
58+
cameraOrigin = ToLocal(camera.GlobalTransform.Origin);
59+
60+
float progressStep = 1.0f / points.Length;
61+
float progress = 0;
62+
float thickness = Mathf.Lerp(start_thickness, end_thickness, progress);
63+
float nextThickness = Mathf.Lerp(start_thickness, end_thickness, progress + progressStep);
64+
65+
immediateMesh.ClearSurfaces();
66+
immediateMesh.SurfaceBegin(Mesh.PrimitiveType.Triangles);
67+
68+
for (int i = 0; i < points.Length - 1; i++)
69+
{
70+
Vector3 A = points[i];
71+
Vector3 B = points[i + 1];
72+
73+
if (use_global_coords)
74+
{
75+
A = ToLocal(A);
76+
B = ToLocal(B);
77+
}
78+
79+
Vector3 AB = B - A;
80+
Vector3 orthogonalABStart = (cameraOrigin - ((A + B) / 2)).Cross(AB).Normalized() * thickness;
81+
Vector3 orthogonalABEnd = (cameraOrigin - ((A + B) / 2)).Cross(AB).Normalized() * nextThickness;
82+
83+
Vector3 AtoABStart = A + orthogonalABStart;
84+
Vector3 AfromABStart = A - orthogonalABStart;
85+
Vector3 BtoABEnd = B + orthogonalABEnd;
86+
Vector3 BfromABEnd = B - orthogonalABEnd;
87+
88+
if (i == 0)
89+
{
90+
if (draw_caps)
91+
{
92+
Cap(A, B, thickness, cap_resolution);
93+
}
94+
}
95+
96+
if (tile_texture)
97+
{
98+
float ABLen = AB.Length();
99+
float ABFloor = Mathf.Floor(ABLen);
100+
float ABFrac = ABLen - ABFloor;
101+
102+
immediateMesh.SurfaceSetUV(new Vector2(ABFloor, 0));
103+
immediateMesh.SurfaceAddVertex(AtoABStart);
104+
immediateMesh.SurfaceSetUV(new Vector2(-ABFrac, 0));
105+
immediateMesh.SurfaceAddVertex(BtoABEnd);
106+
immediateMesh.SurfaceSetUV(new Vector2(ABFloor, 1));
107+
immediateMesh.SurfaceAddVertex(AfromABStart);
108+
immediateMesh.SurfaceSetUV(new Vector2(-ABFrac, 0));
109+
immediateMesh.SurfaceAddVertex(BtoABEnd);
110+
immediateMesh.SurfaceSetUV(new Vector2(-ABFrac, 1));
111+
immediateMesh.SurfaceAddVertex(BfromABEnd);
112+
immediateMesh.SurfaceSetUV(new Vector2(ABFloor, 1));
113+
immediateMesh.SurfaceAddVertex(AfromABStart);
114+
}
115+
else
116+
{
117+
immediateMesh.SurfaceSetUV(new Vector2(1, 0));
118+
immediateMesh.SurfaceAddVertex(AtoABStart);
119+
immediateMesh.SurfaceSetUV(new Vector2(0, 0));
120+
immediateMesh.SurfaceAddVertex(BtoABEnd);
121+
immediateMesh.SurfaceSetUV(new Vector2(1, 1));
122+
immediateMesh.SurfaceAddVertex(AfromABStart);
123+
immediateMesh.SurfaceSetUV(new Vector2(0, 0));
124+
immediateMesh.SurfaceAddVertex(BtoABEnd);
125+
immediateMesh.SurfaceSetUV(new Vector2(0, 1));
126+
immediateMesh.SurfaceAddVertex(BfromABEnd);
127+
immediateMesh.SurfaceSetUV(new Vector2(1, 1));
128+
immediateMesh.SurfaceAddVertex(AfromABStart);
129+
}
130+
131+
if (i == points.Length - 2)
132+
{
133+
if (draw_caps)
134+
{
135+
Cap(B, A, nextThickness, cap_resolution);
136+
}
137+
}
138+
else
139+
{
140+
if (draw_corners)
141+
{
142+
Vector3 C = points[i + 2];
143+
if (use_global_coords)
144+
{
145+
C = ToLocal(C);
146+
}
147+
148+
Vector3 BC = C - B;
149+
Vector3 orthogonalBCStart = (cameraOrigin - ((B + C) / 2)).Cross(BC).Normalized() * nextThickness;
150+
151+
float angleDot = AB.Dot(orthogonalBCStart);
152+
153+
if (angleDot > 0 && !Mathf.IsEqualApprox(angleDot, 1))
154+
{
155+
Corner(B, BtoABEnd, B + orthogonalBCStart, corner_resolution);
156+
}
157+
else if (angleDot < 0 && !Mathf.IsEqualApprox(angleDot, -1))
158+
{
159+
Corner(B, B - orthogonalBCStart, BfromABEnd, corner_resolution);
160+
}
161+
}
162+
}
163+
164+
progress += progressStep;
165+
thickness = Mathf.Lerp(start_thickness, end_thickness, progress);
166+
nextThickness = Mathf.Lerp(start_thickness, end_thickness, progress + progressStep);
167+
}
168+
169+
immediateMesh.SurfaceEnd();
170+
}
171+
172+
private void Cap(Vector3 center, Vector3 pivot, float thickness, int cap_resolution)
173+
{
174+
ImmediateMesh immediateMesh = (ImmediateMesh)Mesh;
175+
Vector3 orthogonal = (cameraOrigin - center).Cross(center - pivot).Normalized() * thickness;
176+
Vector3 axis = (center - cameraOrigin).Normalized();
177+
178+
Vector3[] vertexArray = new Vector3[cap_resolution + 1];
179+
for (int i = 0; i < cap_resolution + 1; i++)
180+
{
181+
vertexArray[i] = new Vector3(0, 0, 0);
182+
}
183+
vertexArray[0] = center + orthogonal;
184+
vertexArray[cap_resolution] = center - orthogonal;
185+
186+
for (int i = 1; i < cap_resolution; i++)
187+
{
188+
vertexArray[i] = center + (orthogonal.Rotated(axis, Mathf.Lerp(0.0f, Mathf.Pi, (float)i / cap_resolution)));
189+
}
190+
191+
for (int i = 1; i < cap_resolution + 1; i++)
192+
{
193+
immediateMesh.SurfaceSetUV(new Vector2(0, (i - 1) / (float)cap_resolution));
194+
immediateMesh.SurfaceAddVertex(vertexArray[i - 1]);
195+
immediateMesh.SurfaceSetUV(new Vector2(0, (i - 1) / (float)cap_resolution));
196+
immediateMesh.SurfaceAddVertex(vertexArray[i]);
197+
immediateMesh.SurfaceSetUV(new Vector2(0.5f, 0.5f));
198+
immediateMesh.SurfaceAddVertex(center);
199+
}
200+
}
201+
202+
private void Corner(Vector3 center, Vector3 start, Vector3 end, int cap_resolution)
203+
{
204+
ImmediateMesh immediateMesh = (ImmediateMesh)Mesh;
205+
Vector3[] vertexArray = new Vector3[cap_resolution + 1];
206+
for (int i = 0; i < cap_resolution + 1; i++)
207+
{
208+
vertexArray[i] = new Vector3(0, 0, 0);
209+
}
210+
vertexArray[0] = start;
211+
vertexArray[cap_resolution] = end;
212+
213+
Vector3 axis = start.Cross(end).Normalized();
214+
Vector3 offset = start - center;
215+
float angle = offset.AngleTo(end - center);
216+
217+
for (int i = 1; i < cap_resolution; i++)
218+
{
219+
vertexArray[i] = center + offset.Rotated(axis, Mathf.Lerp(0.0f, angle, (float)i / cap_resolution));
220+
}
221+
222+
for (int i = 1; i < cap_resolution + 1; i++)
223+
{
224+
immediateMesh.SurfaceSetUV(new Vector2(0, (i - 1) / (float)cap_resolution));
225+
immediateMesh.SurfaceAddVertex(vertexArray[i - 1]);
226+
immediateMesh.SurfaceSetUV(new Vector2(0, (i - 1) / (float)cap_resolution));
227+
immediateMesh.SurfaceAddVertex(vertexArray[i]);
228+
immediateMesh.SurfaceSetUV(new Vector2(0.5f, 0.5f));
229+
immediateMesh.SurfaceAddVertex(center);
230+
}
231+
}
232+
}

line_render_icon.svg

Lines changed: 127 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)