-
Notifications
You must be signed in to change notification settings - Fork 61
/
Trail3D.cs
155 lines (148 loc) · 5.2 KB
/
Trail3D.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using Godot;
public class Trail3D : ImmediateGeometry
{
[Export] public float length = 10.0f;
[Export] public float maxRadius = 0.5f;
[Export] public int densityLengthwise = 25;
[Export] public int densityAround = 5;
[Export] public float shape = 0;
[Export] public Godot.Collections.Array<Vector3> points = new Godot.Collections.Array<Vector3>();
[Export] public float segmentLength = 1.0f;
public override void _Ready()
{
if (length <= 0) length = 2;
if (densityAround < 3) densityAround = 3;
if (densityLengthwise < 2) densityLengthwise = 2;
segmentLength = length / densityLengthwise;
for (int i = 0; i < densityLengthwise; i++)
{
points.Add(GlobalTransform.origin);
}
}
public override void _Process(float delta)
{
UpdateTrail();
RenderTrail();
}
public void UpdateTrail()
{
int i = 0;
Vector3 lastP = GlobalTransform.origin;
foreach (Vector3 p in points)
{
Vector3 v = p; // We can't assign to foreach iterators in C#.
float dis = v.DistanceTo(lastP);
float segLen = segmentLength;
if (i == 0)
{
segLen = 0.05f;
}
if (dis > segLen)
{
v = lastP + (v - lastP) / dis * segLen;
}
lastP = v;
points[i] = v;
i += 1;
}
}
public void RenderTrail()
{
Clear();
Begin(Mesh.PrimitiveType.Triangles);
Godot.Collections.Array<Vector3> localPoints = new Godot.Collections.Array<Vector3>();
foreach (Vector3 p in points)
{
localPoints.Add(p - GlobalTransform.origin);
}
Vector3 lastP = Vector3.Zero;
Godot.Collections.Array<Godot.Collections.Array<Vector3>> verts = new Godot.Collections.Array<Godot.Collections.Array<Vector3>>();
int ind = 0;
bool firstIteration = true;
Vector3 lastFirstVec = Vector3.Zero;
foreach (Vector3 p in localPoints)
{
Godot.Collections.Array<Vector3> newLastPoints = new Godot.Collections.Array<Vector3>();
var offset = lastP - p;
if (offset == Vector3.Zero)
{
continue;
}
var yVec = offset.Normalized(); // get vector pointing from this point to last point
var xVec = Vector3.Zero;
if (firstIteration)
{
xVec = yVec.Cross(yVec.Rotated(Vector3.Right, 0.3f)); //cross product with random vector to get a perpendicular vector
}
else
{
xVec = yVec.Cross(lastFirstVec).Cross(yVec).Normalized(); // keep each loop at the same rotation as the previous
}
var width = maxRadius;
if (shape != 0)
{
width = (1 - Mathf.Ease((ind + 1.0f) / densityLengthwise, shape)) * maxRadius;
}
Godot.Collections.Array<Vector3> segVerts = new Godot.Collections.Array<Vector3>();
var fIter = true;
for (int i = 0; i < densityAround; i++) // set up row of verts for each level
{
var newVert = p + width * xVec.Rotated(yVec, i * 2 * Mathf.Pi / densityAround).Normalized();
if (fIter)
{
lastFirstVec = newVert - p;
fIter = false;
}
segVerts.Add(newVert);
}
verts.Add(segVerts);
lastP = p;
ind += 1;
firstIteration = false;
}
for (int j = 0; j < verts.Count - 1; j++)
{
var cur = verts[j];
var nxt = verts[j + 1];
// 1.0 added to avoid division by zero
float uv = (j + 1.0f) / (verts.Count + 1);
float uvnxt = (j + 2.0f) / (verts.Count + 1);
for (int i = 0; i < densityAround; i++)
{
var nxtI = (i + 1) % densityAround;
//order added affects normal
SetUv(new Vector2(uv, 0f));
AddVertex(cur[i]);
AddVertex(cur[nxtI]);
SetUv(new Vector2(uvnxt, 0f));
AddVertex(nxt[i]);
SetUv(new Vector2(uv, 0f));
AddVertex(cur[nxtI]);
SetUv(new Vector2(uvnxt, 0f));
AddVertex(nxt[nxtI]);
SetUv(new Vector2(uvnxt, 0f));
AddVertex(nxt[i]);
}
}
if (verts.Count > 1)
{
for (int i = 0; i < densityAround; i++)
{
var nxt = (i + 1) % densityAround;
SetUv(Vector2.Zero);
AddVertex(verts[0][i]);
AddVertex(Vector3.Zero);
AddVertex(verts[0][nxt]);
}
for (int i = 0; i < densityAround; i++)
{
var nxt = (i + 1) % densityAround;
SetUv(new Vector2(1f, 0f));
AddVertex(verts[verts.Count - 1][i]);
AddVertex(verts[verts.Count - 1][nxt]);
AddVertex(lastP);
}
}
End();
}
}