1+ using UnityEngine ;
2+ using UnityEngine . Serialization ;
3+
4+ namespace Assets . Code . Misc {
5+ [ LuauAPI ]
6+ public class TubeRendererCS : MonoBehaviour {
7+ [ SerializeField ] Vector3 [ ] _positions ;
8+ [ SerializeField ] int _sides ;
9+ [ SerializeField ] float _radiusOne ;
10+ [ SerializeField ] float _radiusTwo ;
11+ [ SerializeField ] bool _useWorldSpace = true ;
12+ [ SerializeField ] bool _useTwoRadii = false ;
13+
14+ private Vector3 [ ] _vertices ;
15+ private Mesh _mesh ;
16+ private MeshFilter _meshFilter ;
17+ private MeshRenderer _meshRenderer ;
18+
19+ public Material material {
20+ get { return _meshRenderer . material ; }
21+ set { _meshRenderer . material = value ; }
22+ }
23+
24+ void Awake ( ) {
25+ _meshFilter = GetComponent < MeshFilter > ( ) ;
26+ if ( _meshFilter == null ) {
27+ _meshFilter = gameObject . AddComponent < MeshFilter > ( ) ;
28+ }
29+
30+ _meshRenderer = GetComponent < MeshRenderer > ( ) ;
31+ if ( _meshRenderer == null ) {
32+ _meshRenderer = gameObject . AddComponent < MeshRenderer > ( ) ;
33+ }
34+
35+ _mesh = new Mesh ( ) ;
36+ _meshFilter . mesh = _mesh ;
37+ }
38+
39+ private void OnEnable ( ) {
40+ _meshRenderer . enabled = true ;
41+ }
42+
43+ private void OnDisable ( ) {
44+ _meshRenderer . enabled = false ;
45+ }
46+
47+ void Update ( ) {
48+ GenerateMesh ( ) ;
49+ }
50+
51+ public void SetStartRadius ( float radius ) {
52+ _radiusOne = radius ;
53+ }
54+
55+ public float GetStartRadius ( ) {
56+ return _radiusOne ;
57+ }
58+
59+ public void SetEndRadius ( float radius ) {
60+ _radiusTwo = radius ;
61+ }
62+
63+ public float GetEndRadius ( ) {
64+ return _radiusTwo ;
65+ }
66+
67+ public void SetSides ( int sides ) {
68+ _sides = sides ;
69+ }
70+
71+
72+
73+ public void SetPositions ( Vector3 [ ] positions ) {
74+ _positions = positions ;
75+ GenerateMesh ( ) ;
76+ }
77+
78+ private void GenerateMesh ( ) {
79+ if ( _mesh == null || _positions == null || _positions . Length <= 1 ) {
80+ _mesh = new Mesh ( ) ;
81+ return ;
82+ }
83+
84+ var verticesLength = _sides * _positions . Length ;
85+ if ( _vertices == null || _vertices . Length != verticesLength ) {
86+ _vertices = new Vector3 [ verticesLength ] ;
87+
88+ var indices = GenerateIndices ( ) ;
89+ var uvs = GenerateUVs ( ) ;
90+
91+ if ( verticesLength > _mesh . vertexCount ) {
92+ _mesh . vertices = _vertices ;
93+ _mesh . triangles = indices ;
94+ _mesh . uv = uvs ;
95+ }
96+ else {
97+ _mesh . triangles = indices ;
98+ _mesh . vertices = _vertices ;
99+ _mesh . uv = uvs ;
100+ }
101+ }
102+
103+ var currentVertIndex = 0 ;
104+
105+ for ( int i = 0 ; i < _positions . Length ; i ++ ) {
106+ var circle = CalculateCircle ( i ) ;
107+ foreach ( var vertex in circle ) {
108+ _vertices [ currentVertIndex ++ ] = _useWorldSpace ? transform . InverseTransformPoint ( vertex ) : vertex ;
109+ }
110+ }
111+
112+ _mesh . vertices = _vertices ;
113+ _mesh . RecalculateNormals ( ) ;
114+ _mesh . RecalculateBounds ( ) ;
115+
116+ _meshFilter . mesh = _mesh ;
117+ }
118+
119+ private Vector2 [ ] GenerateUVs ( ) {
120+ var uvs = new Vector2 [ _positions . Length * _sides ] ;
121+
122+ for ( int segment = 0 ; segment < _positions . Length ; segment ++ ) {
123+ for ( int side = 0 ; side < _sides ; side ++ ) {
124+ var vertIndex = ( segment * _sides + side ) ;
125+ var u = side / ( _sides - 1f ) ;
126+ var v = segment / ( _positions . Length - 1f ) ;
127+
128+ uvs [ vertIndex ] = new Vector2 ( u , v ) ;
129+ }
130+ }
131+
132+ return uvs ;
133+ }
134+
135+ private int [ ] GenerateIndices ( ) {
136+ // Two triangles and 3 vertices
137+ var indices = new int [ _positions . Length * _sides * 2 * 3 ] ;
138+
139+ var currentIndicesIndex = 0 ;
140+ for ( int segment = 1 ; segment < _positions . Length ; segment ++ ) {
141+ for ( int side = 0 ; side < _sides ; side ++ ) {
142+ var vertIndex = ( segment * _sides + side ) ;
143+ var prevVertIndex = vertIndex - _sides ;
144+
145+ // Triangle one
146+ indices [ currentIndicesIndex ++ ] = prevVertIndex ;
147+ indices [ currentIndicesIndex ++ ] =
148+ ( side == _sides - 1 ) ? ( vertIndex - ( _sides - 1 ) ) : ( vertIndex + 1 ) ;
149+ indices [ currentIndicesIndex ++ ] = vertIndex ;
150+
151+
152+ // Triangle two
153+ indices [ currentIndicesIndex ++ ] =
154+ ( side == _sides - 1 ) ? ( prevVertIndex - ( _sides - 1 ) ) : ( prevVertIndex + 1 ) ;
155+ indices [ currentIndicesIndex ++ ] =
156+ ( side == _sides - 1 ) ? ( vertIndex - ( _sides - 1 ) ) : ( vertIndex + 1 ) ;
157+ indices [ currentIndicesIndex ++ ] = prevVertIndex ;
158+ }
159+ }
160+
161+ return indices ;
162+ }
163+
164+ private Vector3 [ ] CalculateCircle ( int index ) {
165+ var dirCount = 0 ;
166+ var forward = Vector3 . zero ;
167+
168+ // If not first index
169+ if ( index > 0 ) {
170+ forward += ( _positions [ index ] - _positions [ index - 1 ] ) . normalized ;
171+ dirCount ++ ;
172+ }
173+
174+ // If not last index
175+ if ( index < _positions . Length - 1 ) {
176+ forward += ( _positions [ index + 1 ] - _positions [ index ] ) . normalized ;
177+ dirCount ++ ;
178+ }
179+
180+ // Forward is the average of the connecting edges directions
181+ forward = ( forward / dirCount ) . normalized ;
182+ var side = Vector3 . Cross ( forward , forward + new Vector3 ( .123564f , .34675f , .756892f ) ) . normalized ;
183+ var up = Vector3 . Cross ( forward , side ) . normalized ;
184+
185+ var circle = new Vector3 [ _sides ] ;
186+ var angle = 0f ;
187+ var angleStep = ( 2 * Mathf . PI ) / _sides ;
188+
189+ var t = index / ( _positions . Length - 1f ) ;
190+ var radius = _useTwoRadii ? Mathf . Lerp ( _radiusOne , _radiusTwo , t ) : _radiusOne ;
191+
192+ for ( int i = 0 ; i < _sides ; i ++ ) {
193+ var x = Mathf . Cos ( angle ) ;
194+ var y = Mathf . Sin ( angle ) ;
195+
196+ circle [ i ] = _positions [ index ] + side * x * radius + up * y * radius ;
197+
198+ angle += angleStep ;
199+ }
200+
201+ return circle ;
202+ }
203+ }
204+ }
0 commit comments