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
+ }
0 commit comments