实现轮胎印

接到一个任务,实现一个轮胎印记。特效用粒子做的效果, 感觉不是很好。主程大哥说,那程序来实现吧。

关键词

网格控制-网络


(不含烟)

  • 从文章的中github看到案例。是在初始化一定数目的网格,然后根据位置来使用。
  • 代码分析
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
using UnityEngine;
using UnityEngine.Rendering;
// Skidmarks controller. Put one of these in a scene somewhere. Call AddSkidMark.
// Copyright 2017 Nition, BSD licence (see LICENCE file). http://nition.co
public class Skidmarks : MonoBehaviour {
// INSPECTOR SETTINGS
[SerializeField]
Material skidmarksMaterial; // Material for the skidmarks to use
// END INSPECTOR SETTINGS
const int MAX_MARKS = 2048; // Max number of marks total for everyone together
const float MARK_WIDTH = 0.35f; // Width of the skidmarks. Should match the width of the wheels
const float GROUND_OFFSET = 0.02f; // Distance above surface in metres
const float MIN_DISTANCE = 0.25f; // Distance between skid texture sections in metres. Bigger = better performance, less smooth
const float MIN_SQR_DISTANCE = MIN_DISTANCE * MIN_DISTANCE;
// Info for each mark created. Needed to generate the correct mesh
class MarkSection {
public Vector3 Pos = Vector3.zero;
public Vector3 Normal = Vector3.zero;
public Vector4 Tangent = Vector4.zero;
public Vector3 Posl = Vector3.zero;
public Vector3 Posr = Vector3.zero;
public byte Intensity;
public int LastIndex;
};
int markIndex;
MarkSection[] skidmarks;
Mesh marksMesh;
MeshRenderer mr;
MeshFilter mf;
Vector3[] vertices;
Vector3[] normals;
Vector4[] tangents;
Color32[] colors;
Vector2[] uvs;
int[] triangles;
bool meshUpdated;
bool haveSetBounds;
// #### UNITY INTERNAL METHODS ####
protected void Start() {
// Generate a fixed array of skidmarks
skidmarks = new MarkSection[MAX_MARKS];
for (int i = 0; i < MAX_MARKS; i++) {
skidmarks[i] = new MarkSection();
}
mf = GetComponent<MeshFilter>();
mr = GetComponent<MeshRenderer>();
if (mr == null) {
mr = gameObject.AddComponent<MeshRenderer>();
}
marksMesh = new Mesh();
marksMesh.MarkDynamic();
if (mf == null) {
mf = gameObject.AddComponent<MeshFilter>();
}
mf.sharedMesh = marksMesh;
vertices = new Vector3[MAX_MARKS * 4];
normals = new Vector3[MAX_MARKS * 4];
tangents = new Vector4[MAX_MARKS * 4];
colors = new Color32[MAX_MARKS * 4];
uvs = new Vector2[MAX_MARKS * 4];
triangles = new int[MAX_MARKS * 6];
mr.shadowCastingMode = ShadowCastingMode.Off;
mr.receiveShadows = false;
mr.material = skidmarksMaterial;
mr.lightProbeUsage = LightProbeUsage.Off;
}
protected void LateUpdate() {
if (!meshUpdated) return;
meshUpdated = false;
// Reassign the mesh if it's changed this frame
marksMesh.vertices = vertices;
marksMesh.normals = normals;
marksMesh.tangents = tangents;
marksMesh.triangles = triangles;
marksMesh.colors32 = colors;
marksMesh.uv = uvs;
if (!haveSetBounds) {
// Could use RecalculateBounds here each frame instead, but it uses about 0.1-0.2ms each time
// Save time by just making the mesh bounds huge, so the skidmarks will always draw
// Not sure why I only need to do this once, yet can't do it in Start (it resets to zero)
marksMesh.bounds = new Bounds(new Vector3(0, 0, 0), new Vector3(10000, 10000, 10000));
haveSetBounds = true;
}
mf.sharedMesh = marksMesh;
}
// #### PUBLIC METHODS ####
// Function called by the wheel that's skidding. Sets the intensity of the skidmark section
// by setting the alpha of the vertex color
public int AddSkidMark(Vector3 pos, Vector3 normal, float intensity, int lastIndex) {
if (intensity > 1) intensity = 1.0f;
else if (intensity < 0) return -1;
if (lastIndex > 0) {
float sqrDistance = (pos - skidmarks[lastIndex].Pos).sqrMagnitude;
if (sqrDistance < MIN_SQR_DISTANCE) return lastIndex;
}
MarkSection curSection = skidmarks[markIndex];
curSection.Pos = pos + normal * GROUND_OFFSET;
curSection.Normal = normal;
curSection.Intensity = (byte)(intensity * 255f);
curSection.LastIndex = lastIndex;
if (lastIndex != -1) {
MarkSection lastSection = skidmarks[lastIndex];
Vector3 dir = (curSection.Pos - lastSection.Pos);
Vector3 xDir = Vector3.Cross(dir, normal).normalized;
curSection.Posl = curSection.Pos + xDir * MARK_WIDTH * 0.5f;
curSection.Posr = curSection.Pos - xDir * MARK_WIDTH * 0.5f;
curSection.Tangent = new Vector4(xDir.x, xDir.y, xDir.z, 1);
if (lastSection.LastIndex == -1) {
lastSection.Tangent = curSection.Tangent;
lastSection.Posl = curSection.Pos + xDir * MARK_WIDTH * 0.5f;
lastSection.Posr = curSection.Pos - xDir * MARK_WIDTH * 0.5f;
}
}
UpdateSkidmarksMesh();
int curIndex = markIndex;
// Update circular index
markIndex = ++markIndex % MAX_MARKS;
return curIndex;
}
// #### PROTECTED/PRIVATE METHODS ####
// Update part of the mesh for the current markIndex
void UpdateSkidmarksMesh() {
MarkSection curr = skidmarks[markIndex];
// Nothing to connect to yet
if (curr.LastIndex == -1) return;
MarkSection last = skidmarks[curr.LastIndex];
vertices[markIndex * 4 + 0] = last.Posl;
vertices[markIndex * 4 + 1] = last.Posr;
vertices[markIndex * 4 + 2] = curr.Posl;
vertices[markIndex * 4 + 3] = curr.Posr;
normals[markIndex * 4 + 0] = last.Normal;
normals[markIndex * 4 + 1] = last.Normal;
normals[markIndex * 4 + 2] = curr.Normal;
normals[markIndex * 4 + 3] = curr.Normal;
tangents[markIndex * 4 + 0] = last.Tangent;
tangents[markIndex * 4 + 1] = last.Tangent;
tangents[markIndex * 4 + 2] = curr.Tangent;
tangents[markIndex * 4 + 3] = curr.Tangent;
colors[markIndex * 4 + 0] = new Color32(0, 0, 0, last.Intensity);
colors[markIndex * 4 + 1] = new Color32(0, 0, 0, last.Intensity);
colors[markIndex * 4 + 2] = new Color32(0, 0, 0, curr.Intensity);
colors[markIndex * 4 + 3] = new Color32(0, 0, 0, curr.Intensity);
uvs[markIndex * 4 + 0] = new Vector2(0, 0);
uvs[markIndex * 4 + 1] = new Vector2(1, 0);
uvs[markIndex * 4 + 2] = new Vector2(0, 1);
uvs[markIndex * 4 + 3] = new Vector2(1, 1);
triangles[markIndex * 6 + 0] = markIndex * 4 + 0;
triangles[markIndex * 6 + 2] = markIndex * 4 + 1;
triangles[markIndex * 6 + 1] = markIndex * 4 + 2;
triangles[markIndex * 6 + 3] = markIndex * 4 + 2;
triangles[markIndex * 6 + 5] = markIndex * 4 + 1;
triangles[markIndex * 6 + 4] = markIndex * 4 + 3;
meshUpdated = true;
}
}
  • 在LateUpdate()对位置做处理。
  • 在理解了demo中用使用WheelCollider,rigidbody。其实是针对速度有每帧计算,速度大于0.5f有了颜色深浅的变化。还有在Y方向上,给予了(0,1,0)* 0.02f偏移值,和地面有一点间距。
  • 针对项目中具体使用,加速度部分是可以不用的,但是从效率的角度考虑,mesh的数量不要太多,可以复用。同时可以随着时间渐渐隐藏。
  • 不断使用回收,像对象池一样的。在原来的基础上,对代码做了二次开发。
  • 在渲染角度上,只增加了一个DrawCall。
  • 网络长度上和渐隐时间可以在预制件上修改,让美术调整出最好的效果。
  • 当然发现自己计算的把运动物体本身的位移忽视了。

因为公司原因,最终的代码不能分享。

文章目录
  1. 1. 关键词
  2. 2. 网格控制-网络
|