415 lines
11 KiB
C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace DiamondRender
{
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[ExecuteAlways]
public class DiamondRenderer : MonoBehaviour
{
// public JewelModel model;
public Color color = new Color(1,1,1,1);
[Range(0, 3)]
public float ColorIntensity = 1.7f;
[Range(0, 1.5f)]
public float LightTransmission = 0.5f;
[Range(0, 1)]
public float ColorByDepth = 0.1f;
[Range(0,10)]
public int MaxReflection = 4;
[Range(1, 5)]
public float RefractiveIndex = 1.6f;
// public int maxReflectionCount;
Cubemap environment;
public bool autoCaptureEnvironment = false;
public bool captureEnvironmentOnSetup = false;
public int captureEnvironmentSize = 512;
// public ReflectionProbe _reflectionProbe;
public MaterialPropertyBlock block;
/* public Shader ShaderCubeMap;
public Shader ShaderReflectionProbe; */
// calculated
[SerializeField]
// [HideInInspector]
float scale;
[SerializeField]
// [HideInInspector]
Texture2D shapeTexture;
[SerializeField]
[HideInInspector]
int planeCount;
Cubemap capturedEnvironment = null;
Material mat;
float Time_;
Vector3 MinPos;
Vector3 MaxPos;
[HideInInspector]
public Vector4 CentreModel;
MeshRenderer MR;
[HideInInspector]
public Matrix4x4 m;
private void Start()
{
MR = GetComponent<MeshRenderer>();
if (block == null)
{
block = new MaterialPropertyBlock();
MR.GetPropertyBlock(block);
}
}
private void Enable()
{
MR = GetComponent<MeshRenderer>();
mat = MR.sharedMaterial;
if (block == null)
{
block = new MaterialPropertyBlock();
MR.GetPropertyBlock(block);
}
}
private void Update()
{
if(block == null)
{
block = new MaterialPropertyBlock();
MR.GetPropertyBlock(block);
}
if (MR == null)
{
MR = GetComponent<MeshRenderer>();
}
if (mat == null)
mat = MR.sharedMaterial;
m = MR.worldToLocalMatrix;
m.m03 -= CentreModel.x;
m.m13 -= CentreModel.y;
m.m23 -= CentreModel.z;
block.SetVector("CentreModel", CentreModel);
block.SetFloat("ColorByDepth", ColorByDepth);
block.SetColor("_Color", color);
block.SetFloat("ColorIntensity", ColorIntensity);
block.SetFloat("lighttransmission", LightTransmission);
block.SetFloat("_RefractiveIndex", RefractiveIndex);
block.SetInt("_MaxReflection", MaxReflection);
block.SetMatrix("MatrixWorldToObject", m);
if (shapeTexture != null) {
block.SetTexture("_ShapeTex", shapeTexture);
block.SetInt("_SizeX", shapeTexture.width);
block.SetInt("_SizeY", shapeTexture.height);
block.SetFloat("_Scale", scale);
block.SetInt("_PlaneCount", planeCount);
}
MR.SetPropertyBlock(block);
if (mat == null)
mat = MR.sharedMaterial;
if (autoCaptureEnvironment)
{
CaptureEnvironment();
}
}
[ContextMenu("Setup")]
public void Setup()
{
mat = MR.sharedMaterial;
AnalyzeMesh();
MeshRenderer mr = GetComponent<MeshRenderer>();
if (mat == null)
mat = mr.sharedMaterial;
block.SetTexture("_ShapeTex", shapeTexture);
block.SetInt("_SizeX", shapeTexture.width);
block.SetInt("_SizeY", shapeTexture.height);
block.SetFloat("_Scale", scale);
block.SetInt("_PlaneCount", planeCount);
mr.SetPropertyBlock(block);
mr.material = mat;
if (captureEnvironmentOnSetup)
{
CaptureEnvironment();
}
}
[ContextMenu("CaptureEnvironment")]
public void CaptureEnvironment()
{
Material m = GetComponent<MeshRenderer>().sharedMaterial;
if( m == null )
{
Debug.LogWarning("Material is not setup yet. please do Setup first.");
return;
}
if (capturedEnvironment == null)
{
capturedEnvironment = new Cubemap(captureEnvironmentSize, TextureFormat.ARGB32, false);
}
Camera cameraComponent = GetComponent<Camera>();
bool temporaryCameraComponent = false;
if (cameraComponent == null)
{
cameraComponent = gameObject.AddComponent<Camera>();
temporaryCameraComponent = true;
}
cameraComponent.RenderToCubemap(capturedEnvironment);
environment = capturedEnvironment;
m.SetTexture("_Environment", capturedEnvironment);
#if UNITY_EDITOR
if ( temporaryCameraComponent)
{
DestroyImmediate(cameraComponent);
}
#endif
}
[ContextMenu("ApplyNumericParameters")]
public void ApplyNumericParameters()
{
Material m = GetComponent<MeshRenderer>().sharedMaterial;
m.SetInt("_SizeX", shapeTexture.width);
m.SetInt("_SizeY", shapeTexture.height);
m.SetFloat("_Scale", scale);
m.SetInt("_PlaneCount", planeCount);
m.SetColor("_Color", color);
}
bool AnalyzeMesh()
{
Mesh sourceMesh = GetComponent<MeshFilter>().sharedMesh;
if (sourceMesh == null)
{
return false;
}
Vector3[] vertices = sourceMesh.vertices;
Vector3[] normals = sourceMesh.normals;
int[] indices = sourceMesh.GetIndices(0);
MeshTopology topology = sourceMesh.GetTopology(0);
CentreModel = new Vector4(1, 1, 1, 1);
MaxPos = new Vector4(-9999999, -9999999, -9999999, 1);
MinPos = new Vector4(9999999, 9999999, 9999999, 1);
for (int i = 0; i < vertices.Length; i++)
{
if (vertices[i].x < MinPos.x)
{
MinPos.x = vertices[i].x;
}
if (vertices[i].y < MinPos.y)
{
MinPos.y = vertices[i].y;
}
if (vertices[i].z < MinPos.z)
{
MinPos.z = vertices[i].z;
}
if (vertices[i].x > MaxPos.x)
{
MaxPos.x = vertices[i].x;
}
if (vertices[i].y > MaxPos.y)
{
MaxPos.y = vertices[i].y;
}
if (vertices[i].z > MaxPos.z)
{
MaxPos.z = vertices[i].z;
}
}
CentreModel.x = (MaxPos.x + MinPos.x) / 2;
CentreModel.y = (MaxPos.y + MinPos.y) / 2;
CentreModel.z = (MaxPos.z + MinPos.z) / 2;
for (int i = 0; i < vertices.Length; i++)
{
vertices[i].x = vertices[i].x - CentreModel.x;
vertices[i].y = vertices[i].y - CentreModel.y;
vertices[i].z = vertices[i].z - CentreModel.z;
}
scale = 0.0f;
// calc scale
for (int i = 0; i < vertices.Length; ++i)
{
// 5% margin
scale = Mathf.Max(vertices[i].magnitude * 1.05f, scale);
}
int texSize = 4;
Color[] planes = null;
int stride = 3;
if (topology == MeshTopology.Triangles)
{
stride = 3;
}
else if (topology == MeshTopology.Quads)
{
stride = 4;
}
else
{
// no support
Debug.LogError("unsupported mesh topology detected : " + topology.ToString());
}
List<Color> tmpPlanes = new List<Color>();
int faceCount = indices.Length / stride;
for (int i = 0; i < faceCount; i++)
{
int index = i * stride;
int vertIndex = indices[index];
Vector3 primaryPosition = vertices[vertIndex];
Vector3 primaryNormal = normals[vertIndex];
Color packedPlane = PackPlaneIntoColor(primaryPosition, primaryNormal, scale);
bool duplicated = false;
foreach(Color c in tmpPlanes)
{
if( c == packedPlane )
{
duplicated = true;
break;
}
}
if( !duplicated )
{
tmpPlanes.Add(packedPlane);
}
}
planeCount = tmpPlanes.Count;
while (texSize * texSize < planeCount)
{
texSize *= 2;
}
planes = new Color[texSize * texSize];
for( int i=0; i<tmpPlanes.Count; ++i )
{
planes[i] = tmpPlanes[i];
}
{
shapeTexture = new Texture2D(texSize, texSize);
shapeTexture.filterMode = FilterMode.Point;
}
shapeTexture.Reinitialize(texSize, texSize);
shapeTexture.SetPixels(planes);
shapeTexture.Apply();
#if UNITY_EDITOR
AssetDatabase.CreateAsset(shapeTexture, "Assets/SuperRealisticDiamondShaders/ShapeTextures/" + "_" + System.DateTime.Now.ToString("yyyy-MM-dd") + "_ " + System.DateTime.Now.Hour + "_ " + System.DateTime.Now.Minute + Random.Range(-99999,99999) + " shapeTexture_.asset"); // save the modified model
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
#endif
return true;
}
static Color PackPlaneIntoColor(Vector3 position, Vector3 normal, float in_scale)
{
Color retval;
retval.r = (normal.x + 1.0f) * 0.5f;
retval.g = (normal.y + 1.0f) * 0.5f;
retval.b = (normal.z + 1.0f) * 0.5f;
retval.a = Vector3.Dot(position, normal) / in_scale;
return retval;
}
}
}