You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
164 lines
7.8 KiB
C#
164 lines
7.8 KiB
C#
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.Experimental.Rendering;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace FluffyGroomingTool {
|
|
public class FluffyRenderersController {
|
|
internal GameObject hairMeshRendererObject;
|
|
internal GameObject motionVectorRendererObject;
|
|
|
|
private MeshRenderer hairMeshMeshRenderer;
|
|
private MeshRenderer motionVectorMeshRenderer;
|
|
|
|
public void createRendererObject(bool isHdrp, bool isUrp, Material motionVectorMaterial, int verticesCount, int[] triangleIndices) {
|
|
hairMesh = createFurMesh(verticesCount, triangleIndices);
|
|
if (hairMeshRendererObject == null) hairMeshRendererObject = new GameObject();
|
|
hairMeshRendererObject.hideFlags = HideFlags.HideAndDontSave;
|
|
hairMeshMeshRenderer = getMeshRenderer(hairMeshRendererObject);
|
|
|
|
//This should really be MotionVectorGenerationMode.None. But that apparently makes the motionVectorMeshRenderer disappear.
|
|
hairMeshMeshRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.Camera;
|
|
if (isHdrp && SystemInfo.supportsRayTracing) hairMeshMeshRenderer.rayTracingMode = RayTracingMode.DynamicGeometry;
|
|
setupRenderer(hairMeshRendererObject, "FurRenderer", hairMeshMeshRenderer);
|
|
|
|
if (!isUrp) {
|
|
if (motionVectorRendererObject == null) motionVectorRendererObject = new GameObject();
|
|
motionVectorRendererObject.hideFlags = HideFlags.HideAndDontSave;
|
|
motionVectorMeshRenderer = getMeshRenderer(motionVectorRendererObject);
|
|
motionVectorMeshRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.Object;
|
|
motionVectorMeshRenderer.material = motionVectorMaterial;
|
|
setupRenderer(motionVectorRendererObject, "MotionVectorRenderer", motionVectorMeshRenderer);
|
|
}
|
|
}
|
|
|
|
internal Mesh hairMesh;
|
|
internal GraphicsBuffer hairMeshBuffer;
|
|
|
|
private Mesh createFurMesh(int verticesCount, int[] triangleIndices) {
|
|
if (hairMesh == null) hairMesh = new Mesh();
|
|
var emptyVec2List = new Vector2[verticesCount];
|
|
var emptyVec3List = new Vector3[verticesCount];
|
|
hairMesh.hideFlags = HideFlags.HideAndDontSave;
|
|
hairMesh.indexFormat = IndexFormat.UInt32;
|
|
hairMesh.vertices = emptyVec3List;
|
|
hairMesh.normals = emptyVec3List;
|
|
hairMesh.tangents = new Vector4[verticesCount];
|
|
hairMesh.colors = new Color[verticesCount];
|
|
hairMesh.uv = emptyVec2List;
|
|
hairMesh.uv2 = emptyVec2List;
|
|
//Uv 3-4 is used to store the previous mesh vertex position for use with Motion Vector.
|
|
hairMesh.uv3 = emptyVec2List;
|
|
hairMesh.uv4 = emptyVec2List;
|
|
hairMesh.triangles = triangleIndices;
|
|
hairMesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
|
|
hairMesh.indexBufferTarget |= GraphicsBuffer.Target.Raw;
|
|
hairMeshBuffer = hairMesh.GetVertexBuffer(0);
|
|
return hairMesh;
|
|
}
|
|
|
|
public static MeshRenderer getMeshRenderer(GameObject gameObject) {
|
|
var mr = gameObject.GetComponent<MeshRenderer>();
|
|
return mr ? mr : gameObject.AddComponent<MeshRenderer>();
|
|
}
|
|
|
|
|
|
private void setupRenderer(GameObject target, string extensionName, Renderer renderer) {
|
|
var mf = target.GetComponent<MeshFilter>();
|
|
var meshFilter = mf ? mf : target.AddComponent<MeshFilter>();
|
|
meshFilter.sharedMesh = hairMesh;
|
|
meshFilter.hideFlags = HideFlags.DontSave;
|
|
target.name = "FluffyRenderer" + extensionName;
|
|
#if UNITY_EDITOR
|
|
EditorUtility.SetSelectedRenderState(renderer, EditorSelectedRenderState.Hidden);
|
|
#endif
|
|
}
|
|
|
|
public void setupRenderers(bool isCreateMeshPass, Material material, Vector3 position, Renderer currentRenderer, bool isUrp,
|
|
bool isMotionVectorsEnabled) {
|
|
if (!isCreateMeshPass) {
|
|
if (material != null && hairMeshMeshRenderer != null) {
|
|
hairMeshMeshRenderer.sharedMaterial = material;
|
|
hairMeshMeshRenderer.bounds = calculateBounds(position, currentRenderer);
|
|
hairMeshRendererObject.transform.position = Vector3.zero;
|
|
hairMeshRendererObject.transform.rotation = Quaternion.identity;
|
|
if (currentRenderer!=null && currentRenderer.gameObject.layer != hairMeshRendererObject.layer) {
|
|
hairMeshRendererObject.layer = currentRenderer.gameObject.layer;
|
|
}
|
|
|
|
if (currentRenderer!=null && hairMeshMeshRenderer.renderingLayerMask != currentRenderer.renderingLayerMask) {
|
|
hairMeshMeshRenderer.renderingLayerMask = currentRenderer.renderingLayerMask;
|
|
}
|
|
|
|
if (!isUrp) {
|
|
motionVectorMeshRenderer.bounds = hairMeshMeshRenderer.bounds;
|
|
motionVectorRendererObject.transform.position = Vector3.zero;
|
|
motionVectorRendererObject.transform.rotation = Quaternion.identity;
|
|
setMotionVectorEnabledState(false, isMotionVectorsEnabled);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* We currently just guesstimate the bounds. We should calculate that in the compute shader but it's so darn expensive to do.
|
|
* Maybe we should expose the params?
|
|
*/
|
|
private static Bounds calculateBounds(Vector3 position, Renderer currentRenderer) {
|
|
if (currentRenderer == null) return new Bounds(position, Vector3.one * 3);
|
|
var currentRendererBounds = currentRenderer.bounds;
|
|
return new Bounds(currentRendererBounds.center, currentRendererBounds.size * 3);
|
|
}
|
|
|
|
private void setMotionVectorEnabledState(bool isUrp, bool isMotionVectorsEnabled) {
|
|
if (isUrp && motionVectorRendererObject.activeSelf) {
|
|
motionVectorRendererObject.SetActive(false);
|
|
hairMeshMeshRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
|
|
return;
|
|
}
|
|
|
|
if (isMotionVectorsEnabled && !motionVectorRendererObject.activeSelf) {
|
|
motionVectorRendererObject.SetActive(true);
|
|
//This should really be MotionVectorGenerationMode.ForceNoMotion. But that apparently makes the motionVectorMeshRenderer disappear.
|
|
hairMeshMeshRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.Camera;
|
|
}
|
|
else if (!isMotionVectorsEnabled && motionVectorRendererObject.activeSelf) {
|
|
motionVectorRendererObject.SetActive(false);
|
|
hairMeshMeshRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
|
|
}
|
|
}
|
|
|
|
public void clearObjects() {
|
|
hairMeshRendererObject = null;
|
|
motionVectorRendererObject = null;
|
|
}
|
|
|
|
public void destroy() {
|
|
Object.DestroyImmediate(hairMeshRendererObject);
|
|
if (motionVectorRendererObject != null) Object.DestroyImmediate(motionVectorRendererObject);
|
|
hairMeshBuffer?.Dispose();
|
|
Object.DestroyImmediate(hairMesh);
|
|
hairMeshBuffer = null;
|
|
}
|
|
|
|
public void disableRenderer() {
|
|
hairMeshMeshRenderer.enabled = false;
|
|
}
|
|
|
|
public void enableRenderer() {
|
|
hairMeshMeshRenderer.enabled = true;
|
|
}
|
|
|
|
public bool isReady() {
|
|
return hairMeshRendererObject != null;
|
|
}
|
|
|
|
public int getVertexBufferStride() {
|
|
return hairMesh.GetVertexBufferStride(0);
|
|
}
|
|
|
|
public Bounds getRendererBounds() {
|
|
return hairMeshMeshRenderer.bounds;
|
|
}
|
|
}
|
|
} |