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#

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;
}
}
}