/
SkinnerSource.cs
229 lines (185 loc) · 7.86 KB
/
SkinnerSource.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
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
using UnityEngine;
using UnityEngine.Rendering;
namespace Skinner
{
/// Bakes vertex attributes of a skinned mesh into textures
/// and provides them to Skinner renderers.
[AddComponentMenu("Skinner/Skinner Source")]
[RequireComponent(typeof(SkinnedMeshRenderer))]
public class SkinnerSource : MonoBehaviour
{
#region Editable properties
// This is only editable on Editor (not changeable at runtime).
[SerializeField, Tooltip("Preprocessed model data.")]
SkinnerModel _model;
#endregion
#region Public properties
/// The count of vertices of the source model.
public int vertexCount {
get { return _model != null ? _model.vertexCount : 0; }
}
/// Checks if the buffers are ready for use.
public bool isReady {
get { return _frameCount > 1; }
}
/// Baked texture of skinned vertex positions.
public RenderTexture positionBuffer {
get { return _swapFlag ? _positionBuffer1 : _positionBuffer0; }
}
/// Baked texture of skinned vertex positions from the previous frame.
public RenderTexture previousPositionBuffer {
get { return _swapFlag ? _positionBuffer0 : _positionBuffer1; }
}
/// Baked texture of skinned vertex normals.
public RenderTexture normalBuffer {
get { return _normalBuffer; }
}
/// Baked texture of skinned vertex tangents.
public RenderTexture tangentBuffer {
get { return _tangentBuffer; }
}
#endregion
#region Internal resources
// Replacement shader used for baking vertex attributes.
[SerializeField] Shader _replacementShader;
[SerializeField] Shader _replacementShaderPosition;
[SerializeField] Shader _replacementShaderNormal;
[SerializeField] Shader _replacementShaderTangent;
// Placeholder material that draws nothing but only has the replacement tag.
[SerializeField] Material _placeholderMaterial;
#endregion
#region Private members
// Vertex attribute buffers.
RenderTexture _positionBuffer0;
RenderTexture _positionBuffer1;
RenderTexture _normalBuffer;
RenderTexture _tangentBuffer;
// Multiple render target for even/odd frames.
RenderBuffer[] _mrt0;
RenderBuffer[] _mrt1;
bool _swapFlag;
// Temporary camera used for vertex baking.
Camera _camera;
// Used for rejecting the first and second frame.
int _frameCount;
// Create a render texture for vertex baking.
RenderTexture CreateBuffer()
{
var format = SkinnerInternals.supportedBufferFormat;
var rt = new RenderTexture(_model.vertexCount, 1, 0, format);
rt.filterMode = FilterMode.Point;
return rt;
}
// Override the settings of the skinned mesh renderer.
void OverrideRenderer()
{
var smr = GetComponent<SkinnedMeshRenderer>();
smr.sharedMesh = _model.mesh;
smr.material = _placeholderMaterial;
smr.receiveShadows = false;
// This renderer is disabled to hide from other cameras. It will be
// enable by CullingStateController only while rendered from our
// vertex baking camera.
smr.enabled = false;
}
// Create a camera for vertex baking.
void BuildCamera()
{
// Create a new game object.
var go = new GameObject("Camera");
go.hideFlags = HideFlags.HideInHierarchy;
// Make it parented by this game object.
var tr = go.transform;
tr.parent = transform;
tr.localPosition = Vector3.zero;
tr.localRotation = Quaternion.identity;
// Add a camera to the game object.
_camera = go.AddComponent<Camera>();
_camera.renderingPath= RenderingPath.Forward;
_camera.clearFlags = CameraClearFlags.SolidColor;
_camera.depth = -10000; // Is this a right way to control the order?
_camera.nearClipPlane = -100;
_camera.farClipPlane = 100;
_camera.orthographic = true;
_camera.orthographicSize = 100;
_camera.enabled = false; // We'll explicitly call Render().
// Add CullingStateController to hide from other cameras.
var culler = go.AddComponent<CullingStateController>();
culler.target = GetComponent<SkinnedMeshRenderer>();
}
#endregion
#region MonoBehaviour functions
void Start()
{
// Create the attribute buffers.
_positionBuffer0 = CreateBuffer();
_positionBuffer1 = CreateBuffer();
_normalBuffer = CreateBuffer();
_tangentBuffer = CreateBuffer();
// MRT set 0 (used in even frames)
_mrt0 = new [] {
_positionBuffer0.colorBuffer,
_normalBuffer.colorBuffer,
_tangentBuffer.colorBuffer
};
// MRT set 1 (used in odd frames)
_mrt1 = new [] {
_positionBuffer1.colorBuffer,
_normalBuffer.colorBuffer,
_tangentBuffer.colorBuffer
};
// Set up the baking rig.
OverrideRenderer();
BuildCamera();
_swapFlag = true; // This will become false by the first Update call.
}
void OnDestroy()
{
if (_positionBuffer0 != null) Destroy(_positionBuffer0);
if (_positionBuffer1 != null) Destroy(_positionBuffer1);
if (_normalBuffer != null) Destroy(_normalBuffer);
if (_tangentBuffer != null) Destroy(_tangentBuffer);
}
void LateUpdate()
{
// Swap the buffers and invoke vertex baking.
_swapFlag = !_swapFlag;
// Render to vertex attribute buffers at once with using MRT. Note
// that we can't use MRT when VR is enabled (due to issue #942235).
// In that case, we use separate shaders to workaround the issue.
if (!UnityEngine.VR.VRSettings.enabled)
{
if (_swapFlag)
_camera.SetTargetBuffers(_mrt1, _positionBuffer1.depthBuffer);
else
_camera.SetTargetBuffers(_mrt0, _positionBuffer0.depthBuffer);
_camera.RenderWithShader(_replacementShader, "Skinner");
}
else if (_swapFlag)
{
_camera.targetTexture = _positionBuffer1;
_camera.RenderWithShader(_replacementShaderPosition, "Skinner");
_camera.targetTexture = _normalBuffer;
_camera.RenderWithShader(_replacementShaderNormal, "Skinner");
_camera.targetTexture = _tangentBuffer;
_camera.RenderWithShader(_replacementShaderTangent, "Skinner");
}
else
{
_camera.targetTexture = _positionBuffer0;
_camera.RenderWithShader(_replacementShaderPosition, "Skinner");
_camera.targetTexture = _normalBuffer;
_camera.RenderWithShader(_replacementShaderNormal, "Skinner");
_camera.targetTexture = _tangentBuffer;
_camera.RenderWithShader(_replacementShaderTangent, "Skinner");
}
// We manually disable the skinned mesh renderer here because
// there is a regression from 2017.1.0 that prevents
// CallingStateController from being called in OnPostRender.
// This is a pretty hackish workaround, so FIXME later.
GetComponent<SkinnedMeshRenderer>().enabled = false;
_frameCount++;
}
#endregion
}
}