This commit is contained in:
2025-11-14 18:44:06 +08:00
parent 10156da245
commit 22e867d077
7013 changed files with 2572882 additions and 1804 deletions

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 534900b83d731e447a8abe406cb616b6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6e46ea01a7996344eb0beb007193626a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 45e9a2dc58c15a34a8bc8297ebdc8c69
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 55c30f06c41a86348af15276b2f621c5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: adeae27536c26f349969271f27c1bdb8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 31e9cb45329e9504aa7db1c06e069a34
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
using System;
using UnityEngine;
namespace UnityStandardAssets.Water
{
[ExecuteInEditMode]
[RequireComponent(typeof(WaterBase))]
public class Displace : MonoBehaviour
{
public void Awake()
{
if (enabled)
{
OnEnable();
}
else
{
OnDisable();
}
}
public void OnEnable()
{
Shader.EnableKeyword("WATER_VERTEX_DISPLACEMENT_ON");
Shader.DisableKeyword("WATER_VERTEX_DISPLACEMENT_OFF");
}
public void OnDisable()
{
Shader.EnableKeyword("WATER_VERTEX_DISPLACEMENT_OFF");
Shader.DisableKeyword("WATER_VERTEX_DISPLACEMENT_ON");
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: c62b7d87755b447919138e67f8e22e0c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,9 @@
using System;
using UnityEngine;
namespace UnityStandardAssets.Water
{
[ExecuteInEditMode]
[RequireComponent(typeof(WaterBase))]
public class GerstnerDisplace : Displace { }
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 42e7f46d0e5a84171a3909479c1646ba
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,27 @@
using System;
using UnityEngine;
namespace UnityStandardAssets.Water
{
public class MeshContainer
{
public Mesh mesh;
public Vector3[] vertices;
public Vector3[] normals;
public MeshContainer(Mesh m)
{
mesh = m;
vertices = m.vertices;
normals = m.normals;
}
public void Update()
{
mesh.vertices = vertices;
mesh.normals = normals;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 951d74f7d57bed84cb623c62436bd064
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,284 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityStandardAssets.Water
{
[ExecuteInEditMode]
[RequireComponent(typeof(WaterBase))]
public class PlanarReflection : MonoBehaviour
{
public LayerMask reflectionMask;
public bool reflectSkybox = false;
public Color clearColor = Color.grey;
public String reflectionSampler = "_ReflectionTex";
public float clipPlaneOffset = 0.07F;
Vector3 m_Oldpos;
Camera m_ReflectionCamera;
Material m_SharedMaterial;
Dictionary<Camera, bool> m_HelperCameras;
public void Start()
{
m_SharedMaterial = ((WaterBase)gameObject.GetComponent(typeof(WaterBase))).sharedMaterial;
}
Camera CreateReflectionCameraFor(Camera cam)
{
String reflName = gameObject.name + "Reflection" + cam.name;
GameObject go = GameObject.Find(reflName);
if (!go)
{
go = new GameObject(reflName, typeof(Camera));
}
if (!go.GetComponent(typeof(Camera)))
{
go.AddComponent(typeof(Camera));
}
Camera reflectCamera = go.GetComponent<Camera>();
reflectCamera.backgroundColor = clearColor;
reflectCamera.clearFlags = reflectSkybox ? CameraClearFlags.Skybox : CameraClearFlags.SolidColor;
SetStandardCameraParameter(reflectCamera, reflectionMask);
if (!reflectCamera.targetTexture)
{
reflectCamera.targetTexture = CreateTextureFor(cam);
}
return reflectCamera;
}
void SetStandardCameraParameter(Camera cam, LayerMask mask)
{
cam.cullingMask = mask & ~(1 << LayerMask.NameToLayer("Water"));
cam.backgroundColor = Color.black;
cam.enabled = false;
}
RenderTexture CreateTextureFor(Camera cam)
{
RenderTexture rt = new RenderTexture(Mathf.FloorToInt(cam.pixelWidth * 0.5F),
Mathf.FloorToInt(cam.pixelHeight * 0.5F), 24);
rt.hideFlags = HideFlags.DontSave;
return rt;
}
public void RenderHelpCameras(Camera currentCam)
{
if (null == m_HelperCameras)
{
m_HelperCameras = new Dictionary<Camera, bool>();
}
if (!m_HelperCameras.ContainsKey(currentCam))
{
m_HelperCameras.Add(currentCam, false);
}
if (m_HelperCameras[currentCam])
{
return;
}
if (!m_ReflectionCamera)
{
m_ReflectionCamera = CreateReflectionCameraFor(currentCam);
}
RenderReflectionFor(currentCam, m_ReflectionCamera);
m_HelperCameras[currentCam] = true;
}
public void LateUpdate()
{
if (null != m_HelperCameras)
{
m_HelperCameras.Clear();
}
}
public void WaterTileBeingRendered(Transform tr, Camera currentCam)
{
RenderHelpCameras(currentCam);
if (m_ReflectionCamera && m_SharedMaterial)
{
m_SharedMaterial.SetTexture(reflectionSampler, m_ReflectionCamera.targetTexture);
}
}
public void OnEnable()
{
Shader.EnableKeyword("WATER_REFLECTIVE");
Shader.DisableKeyword("WATER_SIMPLE");
}
public void OnDisable()
{
Shader.EnableKeyword("WATER_SIMPLE");
Shader.DisableKeyword("WATER_REFLECTIVE");
}
void RenderReflectionFor(Camera cam, Camera reflectCamera)
{
if (!reflectCamera)
{
return;
}
if (m_SharedMaterial && !m_SharedMaterial.HasProperty(reflectionSampler))
{
return;
}
reflectCamera.cullingMask = reflectionMask & ~(1 << LayerMask.NameToLayer("Water"));
SaneCameraSettings(reflectCamera);
reflectCamera.backgroundColor = clearColor;
reflectCamera.clearFlags = reflectSkybox ? CameraClearFlags.Skybox : CameraClearFlags.SolidColor;
if (reflectSkybox)
{
if (cam.gameObject.GetComponent(typeof(Skybox)))
{
Skybox sb = (Skybox)reflectCamera.gameObject.GetComponent(typeof(Skybox));
if (!sb)
{
sb = (Skybox)reflectCamera.gameObject.AddComponent(typeof(Skybox));
}
sb.material = ((Skybox)cam.GetComponent(typeof(Skybox))).material;
}
}
GL.invertCulling = true;
Transform reflectiveSurface = transform; //waterHeight;
Vector3 eulerA = cam.transform.eulerAngles;
reflectCamera.transform.eulerAngles = new Vector3(-eulerA.x, eulerA.y, eulerA.z);
reflectCamera.transform.position = cam.transform.position;
Vector3 pos = reflectiveSurface.transform.position;
pos.y = reflectiveSurface.position.y;
Vector3 normal = reflectiveSurface.transform.up;
float d = -Vector3.Dot(normal, pos) - clipPlaneOffset;
Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);
Matrix4x4 reflection = Matrix4x4.zero;
reflection = CalculateReflectionMatrix(reflection, reflectionPlane);
m_Oldpos = cam.transform.position;
Vector3 newpos = reflection.MultiplyPoint(m_Oldpos);
reflectCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;
Vector4 clipPlane = CameraSpacePlane(reflectCamera, pos, normal, 1.0f);
Matrix4x4 projection = cam.projectionMatrix;
projection = CalculateObliqueMatrix(projection, clipPlane);
reflectCamera.projectionMatrix = projection;
reflectCamera.transform.position = newpos;
Vector3 euler = cam.transform.eulerAngles;
reflectCamera.transform.eulerAngles = new Vector3(-euler.x, euler.y, euler.z);
reflectCamera.Render();
GL.invertCulling = false;
}
void SaneCameraSettings(Camera helperCam)
{
helperCam.depthTextureMode = DepthTextureMode.None;
helperCam.backgroundColor = Color.black;
helperCam.clearFlags = CameraClearFlags.SolidColor;
helperCam.renderingPath = RenderingPath.Forward;
}
static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane)
{
Vector4 q = projection.inverse * new Vector4(
Sgn(clipPlane.x),
Sgn(clipPlane.y),
1.0F,
1.0F
);
Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
// third row = clip plane - fourth row
projection[2] = c.x - projection[3];
projection[6] = c.y - projection[7];
projection[10] = c.z - projection[11];
projection[14] = c.w - projection[15];
return projection;
}
static Matrix4x4 CalculateReflectionMatrix(Matrix4x4 reflectionMat, Vector4 plane)
{
reflectionMat.m00 = (1.0F - 2.0F * plane[0] * plane[0]);
reflectionMat.m01 = (- 2.0F * plane[0] * plane[1]);
reflectionMat.m02 = (- 2.0F * plane[0] * plane[2]);
reflectionMat.m03 = (- 2.0F * plane[3] * plane[0]);
reflectionMat.m10 = (- 2.0F * plane[1] * plane[0]);
reflectionMat.m11 = (1.0F - 2.0F * plane[1] * plane[1]);
reflectionMat.m12 = (- 2.0F * plane[1] * plane[2]);
reflectionMat.m13 = (- 2.0F * plane[3] * plane[1]);
reflectionMat.m20 = (- 2.0F * plane[2] * plane[0]);
reflectionMat.m21 = (- 2.0F * plane[2] * plane[1]);
reflectionMat.m22 = (1.0F - 2.0F * plane[2] * plane[2]);
reflectionMat.m23 = (- 2.0F * plane[3] * plane[2]);
reflectionMat.m30 = 0.0F;
reflectionMat.m31 = 0.0F;
reflectionMat.m32 = 0.0F;
reflectionMat.m33 = 1.0F;
return reflectionMat;
}
static float Sgn(float a)
{
if (a > 0.0F)
{
return 1.0F;
}
if (a < 0.0F)
{
return -1.0F;
}
return 0.0F;
}
Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)
{
Vector3 offsetPos = pos + normal * clipPlaneOffset;
Matrix4x4 m = cam.worldToCameraMatrix;
Vector3 cpos = m.MultiplyPoint(offsetPos);
Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 4185bc77c7194462ca3b1097ef4a5de0
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,33 @@
using System;
using UnityEngine;
namespace UnityStandardAssets.Water
{
[RequireComponent(typeof(WaterBase))]
[ExecuteInEditMode]
public class SpecularLighting : MonoBehaviour
{
public Transform specularLight;
private WaterBase m_WaterBase;
public void Start()
{
m_WaterBase = (WaterBase)gameObject.GetComponent(typeof(WaterBase));
}
public void Update()
{
if (!m_WaterBase)
{
m_WaterBase = (WaterBase)gameObject.GetComponent(typeof(WaterBase));
}
if (specularLight && m_WaterBase.sharedMaterial)
{
m_WaterBase.sharedMaterial.SetVector("_WorldLightDir", specularLight.transform.forward);
}
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: de2ab2b9ac93bb544b9552e49030371b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,396 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityStandardAssets.Water
{
[ExecuteInEditMode] // Make water live-update even when not in play mode
public class Water : MonoBehaviour
{
public enum WaterMode
{
Simple = 0,
Reflective = 1,
Refractive = 2,
};
public WaterMode waterMode = WaterMode.Refractive;
public bool disablePixelLights = true;
public int textureSize = 256;
public float clipPlaneOffset = 0.07f;
public LayerMask reflectLayers = -1;
public LayerMask refractLayers = -1;
private Dictionary<Camera, Camera> m_ReflectionCameras = new Dictionary<Camera, Camera>(); // Camera -> Camera table
private Dictionary<Camera, Camera> m_RefractionCameras = new Dictionary<Camera, Camera>(); // Camera -> Camera table
private RenderTexture m_ReflectionTexture;
private RenderTexture m_RefractionTexture;
private WaterMode m_HardwareWaterSupport = WaterMode.Refractive;
private int m_OldReflectionTextureSize;
private int m_OldRefractionTextureSize;
private static bool s_InsideWater;
// This is called when it's known that the object will be rendered by some
// camera. We render reflections / refractions and do other updates here.
// Because the script executes in edit mode, reflections for the scene view
// camera will just work!
public void OnWillRenderObject()
{
if (!enabled || !GetComponent<Renderer>() || !GetComponent<Renderer>().sharedMaterial ||
!GetComponent<Renderer>().enabled)
{
return;
}
Camera cam = Camera.current;
if (!cam)
{
return;
}
// Safeguard from recursive water reflections.
if (s_InsideWater)
{
return;
}
s_InsideWater = true;
// Actual water rendering mode depends on both the current setting AND
// the hardware support. There's no point in rendering refraction textures
// if they won't be visible in the end.
m_HardwareWaterSupport = FindHardwareWaterSupport();
WaterMode mode = GetWaterMode();
Camera reflectionCamera, refractionCamera;
CreateWaterObjects(cam, out reflectionCamera, out refractionCamera);
// find out the reflection plane: position and normal in world space
Vector3 pos = transform.position;
Vector3 normal = transform.up;
// Optionally disable pixel lights for reflection/refraction
int oldPixelLightCount = QualitySettings.pixelLightCount;
if (disablePixelLights)
{
QualitySettings.pixelLightCount = 0;
}
UpdateCameraModes(cam, reflectionCamera);
UpdateCameraModes(cam, refractionCamera);
// Render reflection if needed
if (mode >= WaterMode.Reflective)
{
// Reflect camera around reflection plane
float d = -Vector3.Dot(normal, pos) - clipPlaneOffset;
Vector4 reflectionPlane = new Vector4(normal.x, normal.y, normal.z, d);
Matrix4x4 reflection = Matrix4x4.zero;
CalculateReflectionMatrix(ref reflection, reflectionPlane);
Vector3 oldpos = cam.transform.position;
Vector3 newpos = reflection.MultiplyPoint(oldpos);
reflectionCamera.worldToCameraMatrix = cam.worldToCameraMatrix * reflection;
// Setup oblique projection matrix so that near plane is our reflection
// plane. This way we clip everything below/above it for free.
Vector4 clipPlane = CameraSpacePlane(reflectionCamera, pos, normal, 1.0f);
reflectionCamera.projectionMatrix = cam.CalculateObliqueMatrix(clipPlane);
reflectionCamera.cullingMask = ~(1 << 4) & reflectLayers.value; // never render water layer
reflectionCamera.targetTexture = m_ReflectionTexture;
GL.invertCulling = true;
reflectionCamera.transform.position = newpos;
Vector3 euler = cam.transform.eulerAngles;
reflectionCamera.transform.eulerAngles = new Vector3(-euler.x, euler.y, euler.z);
reflectionCamera.Render();
reflectionCamera.transform.position = oldpos;
GL.invertCulling = false;
GetComponent<Renderer>().sharedMaterial.SetTexture("_ReflectionTex", m_ReflectionTexture);
}
// Render refraction
if (mode >= WaterMode.Refractive)
{
refractionCamera.worldToCameraMatrix = cam.worldToCameraMatrix;
// Setup oblique projection matrix so that near plane is our reflection
// plane. This way we clip everything below/above it for free.
Vector4 clipPlane = CameraSpacePlane(refractionCamera, pos, normal, -1.0f);
refractionCamera.projectionMatrix = cam.CalculateObliqueMatrix(clipPlane);
refractionCamera.cullingMask = ~(1 << 4) & refractLayers.value; // never render water layer
refractionCamera.targetTexture = m_RefractionTexture;
refractionCamera.transform.position = cam.transform.position;
refractionCamera.transform.rotation = cam.transform.rotation;
refractionCamera.Render();
GetComponent<Renderer>().sharedMaterial.SetTexture("_RefractionTex", m_RefractionTexture);
}
// Restore pixel light count
if (disablePixelLights)
{
QualitySettings.pixelLightCount = oldPixelLightCount;
}
// Setup shader keywords based on water mode
switch (mode)
{
case WaterMode.Simple:
Shader.EnableKeyword("WATER_SIMPLE");
Shader.DisableKeyword("WATER_REFLECTIVE");
Shader.DisableKeyword("WATER_REFRACTIVE");
break;
case WaterMode.Reflective:
Shader.DisableKeyword("WATER_SIMPLE");
Shader.EnableKeyword("WATER_REFLECTIVE");
Shader.DisableKeyword("WATER_REFRACTIVE");
break;
case WaterMode.Refractive:
Shader.DisableKeyword("WATER_SIMPLE");
Shader.DisableKeyword("WATER_REFLECTIVE");
Shader.EnableKeyword("WATER_REFRACTIVE");
break;
}
s_InsideWater = false;
}
// Cleanup all the objects we possibly have created
void OnDisable()
{
if (m_ReflectionTexture)
{
DestroyImmediate(m_ReflectionTexture);
m_ReflectionTexture = null;
}
if (m_RefractionTexture)
{
DestroyImmediate(m_RefractionTexture);
m_RefractionTexture = null;
}
foreach (var kvp in m_ReflectionCameras)
{
DestroyImmediate((kvp.Value).gameObject);
}
m_ReflectionCameras.Clear();
foreach (var kvp in m_RefractionCameras)
{
DestroyImmediate((kvp.Value).gameObject);
}
m_RefractionCameras.Clear();
}
// This just sets up some matrices in the material; for really
// old cards to make water texture scroll.
void Update()
{
if (!GetComponent<Renderer>())
{
return;
}
Material mat = GetComponent<Renderer>().sharedMaterial;
if (!mat)
{
return;
}
Vector4 waveSpeed = mat.GetVector("WaveSpeed");
float waveScale = mat.GetFloat("_WaveScale");
Vector4 waveScale4 = new Vector4(waveScale, waveScale, waveScale * 0.4f, waveScale * 0.45f);
// Time since level load, and do intermediate calculations with doubles
double t = Time.timeSinceLevelLoad / 20.0;
Vector4 offsetClamped = new Vector4(
(float)Math.IEEERemainder(waveSpeed.x * waveScale4.x * t, 1.0),
(float)Math.IEEERemainder(waveSpeed.y * waveScale4.y * t, 1.0),
(float)Math.IEEERemainder(waveSpeed.z * waveScale4.z * t, 1.0),
(float)Math.IEEERemainder(waveSpeed.w * waveScale4.w * t, 1.0)
);
mat.SetVector("_WaveOffset", offsetClamped);
mat.SetVector("_WaveScale4", waveScale4);
}
void UpdateCameraModes(Camera src, Camera dest)
{
if (dest == null)
{
return;
}
// set water camera to clear the same way as current camera
dest.clearFlags = src.clearFlags;
dest.backgroundColor = src.backgroundColor;
if (src.clearFlags == CameraClearFlags.Skybox)
{
Skybox sky = src.GetComponent<Skybox>();
Skybox mysky = dest.GetComponent<Skybox>();
if (!sky || !sky.material)
{
mysky.enabled = false;
}
else
{
mysky.enabled = true;
mysky.material = sky.material;
}
}
// update other values to match current camera.
// even if we are supplying custom camera&projection matrices,
// some of values are used elsewhere (e.g. skybox uses far plane)
dest.farClipPlane = src.farClipPlane;
dest.nearClipPlane = src.nearClipPlane;
dest.orthographic = src.orthographic;
dest.fieldOfView = src.fieldOfView;
dest.aspect = src.aspect;
dest.orthographicSize = src.orthographicSize;
}
// On-demand create any objects we need for water
void CreateWaterObjects(Camera currentCamera, out Camera reflectionCamera, out Camera refractionCamera)
{
WaterMode mode = GetWaterMode();
reflectionCamera = null;
refractionCamera = null;
if (mode >= WaterMode.Reflective)
{
// Reflection render texture
if (!m_ReflectionTexture || m_OldReflectionTextureSize != textureSize)
{
if (m_ReflectionTexture)
{
DestroyImmediate(m_ReflectionTexture);
}
m_ReflectionTexture = new RenderTexture(textureSize, textureSize, 16);
m_ReflectionTexture.name = "__WaterReflection" + GetInstanceID();
m_ReflectionTexture.isPowerOfTwo = true;
m_ReflectionTexture.hideFlags = HideFlags.DontSave;
m_OldReflectionTextureSize = textureSize;
}
// Camera for reflection
m_ReflectionCameras.TryGetValue(currentCamera, out reflectionCamera);
if (!reflectionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO
{
GameObject go = new GameObject("Water Refl Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(), typeof(Camera), typeof(Skybox));
reflectionCamera = go.GetComponent<Camera>();
reflectionCamera.enabled = false;
reflectionCamera.transform.position = transform.position;
reflectionCamera.transform.rotation = transform.rotation;
reflectionCamera.gameObject.AddComponent<FlareLayer>();
go.hideFlags = HideFlags.HideAndDontSave;
m_ReflectionCameras[currentCamera] = reflectionCamera;
}
}
if (mode >= WaterMode.Refractive)
{
// Refraction render texture
if (!m_RefractionTexture || m_OldRefractionTextureSize != textureSize)
{
if (m_RefractionTexture)
{
DestroyImmediate(m_RefractionTexture);
}
m_RefractionTexture = new RenderTexture(textureSize, textureSize, 16);
m_RefractionTexture.name = "__WaterRefraction" + GetInstanceID();
m_RefractionTexture.isPowerOfTwo = true;
m_RefractionTexture.hideFlags = HideFlags.DontSave;
m_OldRefractionTextureSize = textureSize;
}
// Camera for refraction
m_RefractionCameras.TryGetValue(currentCamera, out refractionCamera);
if (!refractionCamera) // catch both not-in-dictionary and in-dictionary-but-deleted-GO
{
GameObject go =
new GameObject("Water Refr Camera id" + GetInstanceID() + " for " + currentCamera.GetInstanceID(),
typeof(Camera), typeof(Skybox));
refractionCamera = go.GetComponent<Camera>();
refractionCamera.enabled = false;
refractionCamera.transform.position = transform.position;
refractionCamera.transform.rotation = transform.rotation;
refractionCamera.gameObject.AddComponent<FlareLayer>();
go.hideFlags = HideFlags.HideAndDontSave;
m_RefractionCameras[currentCamera] = refractionCamera;
}
}
}
WaterMode GetWaterMode()
{
if (m_HardwareWaterSupport < waterMode)
{
return m_HardwareWaterSupport;
}
return waterMode;
}
WaterMode FindHardwareWaterSupport()
{
if (!GetComponent<Renderer>())
{
return WaterMode.Simple;
}
Material mat = GetComponent<Renderer>().sharedMaterial;
if (!mat)
{
return WaterMode.Simple;
}
string mode = mat.GetTag("WATERMODE", false);
if (mode == "Refractive")
{
return WaterMode.Refractive;
}
if (mode == "Reflective")
{
return WaterMode.Reflective;
}
return WaterMode.Simple;
}
// Given position/normal of the plane, calculates plane in camera space.
Vector4 CameraSpacePlane(Camera cam, Vector3 pos, Vector3 normal, float sideSign)
{
Vector3 offsetPos = pos + normal * clipPlaneOffset;
Matrix4x4 m = cam.worldToCameraMatrix;
Vector3 cpos = m.MultiplyPoint(offsetPos);
Vector3 cnormal = m.MultiplyVector(normal).normalized * sideSign;
return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
}
// Calculates reflection matrix around the given plane
static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane)
{
reflectionMat.m00 = (1F - 2F * plane[0] * plane[0]);
reflectionMat.m01 = (- 2F * plane[0] * plane[1]);
reflectionMat.m02 = (- 2F * plane[0] * plane[2]);
reflectionMat.m03 = (- 2F * plane[3] * plane[0]);
reflectionMat.m10 = (- 2F * plane[1] * plane[0]);
reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);
reflectionMat.m12 = (- 2F * plane[1] * plane[2]);
reflectionMat.m13 = (- 2F * plane[3] * plane[1]);
reflectionMat.m20 = (- 2F * plane[2] * plane[0]);
reflectionMat.m21 = (- 2F * plane[2] * plane[1]);
reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);
reflectionMat.m23 = (- 2F * plane[3] * plane[2]);
reflectionMat.m30 = 0F;
reflectionMat.m31 = 0F;
reflectionMat.m32 = 0F;
reflectionMat.m33 = 1F;
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: a3d3ef1a5bbfb4e0a910fbbe5830b1f9
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,78 @@
using System;
using UnityEngine;
namespace UnityStandardAssets.Water
{
public enum WaterQuality
{
High = 2,
Medium = 1,
Low = 0,
}
[ExecuteInEditMode]
public class WaterBase : MonoBehaviour
{
public Material sharedMaterial;
public WaterQuality waterQuality = WaterQuality.High;
public bool edgeBlend = true;
public void UpdateShader()
{
if (waterQuality > WaterQuality.Medium)
{
sharedMaterial.shader.maximumLOD = 501;
}
else if (waterQuality > WaterQuality.Low)
{
sharedMaterial.shader.maximumLOD = 301;
}
else
{
sharedMaterial.shader.maximumLOD = 201;
}
// If the system does not support depth textures (ie. NaCl), turn off edge bleeding,
// as the shader will render everything as transparent if the depth texture is not valid.
if (!SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.Depth))
{
edgeBlend = false;
}
if (edgeBlend)
{
Shader.EnableKeyword("WATER_EDGEBLEND_ON");
Shader.DisableKeyword("WATER_EDGEBLEND_OFF");
// just to make sure (some peeps might forget to add a water tile to the patches)
if (Camera.main)
{
Camera.main.depthTextureMode |= DepthTextureMode.Depth;
}
}
else
{
Shader.EnableKeyword("WATER_EDGEBLEND_OFF");
Shader.DisableKeyword("WATER_EDGEBLEND_ON");
}
}
public void WaterTileBeingRendered(Transform tr, Camera currentCam)
{
if (currentCam && edgeBlend)
{
currentCam.depthTextureMode |= DepthTextureMode.Depth;
}
}
public void Update()
{
if (sharedMaterial)
{
UpdateShader();
}
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: a1da353243062479a9b31c85074a796b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,67 @@
using System;
using UnityEngine;
namespace UnityStandardAssets.Water
{
[ExecuteInEditMode]
public class WaterTile : MonoBehaviour
{
public PlanarReflection reflection;
public WaterBase waterBase;
public void Start()
{
AcquireComponents();
}
void AcquireComponents()
{
if (!reflection)
{
if (transform.parent)
{
reflection = transform.parent.GetComponent<PlanarReflection>();
}
else
{
reflection = transform.GetComponent<PlanarReflection>();
}
}
if (!waterBase)
{
if (transform.parent)
{
waterBase = transform.parent.GetComponent<WaterBase>();
}
else
{
waterBase = transform.GetComponent<WaterBase>();
}
}
}
#if UNITY_EDITOR
public void Update()
{
AcquireComponents();
}
#endif
public void OnWillRenderObject()
{
if (reflection)
{
reflection.WaterTileBeingRendered(transform, Camera.current);
}
if (waterBase)
{
waterBase.WaterTileBeingRendered(transform, Camera.current);
}
}
}
}

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 2a91e8dd37cdd41efb4859b65aced7a2
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 17fa625ce6e43384aa2e96586473ccb6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,301 @@
using System;
using UnityEngine;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using UltimateGameTools.MeshSimplifier;
public class LODPreview : MonoBehaviour
{
[Serializable]
public class ShowcaseObject
{
public AutomaticLOD m_automaticLOD;
public Vector3 m_position;
public Vector3 m_angles;
public Vector3 m_rotationAxis = Vector3.up;
public string m_description;
}
public ShowcaseObject[] ShowcaseObjects;
public Material WireframeMaterial;
public float MouseSensitvity = 0.3f;
public float MouseReleaseSpeed = 3.0f;
void Start ()
{
if (ShowcaseObjects != null && ShowcaseObjects.Length > 0)
{
for (int i = 0; i < ShowcaseObjects.Length; i++)
{
ShowcaseObjects[i].m_description = ShowcaseObjects[i].m_description.Replace("\\n", Environment.NewLine);
}
SetActiveObject(0);
}
Simplifier.CoroutineFrameMiliseconds = 20;
}
void Progress(string strTitle, string strMessage, float fT)
{
int nPercent = Mathf.RoundToInt(fT * 100.0f);
if(nPercent != m_nLastProgress || m_strLastTitle != strTitle || m_strLastMessage != strMessage)
{
m_strLastTitle = strTitle;
m_strLastMessage = strMessage;
m_nLastProgress = nPercent;
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
m_bWireframe = !m_bWireframe;
SetWireframe(m_bWireframe);
}
if (m_selectedAutomaticLOD != null)
{
if (Input.GetMouseButton(0) && Input.mousePosition.y > 100)
{
Vector3 v3Angles = ShowcaseObjects[m_nSelectedIndex].m_rotationAxis * -((Input.mousePosition.x - m_fLastMouseX) * MouseSensitvity);
m_selectedAutomaticLOD.transform.Rotate(v3Angles, Space.Self);
}
else if(Input.GetMouseButtonUp(0) && Input.mousePosition.y > 100)
{
m_fRotationSpeed = -(Input.mousePosition.x - m_fLastMouseX) * MouseReleaseSpeed;
}
else
{
Vector3 v3Angles = ShowcaseObjects[m_nSelectedIndex].m_rotationAxis * (m_fRotationSpeed * Time.deltaTime);
m_selectedAutomaticLOD.transform.Rotate(v3Angles, Space.Self);
}
}
m_fLastMouseX = Input.mousePosition.x;
}
void OnGUI()
{
int nWidth = 400;
if(ShowcaseObjects == null)
{
return;
}
bool bAllowInteract = true;
if (!string.IsNullOrEmpty(m_strLastTitle) && !string.IsNullOrEmpty(m_strLastMessage))
{
bAllowInteract = false;
}
GUI.Box(new Rect(0, 0, nWidth + 10, 430), "");
GUILayout.Label("Select model:", GUILayout.Width(nWidth));
GUILayout.BeginHorizontal();
for (int i = 0; i < ShowcaseObjects.Length; i++)
{
if (GUILayout.Button(ShowcaseObjects[i].m_automaticLOD.name) && bAllowInteract)
{
if (m_selectedAutomaticLOD != null)
{
DestroyImmediate(m_selectedAutomaticLOD.gameObject);
}
SetActiveObject(i);
}
}
GUILayout.EndHorizontal();
if (m_selectedAutomaticLOD != null)
{
GUILayout.Space(20);
GUILayout.Label(ShowcaseObjects[m_nSelectedIndex].m_description);
GUILayout.Space(20);
GUI.changed = false;
m_bWireframe = GUILayout.Toggle(m_bWireframe, "Show wireframe");
if (GUI.changed && m_selectedAutomaticLOD != null)
{
SetWireframe(m_bWireframe);
}
GUILayout.Space(20);
GUILayout.Label("Select predefined LOD:");
GUILayout.BeginHorizontal();
for (int i = 0; i < m_selectedAutomaticLOD.GetLODLevelCount(); i++)
{
if (GUILayout.Button("LOD " + i) && bAllowInteract)
{
m_selectedAutomaticLOD.SwitchToLOD(i, true);
}
}
GUILayout.EndHorizontal();
GUILayout.Space(20);
GUILayout.Label("Vertex count: " + m_selectedAutomaticLOD.GetCurrentVertexCount(true) + "/" + m_selectedAutomaticLOD.GetOriginalVertexCount(true));
GUILayout.Space(20);
if (!string.IsNullOrEmpty(m_strLastTitle) && !string.IsNullOrEmpty(m_strLastMessage))
{
GUILayout.Label(m_strLastTitle + ": " + m_strLastMessage, GUILayout.MaxWidth(nWidth));
GUI.color = Color.blue;
Rect lastRect = GUILayoutUtility.GetLastRect();
GUI.Box(new Rect(10, lastRect.yMax + 5, 204, 24), "");
GUI.Box(new Rect(12, lastRect.yMax + 7, m_nLastProgress * 2, 20), "");
}
else
{
GUILayout.Label("Vertices: " + (m_fVertexAmount * 100.0f).ToString("0.00") + "%");
m_fVertexAmount = GUILayout.HorizontalSlider(m_fVertexAmount, 0.0f, 1.0f, GUILayout.Width(200));
GUILayout.BeginHorizontal();
GUILayout.Space(3);
if (GUILayout.Button("Compute custom LOD", GUILayout.Width(200)))
{
StartCoroutine(ComputeLODWithVertices(m_fVertexAmount));
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
}
}
private void SetActiveObject(int index)
{
m_nSelectedIndex = index;
AutomaticLOD automaticLOD = Instantiate(ShowcaseObjects[index].m_automaticLOD);
automaticLOD.transform.position = ShowcaseObjects[index].m_position;
automaticLOD.transform.rotation = Quaternion.Euler(ShowcaseObjects[index].m_angles);
m_selectedAutomaticLOD = automaticLOD;
automaticLOD.SetAutomaticCameraLODSwitch(false);
m_objectMaterials = new Dictionary<GameObject, Material[]>();
AddMaterials(automaticLOD.gameObject, m_objectMaterials);
m_bWireframe = false;
}
private void AddMaterials(GameObject theGameObject, Dictionary<GameObject, Material[]> dicMaterials)
{
Renderer theRenderer = theGameObject.GetComponent<Renderer>();
AutomaticLOD automaticLOD = theGameObject.GetComponent<AutomaticLOD>();
if (theRenderer != null && theRenderer.sharedMaterials != null && automaticLOD != null)
{
dicMaterials.Add(theGameObject, theRenderer.sharedMaterials);
}
for (int i = 0; i < theGameObject.transform.childCount; i++)
{
AddMaterials(theGameObject.transform.GetChild(i).gameObject, dicMaterials);
}
}
private void SetWireframe(bool bEnabled)
{
m_bWireframe = bEnabled;
foreach (KeyValuePair<GameObject, Material[]> pair in m_objectMaterials)
{
Renderer theRenderer = pair.Key.GetComponent<Renderer>();
if (bEnabled)
{
Material[] materials = new Material[pair.Value.Length];
for (int i = 0; i < pair.Value.Length; i++)
{
materials[i] = WireframeMaterial;
}
theRenderer.sharedMaterials = materials;
}
else
{
theRenderer.sharedMaterials = pair.Value;
}
}
}
private IEnumerator ComputeLODWithVertices(float fAmount)
{
foreach (KeyValuePair<GameObject, Material[]> pair in m_objectMaterials)
{
AutomaticLOD automaticLOD = pair.Key.GetComponent<AutomaticLOD>();
MeshFilter meshFilter = pair.Key.GetComponent<MeshFilter>();
SkinnedMeshRenderer skin = pair.Key.GetComponent<SkinnedMeshRenderer>();
if (automaticLOD && (meshFilter != null || skin != null))
{
Mesh newMesh = null;
if (meshFilter != null)
{
newMesh = Mesh.Instantiate(meshFilter.sharedMesh);
}
else if (skin != null)
{
newMesh = Mesh.Instantiate(skin.sharedMesh);
}
automaticLOD.GetMeshSimplifier().CoroutineEnded = false;
StartCoroutine(automaticLOD.GetMeshSimplifier().ComputeMeshWithVertexCount(pair.Key, newMesh, Mathf.RoundToInt(fAmount * automaticLOD.GetMeshSimplifier().GetOriginalMeshUniqueVertexCount()), automaticLOD.name, Progress));
while (automaticLOD.GetMeshSimplifier().CoroutineEnded == false)
{
yield return null;
}
if (meshFilter != null)
{
meshFilter.mesh = newMesh;
}
else if (skin != null)
{
skin.sharedMesh = newMesh;
}
}
}
m_strLastTitle = "";
m_strLastMessage = "";
m_nLastProgress = 0;
}
Dictionary<GameObject, Material[]> m_objectMaterials;
AutomaticLOD m_selectedAutomaticLOD;
int m_nSelectedIndex = -1;
bool m_bWireframe;
float m_fRotationSpeed = 10.0f;
float m_fLastMouseX;
Mesh m_newMesh;
int m_nLastProgress = -1;
string m_strLastTitle = "";
string m_strLastMessage = "";
float m_fVertexAmount = 1.0f;
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8a8108f029c393b4e9408d6d07364ab9
timeCreated: 1434752013
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,258 @@
using System;
using UnityEngine;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using UltimateGameTools.MeshSimplifier;
public class LODSampleLODScene : MonoBehaviour
{
[Serializable]
public class SceneCamera
{
public Camera m_camera;
public float m_near;
public float m_far;
[HideInInspector]
public Vector3 m_v3InitialCameraPosition;
[HideInInspector]
public Vector3 m_v3ViewDir;
}
public SceneCamera[] SceneCameras;
public Material WireframeMaterial;
void Start ()
{
// Enumerate all our objects with automatic LOD components
AutomaticLOD[] automaticLODObjects = FindObjectsOfType<AutomaticLOD>();
m_sceneLODObjects = new List<AutomaticLOD>();
m_objectMaterials = new Dictionary<GameObject, Material[]>();
m_nMaxLODLevels = 0;
foreach (AutomaticLOD automaticLOD in automaticLODObjects)
{
if (automaticLOD.IsRootAutomaticLOD())
{
m_sceneLODObjects.Add(automaticLOD);
if (automaticLOD.GetLODLevelCount() > m_nMaxLODLevels)
{
m_nMaxLODLevels = automaticLOD.GetLODLevelCount();
}
AddMaterials(automaticLOD.gameObject, m_objectMaterials);
}
}
// Setup camera
if (SceneCameras != null && SceneCameras.Length > 0)
{
foreach(SceneCamera sceneCamera in SceneCameras)
{
sceneCamera.m_v3InitialCameraPosition = sceneCamera.m_camera.transform.position;
sceneCamera.m_v3ViewDir = sceneCamera.m_camera.transform.forward;
}
SetActiveCamera(0);
}
m_bWireframe = false;
}
void Update()
{
m_nCamMode = 0;
if(Input.GetKey(KeyCode.I))
{
m_nCamMode = 1;
}
else if (Input.GetKey(KeyCode.O))
{
m_nCamMode = -1;
}
if (m_nCamMode != 0)
{
m_fCurrentDistanceSlider -= Time.deltaTime * 0.1f * m_nCamMode;
m_fCurrentDistanceSlider = Mathf.Clamp01(m_fCurrentDistanceSlider);
UpdateCamera(m_fCurrentDistanceSlider);
}
if (Input.GetKeyDown(KeyCode.W))
{
m_bWireframe = !m_bWireframe;
SetWireframe(m_bWireframe);
}
}
void OnGUI()
{
int nWidth = 400;
if(SceneCameras == null)
{
return;
}
if (SceneCameras.Length == 0)
{
return;
}
GUI.Box(new Rect(0, 0, nWidth + 10, 260), "");
GUILayout.Space(20);
GUILayout.Label("Select camera:", GUILayout.Width(nWidth));
GUILayout.BeginHorizontal();
for (int i = 0; i < SceneCameras.Length; i++)
{
if (GUILayout.Button(SceneCameras[i].m_camera.name))
{
SetActiveCamera(i);
}
}
GUILayout.EndHorizontal();
GUILayout.Label("Camera distance:", GUILayout.Width(nWidth));
GUI.changed = false;
m_fCurrentDistanceSlider = GUILayout.HorizontalSlider(m_fCurrentDistanceSlider, 0.0f, 1.0f);
if (GUI.changed)
{
UpdateCamera(m_fCurrentDistanceSlider);
}
GUI.changed = false;
m_bWireframe = GUILayout.Toggle(m_bWireframe, "Show wireframe");
if (GUI.changed)
{
SetWireframe(m_bWireframe);
}
GUILayout.Space(20);
GUILayout.Label("Select LOD:");
GUILayout.BeginHorizontal();
if (GUILayout.Button("Automatic LOD"))
{
foreach(AutomaticLOD automaticLOD in m_sceneLODObjects)
{
automaticLOD.SetAutomaticCameraLODSwitch(true);
}
}
for (int i = 0; i < m_nMaxLODLevels; i++)
{
if (GUILayout.Button("LOD " + i))
{
foreach(AutomaticLOD automaticLOD in m_sceneLODObjects)
{
automaticLOD.SetAutomaticCameraLODSwitch(false);
automaticLOD.SwitchToLOD(i, true);
}
}
}
GUILayout.EndHorizontal();
GUILayout.Space(20);
int nLODVertexCount = 0;
int nTotalVertexCount = 0;
foreach(AutomaticLOD automaticLOD in m_sceneLODObjects)
{
nLODVertexCount += automaticLOD.GetCurrentVertexCount(true);
nTotalVertexCount += automaticLOD.GetOriginalVertexCount(true);
}
GUILayout.Label("Vertex count: " + nLODVertexCount + "/" + nTotalVertexCount + " " + Mathf.RoundToInt(100.0f * ((float)nLODVertexCount / (float)nTotalVertexCount)).ToString() + "%");
GUILayout.Space(20);
}
private void SetActiveCamera(int index)
{
foreach (SceneCamera sceneCamera in SceneCameras)
{
sceneCamera.m_camera.gameObject.SetActive(false);
}
m_selectedCamera = SceneCameras[index];
m_selectedCamera.m_camera.gameObject.SetActive(true);
m_selectedCamera.m_camera.transform.position = m_selectedCamera.m_v3InitialCameraPosition;
m_fCurrentDistanceSlider = m_selectedCamera.m_near / (m_selectedCamera.m_near - m_selectedCamera.m_far);
}
private void UpdateCamera(float fPos)
{
Vector3 v3Position = Vector3.Lerp(m_selectedCamera.m_v3InitialCameraPosition + (m_selectedCamera.m_v3ViewDir * m_selectedCamera.m_near),
m_selectedCamera.m_v3InitialCameraPosition + (m_selectedCamera.m_v3ViewDir * m_selectedCamera.m_far),
fPos);
m_selectedCamera.m_camera.transform.position = v3Position;
}
private void AddMaterials(GameObject theGameObject, Dictionary<GameObject, Material[]> dicMaterials)
{
Renderer theRenderer = theGameObject.GetComponent<Renderer>();
AutomaticLOD automaticLOD = theGameObject.GetComponent<AutomaticLOD>();
if (theRenderer != null && theRenderer.sharedMaterials != null && automaticLOD != null && automaticLOD != null)
{
dicMaterials.Add(theGameObject, theRenderer.sharedMaterials);
}
for (int i = 0; i < theGameObject.transform.childCount; i++)
{
AddMaterials(theGameObject.transform.GetChild(i).gameObject, dicMaterials);
}
}
private void SetWireframe(bool bEnabled)
{
m_bWireframe = bEnabled;
foreach (KeyValuePair<GameObject, Material[]> pair in m_objectMaterials)
{
Renderer theRenderer = pair.Key.GetComponent<Renderer>();
if (bEnabled)
{
Material[] materials = new Material[pair.Value.Length];
for (int i = 0; i < pair.Value.Length; i++)
{
materials[i] = WireframeMaterial;
}
theRenderer.sharedMaterials = materials;
}
else
{
theRenderer.sharedMaterials = pair.Value;
}
}
}
Dictionary<GameObject, Material[]> m_objectMaterials;
SceneCamera m_selectedCamera;
bool m_bWireframe;
List<AutomaticLOD> m_sceneLODObjects;
int m_nMaxLODLevels;
float m_fCurrentDistanceSlider;
int m_nCamMode = 0; // -1 = zoom out, 1 = zoom in
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5811c134011b7ac469bb48c134040d30
timeCreated: 1438106980
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,48 @@
using UnityEngine;
using System.Collections;
public class LODSceneSelection : MonoBehaviour
{
[System.Serializable]
public class SceneOption
{
public string m_sceneName;
public string m_sceneDisplayName;
}
public int BoxWidth = 300;
public int BoxHeight = 50;
public int MarginH = 20;
public int MarginV = 20;
public SceneOption[] SceneOptions;
void OnGUI()
{
Rect boxRect = new Rect((Screen.width / 2) - (BoxWidth / 2), 0, BoxWidth, BoxHeight);
Rect areaRect = new Rect(boxRect.x + MarginH, boxRect.y + MarginV, BoxWidth - (MarginH * 2), BoxHeight - (MarginV * 2));
GUI.Box(boxRect, "");
GUI.Box(boxRect, "");
GUILayout.BeginArea(areaRect);
GUILayout.Label("Scene selection:");
GUILayout.BeginHorizontal();
foreach(SceneOption sceneOption in SceneOptions)
{
if(GUILayout.Button(sceneOption.m_sceneDisplayName))
{
UnityEngine.SceneManagement.SceneManager.LoadScene(sceneOption.m_sceneName);
}
}
if (GUILayout.Button("Exit"))
{
Application.Quit();
}
GUILayout.EndHorizontal();
GUILayout.EndArea();
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5cf189c258aa10a4eb03811a139fdea0
timeCreated: 1438135577
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e0889086c0bdcc3459025a94be2da0b4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d15024d8291bfb3408ecafe326e6f235
timeCreated: 1434653206
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2cb20282246102f4db576c4bfaae571e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e90785789c206fa4e951b02cff2c61c8
timeCreated: 1434653219
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 157cba43bc196cc44b6231165942c1f6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 254d70a8b3d89324da256e5cffdd1daa
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c0aaa0eba67f86b4aade715580d29551
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,326 @@
using System;
using UnityEngine;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using UltimateGameTools.MeshSimplifier;
public class SimplifyMeshPreview : MonoBehaviour
{
[Serializable]
public class ShowcaseObject
{
public MeshSimplify m_meshSimplify;
public Vector3 m_position;
public Vector3 m_angles;
public Vector3 m_rotationAxis = Vector3.up;
public string m_description;
}
public ShowcaseObject[] ShowcaseObjects;
public Material WireframeMaterial;
public float MouseSensitvity = 0.3f;
public float MouseReleaseSpeed = 3.0f;
void Start ()
{
if (ShowcaseObjects != null && ShowcaseObjects.Length > 0)
{
for (int i = 0; i < ShowcaseObjects.Length; i++)
{
ShowcaseObjects[i].m_description = ShowcaseObjects[i].m_description.Replace("\\n", Environment.NewLine);
}
SetActiveObject(0);
}
Simplifier.CoroutineFrameMiliseconds = 20;
}
void Progress(string strTitle, string strMessage, float fT)
{
int nPercent = Mathf.RoundToInt(fT * 100.0f);
if(nPercent != m_nLastProgress || m_strLastTitle != strTitle || m_strLastMessage != strMessage)
{
m_strLastTitle = strTitle;
m_strLastMessage = strMessage;
m_nLastProgress = nPercent;
}
}
void Update()
{
if(Input.GetKeyDown(KeyCode.F1))
{
m_bGUIEnabled = !m_bGUIEnabled;
}
if (Input.GetKeyDown(KeyCode.W))
{
m_bWireframe = !m_bWireframe;
SetWireframe(m_bWireframe);
}
if (m_selectedMeshSimplify != null)
{
if (Input.GetMouseButton(0) && Input.mousePosition.y > 100)
{
Vector3 v3Angles = ShowcaseObjects[m_nSelectedIndex].m_rotationAxis * -((Input.mousePosition.x - m_fLastMouseX) * MouseSensitvity);
m_selectedMeshSimplify.transform.Rotate(v3Angles, Space.Self);
}
else if (Input.GetMouseButtonUp(0) && Input.mousePosition.y > 100)
{
m_fRotationSpeed = -(Input.mousePosition.x - m_fLastMouseX) * MouseReleaseSpeed;
}
else
{
Vector3 v3Angles = ShowcaseObjects[m_nSelectedIndex].m_rotationAxis * (m_fRotationSpeed * Time.deltaTime);
m_selectedMeshSimplify.transform.Rotate(v3Angles, Space.Self);
}
}
m_fLastMouseX = Input.mousePosition.x;
}
void OnGUI()
{
// Exit menu
int BoxWidth = 150;
int BoxHeight = 50;
int MarginH = 20;
int MarginV = 10;
Rect boxRect = new Rect((Screen.width / 2) - (BoxWidth / 2), 0, BoxWidth, BoxHeight);
Rect areaRect = new Rect(boxRect.x + MarginH, boxRect.y + MarginV, BoxWidth - (MarginH * 2), BoxHeight - (MarginV * 2));
//GUI.Box(boxRect, "");
//GUI.Box(boxRect, "");
GUILayout.BeginArea(areaRect);
if(GUILayout.Button("Exit"))
{
Application.Quit();
}
GUILayout.EndArea();
// Main menu
if(m_bGUIEnabled == false)
{
return;
}
int nWidth = 400;
if(ShowcaseObjects == null)
{
return;
}
bool bAllowInteract = true;
if (!string.IsNullOrEmpty(m_strLastTitle) && !string.IsNullOrEmpty(m_strLastMessage))
{
bAllowInteract = false;
}
GUI.Box(new Rect(0, 0, nWidth + 10, 400), "");
GUILayout.Label("Select model:", GUILayout.Width(nWidth));
GUILayout.BeginHorizontal();
for (int i = 0; i < ShowcaseObjects.Length; i++)
{
if (GUILayout.Button(ShowcaseObjects[i].m_meshSimplify.name) && bAllowInteract)
{
if (m_selectedMeshSimplify != null)
{
DestroyImmediate(m_selectedMeshSimplify.gameObject);
}
SetActiveObject(i);
}
}
GUILayout.EndHorizontal();
if (m_selectedMeshSimplify != null)
{
GUILayout.Space(20);
GUILayout.Label(ShowcaseObjects[m_nSelectedIndex].m_description);
GUILayout.Space(20);
GUI.changed = false;
m_bWireframe = GUILayout.Toggle(m_bWireframe, "Show wireframe");
if (GUI.changed && m_selectedMeshSimplify != null)
{
SetWireframe(m_bWireframe);
}
GUILayout.Space(20);
int nSimplifiedVertices = m_selectedMeshSimplify.GetSimplifiedVertexCount(true);
int nTotalVertices = m_selectedMeshSimplify.GetOriginalVertexCount(true);
GUILayout.Label("Vertex count: " + nSimplifiedVertices + "/" + nTotalVertices + " " + (Mathf.RoundToInt(((float)nSimplifiedVertices / (float)nTotalVertices) * 100.0f).ToString() + "% from original"));
GUILayout.Space(20);
if (!string.IsNullOrEmpty(m_strLastTitle) && !string.IsNullOrEmpty(m_strLastMessage))
{
GUILayout.Label(m_strLastTitle + ": " + m_strLastMessage, GUILayout.MaxWidth(nWidth));
GUI.color = Color.blue;
Rect lastRect = GUILayoutUtility.GetLastRect();
GUI.Box(new Rect(10, lastRect.yMax + 5, 204, 24), "");
GUI.Box(new Rect(12, lastRect.yMax + 7, m_nLastProgress * 2, 20), "");
}
else
{
GUILayout.Label("Vertices: " + (m_fVertexAmount * 100.0f).ToString("0.00") + "%");
m_fVertexAmount = GUILayout.HorizontalSlider(m_fVertexAmount, 0.0f, 1.0f, GUILayout.Width(200));
GUILayout.BeginHorizontal();
GUILayout.Space(3);
if (GUILayout.Button("Compute simplified mesh", GUILayout.Width(200)))
{
StartCoroutine(ComputeMeshWithVertices(m_fVertexAmount));
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
}
}
private void SetActiveObject(int index)
{
m_nSelectedIndex = index;
MeshSimplify meshSimplify = Instantiate(ShowcaseObjects[index].m_meshSimplify);
meshSimplify.transform.position = ShowcaseObjects[index].m_position;
meshSimplify.transform.rotation = Quaternion.Euler(ShowcaseObjects[index].m_angles);
m_selectedMeshSimplify = meshSimplify;
m_objectMaterials = new Dictionary<GameObject, Material[]>();
AddMaterials(meshSimplify.gameObject, m_objectMaterials);
m_bWireframe = false;
}
private void AddMaterials(GameObject theGameObject, Dictionary<GameObject, Material[]> dicMaterials)
{
Renderer theRenderer = theGameObject.GetComponent<Renderer>();
MeshSimplify meshSimplify = theGameObject.GetComponent<MeshSimplify>();
if (theRenderer != null && theRenderer.sharedMaterials != null && meshSimplify != null)
{
dicMaterials.Add(theGameObject, theRenderer.sharedMaterials);
}
for (int i = 0; i < theGameObject.transform.childCount; i++)
{
AddMaterials(theGameObject.transform.GetChild(i).gameObject, dicMaterials);
}
}
private void SetWireframe(bool bEnabled)
{
m_bWireframe = bEnabled;
foreach (KeyValuePair<GameObject, Material[]> pair in m_objectMaterials)
{
Renderer theRenderer = pair.Key.GetComponent<Renderer>();
if (bEnabled)
{
Material[] materials = new Material[pair.Value.Length];
for (int i = 0; i < pair.Value.Length; i++)
{
materials[i] = WireframeMaterial;
}
theRenderer.sharedMaterials = materials;
}
else
{
theRenderer.sharedMaterials = pair.Value;
}
}
}
private IEnumerator ComputeMeshWithVertices(float fAmount)
{
foreach (KeyValuePair<GameObject, Material[]> pair in m_objectMaterials)
{
MeshSimplify meshSimplify = pair.Key.GetComponent<MeshSimplify>();
MeshFilter meshFilter = pair.Key.GetComponent<MeshFilter>();
SkinnedMeshRenderer skin = pair.Key.GetComponent<SkinnedMeshRenderer>();
if (meshSimplify && (meshFilter != null || skin != null))
{
Mesh newMesh = null;
if (meshFilter != null)
{
newMesh = Mesh.Instantiate(meshFilter.sharedMesh);
}
else if (skin != null)
{
newMesh = Mesh.Instantiate(skin.sharedMesh);
}
if (meshSimplify.GetMeshSimplifier() != null)
{
meshSimplify.GetMeshSimplifier().CoroutineEnded = false;
StartCoroutine(meshSimplify.GetMeshSimplifier().ComputeMeshWithVertexCount(pair.Key, newMesh, Mathf.RoundToInt(fAmount * meshSimplify.GetMeshSimplifier().GetOriginalMeshUniqueVertexCount()), meshSimplify.name, Progress));
while (meshSimplify.GetMeshSimplifier().CoroutineEnded == false)
{
yield return null;
}
if (meshFilter != null)
{
meshFilter.mesh = newMesh;
}
else if (skin != null)
{
skin.sharedMesh = newMesh;
}
meshSimplify.m_simplifiedMesh = newMesh;
}
}
}
m_strLastTitle = "";
m_strLastMessage = "";
m_nLastProgress = 0;
}
Dictionary<GameObject, Material[]> m_objectMaterials;
MeshSimplify m_selectedMeshSimplify;
int m_nSelectedIndex = -1;
bool m_bWireframe;
float m_fRotationSpeed = 10.0f;
float m_fLastMouseX;
Mesh m_newMesh;
int m_nLastProgress = -1;
string m_strLastTitle = "";
string m_strLastMessage = "";
float m_fVertexAmount = 1.0f;
bool m_bGUIEnabled = true;
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 17244aba0a90b4a4189405b3405f74ae
timeCreated: 1438106980
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 7a596981819401047ad211da94723baa
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,763 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using UltimateGameTools.MeshSimplifier;
[CustomEditor(typeof(MeshSimplify)), CanEditMultipleObjects]
public class MeshSimplifyEditor : Editor
{
void Progress(string strTitle, string strMessage, float fT)
{
int nPercent = Mathf.RoundToInt(fT * 100.0f);
if(nPercent != s_nLastProgress || s_strLastTitle != strTitle || s_strLastMessage != strMessage)
{
s_strLastTitle = strTitle;
s_strLastMessage = strMessage;
s_nLastProgress = nPercent;
if(EditorUtility.DisplayCancelableProgressBar(strTitle, strMessage, fT))
{
Simplifier.Cancelled = true;
}
}
}
void OnEnable()
{
PropertyGenerateIncludeChildren = serializedObject.FindProperty("m_bGenerateIncludeChildren");
PropertyEnablePrefabUsage = serializedObject.FindProperty("m_bEnablePrefabUsage");
PropertyExpandRelevanceSpheres = serializedObject.FindProperty("m_bExpandRelevanceSpheres");
PropertyRelevanceSpheres = serializedObject.FindProperty("m_aRelevanceSpheres");
PropertyOverrideRootSettings = serializedObject.FindProperty("m_bOverrideRootSettings");
PropertyVertexAmount = serializedObject.FindProperty("m_fVertexAmount");
PropertyUseEdgeLength = serializedObject.FindProperty("m_bUseEdgeLength");
PropertyUseCurvature = serializedObject.FindProperty("m_bUseCurvature");
PropertyProtectTexture = serializedObject.FindProperty("m_bProtectTexture");
PropertyLockBorder = serializedObject.FindProperty("m_bLockBorder");
PropertyDataDirty = serializedObject.FindProperty("m_bDataDirty");
PropertyExcludedFromTree = serializedObject.FindProperty("m_bExcludedFromTree");
m_bComputeMesh = false;
m_bEnablePrefabUsage = false;
m_bDisablePrefabUsage = false;
m_bDeleteData = false;
m_bRemoveFromTree = false;
m_bSetupNewRelevanceSphere = false;
SetHideFlags();
}
void OnDisable()
{
if(m_bPreviewOriginalMesh)
{
foreach (Object targetObject in targets)
{
if (targetObject != null)
{
MeshSimplify meshSimplify = targetObject as MeshSimplify;
meshSimplify.AssignSimplifiedMesh(true);
}
}
}
}
void OnSceneGUI()
{
MeshSimplify meshSimplify = target as MeshSimplify;
bool bDrawSpheres = true;
if (meshSimplify.m_meshSimplifyRoot != null)
{
if (meshSimplify.m_meshSimplifyRoot.m_bExpandRelevanceSpheres == false)
{
bDrawSpheres = false;
}
}
else
{
if (meshSimplify.m_bExpandRelevanceSpheres == false)
{
bDrawSpheres = false;
}
}
if (meshSimplify.m_aRelevanceSpheres != null && bDrawSpheres)
{
for (int nSphere = 0; nSphere < meshSimplify.m_aRelevanceSpheres.Length; nSphere++)
{
if (meshSimplify.m_aRelevanceSpheres[nSphere].m_bExpanded == false)
{
continue;
}
RelevanceSphere relevanceSphere = meshSimplify.m_aRelevanceSpheres[nSphere] as RelevanceSphere;
if (Tools.current == Tool.Move)
{
EditorGUI.BeginChangeCheck();
Vector3 v3Position = Handles.PositionHandle(relevanceSphere.m_v3Position, Quaternion.Euler(relevanceSphere.m_v3Rotation));
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(meshSimplify, "Move Relevance Sphere");
relevanceSphere.m_v3Position = v3Position;
meshSimplify.RestoreOriginalMesh(false, true);
meshSimplify.SetDataDirty(true);
EditorUtility.SetDirty(target);
}
}
else if (Tools.current == Tool.Rotate)
{
EditorGUI.BeginChangeCheck();
Quaternion qRotation = Handles.RotationHandle(Quaternion.Euler(relevanceSphere.m_v3Rotation), relevanceSphere.m_v3Position);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(meshSimplify, "Rotate Relevance Sphere");
relevanceSphere.m_v3Rotation = qRotation.eulerAngles;
meshSimplify.RestoreOriginalMesh(false, true);
meshSimplify.SetDataDirty(true);
EditorUtility.SetDirty(target);
}
}
else if (Tools.current == Tool.Scale)
{
EditorGUI.BeginChangeCheck();
Vector3 v3Scale = Handles.ScaleHandle(relevanceSphere.m_v3Scale, relevanceSphere.m_v3Position, Quaternion.Euler(relevanceSphere.m_v3Rotation), HandleUtility.GetHandleSize(relevanceSphere.m_v3Position) * 1.0f);
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(meshSimplify, "Scale Relevance Sphere");
relevanceSphere.m_v3Scale = v3Scale;
meshSimplify.RestoreOriginalMesh(false, true);
meshSimplify.SetDataDirty(true);
EditorUtility.SetDirty(target);
}
}
if(Event.current.type == EventType.Repaint)
{
Matrix4x4 mtxHandles = Handles.matrix;
Handles.matrix = Matrix4x4.TRS(relevanceSphere.m_v3Position, Quaternion.Euler(relevanceSphere.m_v3Rotation), relevanceSphere.m_v3Scale);
Handles.color = new Color(0.0f, 0.0f, 1.0f, 0.5f);
Handles.SphereHandleCap(0, Vector3.zero, Quaternion.identity, 1.0f, EventType.Repaint);
Handles.matrix = mtxHandles;
}
}
}
}
public override void OnInspectorGUI()
{
MeshSimplify meshSimplify;
string strIncludeChildrenLabel = "Recurse Into Children";
int nButtonWidth = 200;
int nButtonWidthSmall = 130;
foreach (Object targetObject in targets)
{
meshSimplify = targetObject as MeshSimplify;
if (meshSimplify.m_meshSimplifyRoot != null && targets.Length > 1)
{
EditorGUILayout.HelpBox("One or more GameObjects of the selection is not a root MeshSimplify GameObject. Only root MeshSimplify GameObjects can be edited at the same time.", MessageType.Warning);
return;
}
}
if (targets.Length > 1)
{
EditorGUILayout.HelpBox("Multiple selection", MessageType.Info);
}
serializedObject.Update();
EditorGUILayout.Space();
meshSimplify = target as MeshSimplify;
if (meshSimplify.m_meshSimplifyRoot == null)
{
EditorGUILayout.PropertyField(PropertyGenerateIncludeChildren, new GUIContent(strIncludeChildrenLabel, "If checked, we will traverse the whole GameObject's hierarchy looking for meshes"));
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(PropertyEnablePrefabUsage, new GUIContent("Enable Prefab Usage", "Will save the generated mesh assets to disk, so that this GameObject can be used as a prefab and be instantiated at runtime. Otherwise the mesh won't be available"));
if (EditorGUI.EndChangeCheck())
{
if (PropertyEnablePrefabUsage.boolValue)
{
m_bEnablePrefabUsage = true;
}
else
{
m_bDisablePrefabUsage = true;
}
}
}
else
{
if (PropertyExcludedFromTree.boolValue)
{
GUILayout.Label("Object has been excluded from mesh simplification.");
}
else
{
GUILayout.Label("Child MeshSimplify GameObject depending on " + meshSimplify.m_meshSimplifyRoot.name);
EditorGUILayout.PropertyField(PropertyOverrideRootSettings, new GUIContent("Override " + meshSimplify.m_meshSimplifyRoot.name + " settings", "Will allow to edit this object's own parameters, instead of inheriting those of the root Automatic LOD GameObject"));
}
}
if (meshSimplify.m_meshSimplifyRoot == null || (PropertyOverrideRootSettings.boolValue == true && PropertyExcludedFromTree.boolValue == false))
{
bool bIsOverriden = PropertyOverrideRootSettings.boolValue == true;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(PropertyUseEdgeLength, new GUIContent("Use Edge Length", "Will take edge length into consideration when simplifying the mesh. Edges with higher length will be more likely to be kept"));
if (EditorGUI.EndChangeCheck())
{
PropertyDataDirty.boolValue = true;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(PropertyUseCurvature, new GUIContent("Use Curvature", "Will take the angle between triangles into consideration. Edges with smaller angles between two triangles will be more likely to be kept when simplifying the mesh."));
if (EditorGUI.EndChangeCheck())
{
PropertyDataDirty.boolValue = true;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(PropertyProtectTexture, new GUIContent("Protect Texture", "Will try to keep mapping integrity during the process of mesh simplification"));
if (EditorGUI.EndChangeCheck())
{
PropertyDataDirty.boolValue = true;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(PropertyLockBorder, new GUIContent("Keep Borders", "Will try to keep those vertices that form an object's border"));
if (EditorGUI.EndChangeCheck())
{
PropertyDataDirty.boolValue = true;
}
EditorGUILayout.Space();
float fVertexAmount = EditorGUILayout.Slider(new GUIContent("Vertex %", "The percentage of vertices from the original mesh to keep when simplifying it"), PropertyVertexAmount.floatValue * 100.0f, 0.0f, 100.0f);
PropertyVertexAmount.floatValue = Mathf.Clamp01(fVertexAmount / 100.0f);
int nSimplifiedMeshVertexCount = meshSimplify.GetSimplifiedVertexCount(bIsOverriden == false);
int nMeshVertexCount = meshSimplify.GetOriginalVertexCount(bIsOverriden == false);
EditorGUILayout.LabelField("Vertex count: " + nSimplifiedMeshVertexCount + "/" + nMeshVertexCount);
int nSimplifiedMeshTriangleCount = meshSimplify.GetSimplifiedTriangleCount(bIsOverriden == false);
int nMeshTriangleCount = meshSimplify.GetOriginalTriangleCount(bIsOverriden == false);
EditorGUILayout.LabelField("Triangle count: " + nSimplifiedMeshTriangleCount + "/" + nMeshTriangleCount);
//EditorGUILayout.LabelField("Child nodes: " + (meshSimplify.m_listDependentChildren == null ? 0 : meshSimplify.m_listDependentChildren.Count));
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
m_bPreviewOriginalMesh = EditorGUILayout.Toggle(new GUIContent("Preview Original Mesh", "Allows to quickly switch between viewing the simplified mesh and the original mesh to check the reduction quality"), m_bPreviewOriginalMesh);
if (EditorGUI.EndChangeCheck())
{
if (m_bPreviewOriginalMesh)
{
meshSimplify.RestoreOriginalMesh(false, bIsOverriden == false);
}
else
{
meshSimplify.AssignSimplifiedMesh(bIsOverriden == false);
}
}
EditorGUILayout.Space();
}
if (meshSimplify.m_meshSimplifyRoot == null)
{
PropertyExpandRelevanceSpheres.boolValue = EditorGUILayout.Foldout(PropertyExpandRelevanceSpheres.boolValue, new GUIContent("Vertex Relevance Modifiers:"));
if (PropertyExpandRelevanceSpheres.boolValue)
{
EditorGUILayout.HelpBox("Use vertex relevance spheres to select which vertices should be preserved with more or less priority when simplifying the mesh.", MessageType.Info);
EditorGUILayout.Space();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(new GUIContent("Add New Sphere", "Adds a new vertex relevance sphere"), GUILayout.Width(nButtonWidthSmall)))
{
PropertyRelevanceSpheres.InsertArrayElementAtIndex(0);
PropertyDataDirty.boolValue = true;
m_bSetupNewRelevanceSphere = true;
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
EditorGUILayout.Space();
EditorGUI.indentLevel++;
int nSphereToDelete = -1;
for (int i = 0; i < PropertyRelevanceSpheres.arraySize; i++)
{
SerializedProperty elementProperty = PropertyRelevanceSpheres.GetArrayElementAtIndex(i);
SerializedProperty elementExpanded = elementProperty.FindPropertyRelative("m_bExpanded");
SerializedProperty elementPosition = elementProperty.FindPropertyRelative("m_v3Position");
SerializedProperty elementRotation = elementProperty.FindPropertyRelative("m_v3Rotation");
SerializedProperty elementScale = elementProperty.FindPropertyRelative("m_v3Scale");
SerializedProperty elementRelevance = elementProperty.FindPropertyRelative("m_fRelevance");
elementExpanded.boolValue = EditorGUILayout.Foldout(elementExpanded.boolValue, new GUIContent("Sphere"));
if (elementExpanded.boolValue)
{
bool bWideMode = EditorGUIUtility.wideMode;
EditorGUIUtility.wideMode = true;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(elementPosition, new GUIContent("Position"));
if (EditorGUI.EndChangeCheck())
{
PropertyDataDirty.boolValue = true;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(elementRotation, new GUIContent("Rotation"));
if (EditorGUI.EndChangeCheck())
{
PropertyDataDirty.boolValue = true;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(elementScale, new GUIContent("Scale"));
if (EditorGUI.EndChangeCheck())
{
PropertyDataDirty.boolValue = true;
}
EditorGUI.BeginChangeCheck();
elementRelevance.floatValue = EditorGUILayout.Slider(new GUIContent("Relevance", "Tells the simplification algorithm how relevant the vertices inside this sphere are. Default relevance is 0, use lower values to discard non important vertices, and higher values to keep them before others when simplifying the mesh"), elementRelevance.floatValue, -1.0f, 1.0f);
if (EditorGUI.EndChangeCheck())
{
PropertyDataDirty.boolValue = true;
}
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(new GUIContent("Remove Sphere", "Removes this simplification sphere"), GUILayout.Width(nButtonWidthSmall)))
{
nSphereToDelete = i;
PropertyDataDirty.boolValue = true;
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
EditorGUIUtility.wideMode = bWideMode;
}
}
if (nSphereToDelete >= 0)
{
PropertyRelevanceSpheres.DeleteArrayElementAtIndex(nSphereToDelete);
}
EditorGUI.indentLevel--;
}
EditorGUILayout.Space();
}
if (meshSimplify.m_meshSimplifyRoot == null || (PropertyOverrideRootSettings.boolValue == true && PropertyExcludedFromTree.boolValue == false))
{
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(new GUIContent("Compute mesh", "Starts the mesh simplification process and assigns the GameObject the new simplified mesh"), GUILayout.Width(nButtonWidth)))
{
m_bComputeMesh = true;
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(new GUIContent("Restore Original Mesh...", "Deletes the simplified data and restores the original mesh"), GUILayout.Width(nButtonWidth)))
{
if (EditorUtility.DisplayDialog("Delete all data and restore original mesh?", "Are you sure you want to delete all data and restore the original mesh?", "Delete", "Cancel"))
{
m_bDeleteData = true;
}
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
if (meshSimplify.m_meshSimplifyRoot != null && PropertyExcludedFromTree.boolValue == false)
{
EditorGUILayout.Space();
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button(new GUIContent("Exclude from tree...", "Restores this GameObject's original mesh and excludes it from the mesh simplification tree"), GUILayout.Width(nButtonWidth)))
{
if (EditorUtility.DisplayDialog("Remove from tree?", "Are you sure you want to restore this gameobject's mesh and exclude it from the tree?", "Remove", "Cancel"))
{
m_bRemoveFromTree = true;
}
}
GUILayout.FlexibleSpace();
GUILayout.EndHorizontal();
}
serializedObject.ApplyModifiedProperties();
bool bRepaint = false;
if(m_bEnablePrefabUsage)
{
m_bEnablePrefabUsage = false;
SaveMeshAssets();
}
if(m_bDisablePrefabUsage)
{
m_bDisablePrefabUsage = false;
if (PropertyEnablePrefabUsage.boolValue == false)
{
foreach (Object targetObject in targets)
{
meshSimplify = targetObject as MeshSimplify;
meshSimplify.DisablePrefabUsage(true);
}
}
}
if (m_bComputeMesh && Event.current.type == EventType.Repaint)
{
m_bComputeMesh = false;
Simplifier.Cancelled = false;
foreach (Object targetObject in targets)
{
meshSimplify = targetObject as MeshSimplify;
if (meshSimplify.HasData() == false)
{
if (PropertyGenerateIncludeChildren.boolValue == false)
{
if (MeshSimplify.HasValidMeshData(meshSimplify.gameObject) == false)
{
EditorUtility.DisplayDialog("Error", "Object " + meshSimplify.name + " has no MeshFilter nor Skinned Mesh to process. Please use the \"" + strIncludeChildrenLabel + "\" parameter if you want to process the whole " + meshSimplify.name + " hierarchy for meshes", "OK");
continue;
}
}
}
try
{
if (meshSimplify.HasDataDirty() || meshSimplify.HasData() == false || meshSimplify.HasNonMeshSimplifyGameObjectsInTree())
{
meshSimplify.RestoreOriginalMesh(true, meshSimplify.m_meshSimplifyRoot == null);
meshSimplify.ComputeData(meshSimplify.m_meshSimplifyRoot == null, Progress);
if (Simplifier.Cancelled)
{
meshSimplify.RestoreOriginalMesh(true, meshSimplify.m_meshSimplifyRoot == null);
break;
}
}
meshSimplify.ComputeMesh(meshSimplify.m_meshSimplifyRoot == null, Progress);
if (Simplifier.Cancelled)
{
break;
}
meshSimplify.AssignSimplifiedMesh(meshSimplify.m_meshSimplifyRoot == null);
if (meshSimplify.m_strAssetPath != null && meshSimplify.m_bEnablePrefabUsage)
{
SaveMeshAssets();
}
}
catch (System.Exception e)
{
Debug.LogError("Error generating mesh: " + e.Message + " Stack: " + e.StackTrace);
EditorUtility.ClearProgressBar();
Simplifier.Cancelled = false;
}
Simplifier.Cancelled = false;
}
bRepaint = true;
EditorUtility.ClearProgressBar();
}
if (m_bDeleteData && Event.current.type == EventType.Repaint)
{
m_bDeleteData = false;
foreach (Object targetObject in targets)
{
meshSimplify = targetObject as MeshSimplify;
meshSimplify.RestoreOriginalMesh(true, meshSimplify.m_meshSimplifyRoot == null);
RemoveChildMeshSimplifyComponents(meshSimplify);
}
bRepaint = true;
}
if (m_bRemoveFromTree && Event.current.type == EventType.Repaint)
{
m_bRemoveFromTree = false;
meshSimplify = target as MeshSimplify;
meshSimplify.RemoveFromTree();
if (Application.isEditor && Application.isPlaying == false)
{
UnityEngine.Object.DestroyImmediate(meshSimplify);
}
else
{
UnityEngine.Object.Destroy(meshSimplify);
}
bRepaint = true;
}
if (m_bSetupNewRelevanceSphere)
{
m_bSetupNewRelevanceSphere = false;
foreach (Object targetObject in targets)
{
meshSimplify = targetObject as MeshSimplify;
if (meshSimplify.m_aRelevanceSpheres != null && meshSimplify.m_aRelevanceSpheres.Length > 0)
{
meshSimplify.m_aRelevanceSpheres[0].SetDefault(meshSimplify.transform, 0.0f);
}
}
}
if (bRepaint)
{
Repaint();
}
}
void RemoveChildMeshSimplifyComponents(MeshSimplify meshSimplify)
{
RemoveChildMeshSimplifyComponentsRecursive(meshSimplify.gameObject, meshSimplify.gameObject, true);
}
void RemoveChildMeshSimplifyComponentsRecursive(GameObject root, GameObject gameObject, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null && meshSimplify.m_meshSimplifyRoot != null)
{
if (Application.isEditor && Application.isPlaying == false)
{
UnityEngine.Object.DestroyImmediate(meshSimplify);
}
else
{
UnityEngine.Object.Destroy(meshSimplify);
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
RemoveChildMeshSimplifyComponentsRecursive(root, gameObject.transform.GetChild(nChild).gameObject, true);
}
}
}
void SaveMeshAssets()
{
try
{
foreach (Object targetObject in targets)
{
MeshSimplify meshSimplify = targetObject as MeshSimplify;
GameObject gameObject = meshSimplify.gameObject;
if (meshSimplify.m_meshSimplifyRoot == null && meshSimplify.m_bEnablePrefabUsage)
{
string strMeshAssetPath = meshSimplify.m_strAssetPath;
if (string.IsNullOrEmpty(strMeshAssetPath))
{
//Debug.Log("Showing file selection panel");
strMeshAssetPath = UnityEditor.EditorUtility.SaveFilePanelInProject("Save mesh asset(s)", "mesh_" + gameObject.name + gameObject.GetInstanceID().ToString() + ".asset", "asset", "Please enter a file name to save the mesh asset(s) to");
if (strMeshAssetPath.Length == 0)
{
//Debug.LogWarning("strMeshAssetPath.Length == 0. User cancelled?");
return;
}
//Debug.Log("User selected " + strMeshAssetPath + " using panel.");
meshSimplify.m_strAssetPath = strMeshAssetPath;
}
int nCounter = 0;
//Debug.Log("Saving files to " + strMeshAssetPath + ". Exists previously?: " + System.IO.File.Exists(strMeshAssetPath));
SaveMeshAssetsRecursive(gameObject, gameObject, strMeshAssetPath, true, System.IO.File.Exists(strMeshAssetPath), ref nCounter);
}
}
}
catch (System.Exception e)
{
Debug.LogError("Error saving mesh assets to disk: " + e.Message + " Stack: " + e.StackTrace);
EditorUtility.ClearProgressBar();
Simplifier.Cancelled = false;
}
EditorUtility.ClearProgressBar();
UnityEditor.AssetDatabase.Refresh();
Simplifier.Cancelled = false;
}
bool SaveMeshAssetsRecursive(GameObject root, GameObject gameObject, string strFile, bool bRecurseIntoChildren, bool bAssetAlreadyCreated, ref int nProgressElementsCounter)
{
if(gameObject == null || Simplifier.Cancelled)
{
return bAssetAlreadyCreated;
}
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null && meshSimplify.HasData() && (meshSimplify.m_meshSimplifyRoot == null || meshSimplify.m_meshSimplifyRoot.gameObject == root))
{
int nTotalProgressElements = meshSimplify.m_meshSimplifyRoot != null ? (meshSimplify.m_meshSimplifyRoot.m_listDependentChildren.Count + 1) : 1;
if (meshSimplify.m_simplifiedMesh != null && MeshSimplify.HasValidMeshData(meshSimplify.gameObject))
{
float fT = (float)nProgressElementsCounter / (float)nTotalProgressElements;
Progress("Saving meshes to asset file", meshSimplify.name, fT);
if (Simplifier.Cancelled)
{
return bAssetAlreadyCreated;
}
if (bAssetAlreadyCreated == false && UnityEditor.AssetDatabase.Contains(meshSimplify.m_simplifiedMesh) == false)
{
//Debug.Log("Creating asset " + meshSimplify.m_simplifiedMesh.name);
UnityEditor.AssetDatabase.CreateAsset(meshSimplify.m_simplifiedMesh, strFile);
bAssetAlreadyCreated = true;
}
else
{
if (UnityEditor.AssetDatabase.Contains(meshSimplify.m_simplifiedMesh) == false)
{
//Debug.Log("Adding asset " + meshSimplify.m_simplifiedMesh.name);
UnityEditor.AssetDatabase.AddObjectToAsset(meshSimplify.m_simplifiedMesh, strFile);
UnityEditor.AssetDatabase.ImportAsset(UnityEditor.AssetDatabase.GetAssetPath(meshSimplify.m_simplifiedMesh));
}
}
nProgressElementsCounter++;
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
bAssetAlreadyCreated = SaveMeshAssetsRecursive(root, gameObject.transform.GetChild(nChild).gameObject, strFile, bRecurseIntoChildren, bAssetAlreadyCreated, ref nProgressElementsCounter);
}
}
return bAssetAlreadyCreated;
}
void SetHideFlags()
{
foreach (Object targetObject in targets)
{
MeshSimplify meshSimplify = targetObject as MeshSimplify;
if (meshSimplify.m_meshSimplifyRoot == null)
{
SetHideFlagsRecursive(meshSimplify.gameObject, meshSimplify.gameObject, true);
}
}
}
void SetHideFlagsRecursive(GameObject root, GameObject gameObject, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify && meshSimplify.GetMeshSimplifier())
{
meshSimplify.GetMeshSimplifier().hideFlags = HideFlags.HideInInspector;
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
SetHideFlagsRecursive(root, gameObject.transform.GetChild(nChild).gameObject, true);
}
}
}
bool m_bComputeMesh = false;
bool m_bEnablePrefabUsage = false;
bool m_bDisablePrefabUsage = false;
bool m_bDeleteData = false;
bool m_bRemoveFromTree = false;
bool m_bSetupNewRelevanceSphere = false;
bool m_bPreviewOriginalMesh = false;
SerializedProperty PropertyGenerateIncludeChildren;
SerializedProperty PropertyEnablePrefabUsage;
SerializedProperty PropertyExpandRelevanceSpheres;
SerializedProperty PropertyRelevanceSpheres;
SerializedProperty PropertyOverrideRootSettings;
SerializedProperty PropertyVertexAmount;
SerializedProperty PropertyUseEdgeLength;
SerializedProperty PropertyUseCurvature;
SerializedProperty PropertyProtectTexture;
SerializedProperty PropertyLockBorder;
SerializedProperty PropertyDataDirty;
SerializedProperty PropertyExcludedFromTree;
static int s_nLastProgress = -1;
static string s_strLastTitle = "";
static string s_strLastMessage = "";
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a52cb74794833b64492fa4b27f8cb797
timeCreated: 1438106980
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ef0e28345212fa344986b5be580ae95c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,862 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using UltimateGameTools.MeshSimplifier;
public class MeshSimplify : MonoBehaviour
{
public bool RecurseIntoChildren
{
get
{
return m_bGenerateIncludeChildren;
}
}
public Simplifier MeshSimplifier
{
get
{
return m_meshSimplifier;
}
set
{
m_meshSimplifier = value;
}
}
[HideInInspector]
public Mesh m_originalMesh = null;
[HideInInspector]
public Mesh m_simplifiedMesh = null;
[HideInInspector]
public bool m_bEnablePrefabUsage = false;
[HideInInspector]
public float m_fVertexAmount = 1.0f;
[HideInInspector]
public string m_strAssetPath = null;
[HideInInspector]
public MeshSimplify m_meshSimplifyRoot;
[HideInInspector]
public List<MeshSimplify> m_listDependentChildren = new List<MeshSimplify>();
[HideInInspector]
public bool m_bExpandRelevanceSpheres = true;
public RelevanceSphere[] m_aRelevanceSpheres = null;
[SerializeField, HideInInspector]
private Simplifier m_meshSimplifier = null;
[SerializeField, HideInInspector]
private bool m_bGenerateIncludeChildren = true;
[SerializeField, HideInInspector]
private bool m_bOverrideRootSettings = false;
[SerializeField, HideInInspector]
private bool m_bUseEdgeLength = true, m_bUseCurvature = true, m_bProtectTexture = true, m_bLockBorder = true;
[SerializeField, HideInInspector]
private bool m_bDataDirty = true;
[SerializeField, HideInInspector]
private bool m_bExcludedFromTree = false;
#if UNITY_EDITOR
public void OnDrawGizmos()
{
if (m_meshSimplifyRoot != null)
{
if (m_meshSimplifyRoot.m_bExpandRelevanceSpheres == false)
{
return;
}
}
else
{
if (m_bExpandRelevanceSpheres == false)
{
return;
}
}
Gizmos.color = Color.red;
RelevanceSphere[] aRelevanceSpheres = m_meshSimplifyRoot != null ? m_meshSimplifyRoot.m_aRelevanceSpheres : m_aRelevanceSpheres;
if (aRelevanceSpheres == null)
{
return;
}
bool bDrawVertices = false;
for (int i = 0; i < UnityEditor.Selection.gameObjects.Length; i++)
{
if (((UnityEditor.Selection.gameObjects[i] == this.gameObject) && m_meshSimplifyRoot == null) || ((m_meshSimplifyRoot != null) && (UnityEditor.Selection.gameObjects[i] == m_meshSimplifyRoot.gameObject)))
{
bDrawVertices = true;
}
}
if (bDrawVertices == false)
{
return;
}
Vector3[] aVerticesWorld = Simplifier.GetWorldVertices(this.gameObject);
if(aVerticesWorld == null)
{
return;
}
Matrix4x4[] aSphereMatrices = new Matrix4x4[aRelevanceSpheres.Length];
for (int nSphere = 0; nSphere < aRelevanceSpheres.Length; nSphere++)
{
aSphereMatrices[nSphere] = Matrix4x4.TRS(aRelevanceSpheres[nSphere].m_v3Position, Quaternion.Euler(aRelevanceSpheres[nSphere].m_v3Rotation), aRelevanceSpheres[nSphere].m_v3Scale).inverse;
}
for (int nVertex = 0; nVertex < aVerticesWorld.Length; nVertex++)
{
for (int nSphere = 0; nSphere < aRelevanceSpheres.Length; nSphere++)
{
if (aRelevanceSpheres[nSphere].m_bExpanded)
{
Vector3 v3VertexSphereLocal = aSphereMatrices[nSphere].MultiplyPoint(aVerticesWorld[nVertex]);
if (v3VertexSphereLocal.magnitude <= 0.5)
{
Gizmos.DrawCube(aVerticesWorld[nVertex], Vector3.one * UnityEditor.HandleUtility.GetHandleSize(aVerticesWorld[nVertex]) * 0.05f);
break;
}
}
}
}
}
#endif
public static bool HasValidMeshData(GameObject go)
{
MeshFilter meshFilter = go.GetComponent<MeshFilter>();
if (meshFilter != null)
{
return true;
}
else
{
SkinnedMeshRenderer skin = go.GetComponent<SkinnedMeshRenderer>();
if (skin != null)
{
return true;
}
}
return false;
}
public static bool IsRootOrBelongsToTree(MeshSimplify meshSimplify, MeshSimplify root)
{
if (meshSimplify == null)
{
return false;
}
return (meshSimplify.m_bExcludedFromTree == false) && ((meshSimplify.m_meshSimplifyRoot == null) || (meshSimplify.m_meshSimplifyRoot == root) || (meshSimplify == root) || (meshSimplify.m_meshSimplifyRoot == root.m_meshSimplifyRoot));
}
public bool IsGenerateIncludeChildrenActive()
{
return m_bGenerateIncludeChildren;
}
public bool HasDependentChildren()
{
return m_listDependentChildren != null && m_listDependentChildren.Count > 0;
}
public bool HasDataDirty()
{
return m_bDataDirty;
}
public bool SetDataDirty(bool bDirty)
{
return m_bDataDirty = bDirty;
}
public bool HasNonMeshSimplifyGameObjectsInTree()
{
return HasNonMeshSimplifyGameObjectsInTreeRecursive(this, this.gameObject);
}
private bool HasNonMeshSimplifyGameObjectsInTreeRecursive(MeshSimplify root, GameObject gameObject)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify == null && HasValidMeshData(gameObject))
{
return true;
}
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
if(HasNonMeshSimplifyGameObjectsInTreeRecursive(root, gameObject.transform.GetChild(nChild).gameObject))
{
return true;
}
}
return false;
}
public void ConfigureSimplifier()
{
m_meshSimplifier.UseEdgeLength = (m_meshSimplifyRoot != null && m_bOverrideRootSettings == false) ? m_meshSimplifyRoot.m_bUseEdgeLength : m_bUseEdgeLength;
m_meshSimplifier.UseCurvature = (m_meshSimplifyRoot != null && m_bOverrideRootSettings == false) ? m_meshSimplifyRoot.m_bUseCurvature : m_bUseCurvature;
m_meshSimplifier.ProtectTexture = (m_meshSimplifyRoot != null && m_bOverrideRootSettings == false) ? m_meshSimplifyRoot.m_bProtectTexture : m_bProtectTexture;
m_meshSimplifier.LockBorder = (m_meshSimplifyRoot != null && m_bOverrideRootSettings == false) ? m_meshSimplifyRoot.m_bLockBorder : m_bLockBorder;
}
public Simplifier GetMeshSimplifier()
{
return m_meshSimplifier;
}
public void ComputeData(bool bRecurseIntoChildren, Simplifier.ProgressDelegate progress = null)
{
ComputeDataRecursive(this, this.gameObject, bRecurseIntoChildren, progress);
}
private static void ComputeDataRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren, Simplifier.ProgressDelegate progress = null)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify == null && root.m_bGenerateIncludeChildren)
{
if (HasValidMeshData(gameObject))
{
meshSimplify = gameObject.AddComponent<MeshSimplify>();
meshSimplify.m_meshSimplifyRoot = root;
root.m_listDependentChildren.Add(meshSimplify);
}
}
if(meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
meshSimplify.FreeData(false);
MeshFilter meshFilter = meshSimplify.GetComponent<MeshFilter>();
if (meshFilter != null && meshFilter.sharedMesh != null)
{
if (meshFilter.sharedMesh.vertexCount > 0)
{
if (meshSimplify.m_originalMesh == null)
{
meshSimplify.m_originalMesh = meshFilter.sharedMesh;
}
Simplifier[] simplifiers = meshSimplify.GetComponents<Simplifier>();
for (int c = 0; c < simplifiers.Length; c++)
{
if (Application.isEditor && Application.isPlaying == false)
{
DestroyImmediate(simplifiers[c]);
}
else
{
Destroy(simplifiers[c]);
}
}
meshSimplify.m_meshSimplifier = meshSimplify.gameObject.AddComponent<Simplifier>();
meshSimplify.m_meshSimplifier.hideFlags = HideFlags.HideInInspector;
meshSimplify.ConfigureSimplifier();
IEnumerator enumerator = meshSimplify.m_meshSimplifier.ProgressiveMesh(gameObject, meshSimplify.m_originalMesh, root.m_aRelevanceSpheres, meshSimplify.name, progress);
while (enumerator.MoveNext())
{
if (Simplifier.Cancelled)
{
return;
}
}
if (Simplifier.Cancelled)
{
return;
}
}
}
else
{
SkinnedMeshRenderer skin = meshSimplify.GetComponent<SkinnedMeshRenderer>();
if (skin != null)
{
if (skin.sharedMesh.vertexCount > 0)
{
if (meshSimplify.m_originalMesh == null)
{
meshSimplify.m_originalMesh = skin.sharedMesh;
}
Simplifier[] simplifiers = meshSimplify.GetComponents<Simplifier>();
for (int c = 0; c < simplifiers.Length; c++)
{
if (Application.isEditor && Application.isPlaying == false)
{
DestroyImmediate(simplifiers[c]);
}
else
{
Destroy(simplifiers[c]);
}
}
meshSimplify.m_meshSimplifier = meshSimplify.gameObject.AddComponent<Simplifier>();
meshSimplify.m_meshSimplifier.hideFlags = HideFlags.HideInInspector;
meshSimplify.ConfigureSimplifier();
IEnumerator enumerator = meshSimplify.m_meshSimplifier.ProgressiveMesh(gameObject, meshSimplify.m_originalMesh, root.m_aRelevanceSpheres, meshSimplify.name, progress);
while (enumerator.MoveNext())
{
if (Simplifier.Cancelled)
{
return;
}
}
if (Simplifier.Cancelled)
{
return;
}
}
}
}
meshSimplify.m_bDataDirty = false;
}
}
if(bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
ComputeDataRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren, progress);
if (Simplifier.Cancelled)
{
return;
}
}
}
}
public bool HasData()
{
return (m_meshSimplifier != null && m_simplifiedMesh != null) || (m_listDependentChildren != null && m_listDependentChildren.Count != 0);
}
public bool HasSimplifiedMesh()
{
return m_simplifiedMesh != null && m_simplifiedMesh.vertexCount > 0;
}
public void ComputeMesh(bool bRecurseIntoChildren, Simplifier.ProgressDelegate progress = null)
{
ComputeMeshRecursive(this, this.gameObject, bRecurseIntoChildren, progress);
}
private static void ComputeMeshRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren, Simplifier.ProgressDelegate progress = null)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_meshSimplifier != null)
{
if (meshSimplify.m_simplifiedMesh)
{
meshSimplify.m_simplifiedMesh.Clear();
}
float fAmount = meshSimplify.m_fVertexAmount;
if (meshSimplify.m_bOverrideRootSettings == false && meshSimplify.m_meshSimplifyRoot != null)
{
fAmount = meshSimplify.m_meshSimplifyRoot.m_fVertexAmount;
}
if (meshSimplify.m_simplifiedMesh == null)
{
meshSimplify.m_simplifiedMesh = CreateNewEmptyMesh(meshSimplify);
}
meshSimplify.ConfigureSimplifier();
IEnumerator enumerator = meshSimplify.m_meshSimplifier.ComputeMeshWithVertexCount(gameObject, meshSimplify.m_simplifiedMesh, Mathf.RoundToInt(fAmount * meshSimplify.m_meshSimplifier.GetOriginalMeshUniqueVertexCount()), meshSimplify.name + " Simplified", progress);
while (enumerator.MoveNext())
{
if (Simplifier.Cancelled)
{
return;
}
}
if (Simplifier.Cancelled)
{
return;
}
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
ComputeMeshRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren, progress);
if (Simplifier.Cancelled)
{
return;
}
}
}
}
public void AssignSimplifiedMesh(bool bRecurseIntoChildren)
{
AssignSimplifiedMeshRecursive(this, this.gameObject, bRecurseIntoChildren);
}
private static void AssignSimplifiedMeshRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_simplifiedMesh != null)
{
MeshFilter meshFilter = meshSimplify.GetComponent<MeshFilter>();
if (meshFilter != null)
{
meshFilter.sharedMesh = meshSimplify.m_simplifiedMesh;
}
else
{
SkinnedMeshRenderer skin = meshSimplify.GetComponent<SkinnedMeshRenderer>();
if (skin != null)
{
skin.sharedMesh = meshSimplify.m_simplifiedMesh;
}
}
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
AssignSimplifiedMeshRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren);
}
}
}
public void RestoreOriginalMesh(bool bDeleteData, bool bRecurseIntoChildren)
{
RestoreOriginalMeshRecursive(this, this.gameObject, bDeleteData, bRecurseIntoChildren);
}
private static void RestoreOriginalMeshRecursive(MeshSimplify root, GameObject gameObject, bool bDeleteData, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_originalMesh != null)
{
MeshFilter meshFilter = meshSimplify.GetComponent<MeshFilter>();
if (meshFilter != null)
{
meshFilter.sharedMesh = meshSimplify.m_originalMesh;
}
else
{
SkinnedMeshRenderer skin = meshSimplify.GetComponent<SkinnedMeshRenderer>();
if (skin != null)
{
skin.sharedMesh = meshSimplify.m_originalMesh;
}
}
}
if (bDeleteData)
{
meshSimplify.FreeData(false);
meshSimplify.m_listDependentChildren.Clear();
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
RestoreOriginalMeshRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bDeleteData, bRecurseIntoChildren);
}
}
}
public bool HasOriginalMeshActive(bool bRecurseIntoChildren)
{
return HasOriginalMeshActiveRecursive(this, this.gameObject, bRecurseIntoChildren);
}
private static bool HasOriginalMeshActiveRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
bool bHasOriginalMeshActive = false;
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_originalMesh != null)
{
MeshFilter meshFilter = meshSimplify.GetComponent<MeshFilter>();
if (meshFilter != null)
{
if(meshFilter.sharedMesh == meshSimplify.m_originalMesh)
{
bHasOriginalMeshActive = true;
}
}
else
{
SkinnedMeshRenderer skin = meshSimplify.GetComponent<SkinnedMeshRenderer>();
if (skin != null)
{
if(skin.sharedMesh == meshSimplify.m_originalMesh)
{
bHasOriginalMeshActive = true;
}
}
}
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
bHasOriginalMeshActive = bHasOriginalMeshActive || HasOriginalMeshActiveRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren);
}
}
return bHasOriginalMeshActive;
}
public bool HasVertexData(bool bRecurseIntoChildren)
{
return HasVertexDataRecursive(this, this.gameObject, bRecurseIntoChildren);
}
private static bool HasVertexDataRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_simplifiedMesh && meshSimplify.m_simplifiedMesh.vertexCount > 0)
{
return true;
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
if (HasVertexDataRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren))
{
return true;
}
}
}
return false;
}
public int GetOriginalVertexCount(bool bRecurseIntoChildren)
{
int nVertexCount = 0;
GetOriginalVertexCountRecursive(this, this.gameObject, ref nVertexCount, bRecurseIntoChildren);
return nVertexCount;
}
private static void GetOriginalVertexCountRecursive(MeshSimplify root, GameObject gameObject, ref int nVertexCount, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_originalMesh != null)
{
nVertexCount += meshSimplify.m_originalMesh.vertexCount;
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
GetOriginalVertexCountRecursive(root, gameObject.transform.GetChild(nChild).gameObject, ref nVertexCount, bRecurseIntoChildren);
}
}
}
public int GetOriginalTriangleCount(bool bRecurseIntoChildren)
{
int nTriangleCount = 0;
GetOriginalTriangleCountRecursive(this, this.gameObject, ref nTriangleCount, bRecurseIntoChildren);
return nTriangleCount;
}
private static void GetOriginalTriangleCountRecursive(MeshSimplify root, GameObject gameObject, ref int nTriangleCount, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_originalMesh != null)
{
nTriangleCount += meshSimplify.m_originalMesh.triangles.Length / 3;
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
GetOriginalTriangleCountRecursive(root, gameObject.transform.GetChild(nChild).gameObject, ref nTriangleCount, bRecurseIntoChildren);
}
}
}
public int GetSimplifiedVertexCount(bool bRecurseIntoChildren)
{
int nVertexCount = 0;
GetSimplifiedVertexCountRecursive(this, this.gameObject, ref nVertexCount, bRecurseIntoChildren);
return nVertexCount;
}
private static void GetSimplifiedVertexCountRecursive(MeshSimplify root, GameObject gameObject, ref int nVertexCount, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_simplifiedMesh != null)
{
nVertexCount += meshSimplify.m_simplifiedMesh.vertexCount;
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
GetSimplifiedVertexCountRecursive(root, gameObject.transform.GetChild(nChild).gameObject, ref nVertexCount, bRecurseIntoChildren);
}
}
}
public int GetSimplifiedTriangleCount(bool bRecurseIntoChildren)
{
int nTriangleCount = 0;
GetSimplifiedTriangleCountRecursive(this, this.gameObject, ref nTriangleCount, bRecurseIntoChildren);
return nTriangleCount;
}
private static void GetSimplifiedTriangleCountRecursive(MeshSimplify root, GameObject gameObject, ref int nTriangleCount, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_simplifiedMesh != null)
{
nTriangleCount += meshSimplify.m_simplifiedMesh.triangles.Length / 3;
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
GetSimplifiedTriangleCountRecursive(root, gameObject.transform.GetChild(nChild).gameObject, ref nTriangleCount, bRecurseIntoChildren);
}
}
}
public void RemoveFromTree()
{
if (m_meshSimplifyRoot != null)
{
m_meshSimplifyRoot.m_listDependentChildren.Remove(this);
}
RestoreOriginalMesh(true, false);
m_bExcludedFromTree = true;
}
public void FreeData(bool bRecurseIntoChildren)
{
FreeDataRecursive(this, this.gameObject, bRecurseIntoChildren);
}
private static void FreeDataRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_simplifiedMesh)
{
meshSimplify.m_simplifiedMesh.Clear();
}
Simplifier[] simplifiers = gameObject.GetComponents<Simplifier>();
for (int c = 0; c < simplifiers.Length; c++)
{
if (Application.isEditor && Application.isPlaying == false)
{
DestroyImmediate(simplifiers[c]);
}
else
{
Destroy(simplifiers[c]);
}
}
meshSimplify.m_bDataDirty = true;
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
FreeDataRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren);
}
}
}
private static Mesh CreateNewEmptyMesh(MeshSimplify meshSimplify)
{
if(meshSimplify.m_originalMesh == null)
{
return new Mesh();
}
Mesh meshOut = Mesh.Instantiate(meshSimplify.m_originalMesh);
meshOut.Clear();
return meshOut;
}
#if UNITY_EDITOR
public void DisablePrefabUsage(bool bRecurseIntoChildren)
{
DisablePrefabUsageRecursive(this, this.gameObject, bRecurseIntoChildren);
}
private static void DisablePrefabUsageRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_simplifiedMesh)
{
if (UnityEditor.AssetDatabase.IsMainAsset(meshSimplify.m_simplifiedMesh) || UnityEditor.AssetDatabase.IsSubAsset(meshSimplify.m_simplifiedMesh))
{
Mesh newMesh = Instantiate(meshSimplify.m_simplifiedMesh) as Mesh;
meshSimplify.m_simplifiedMesh = newMesh;
}
}
meshSimplify.m_strAssetPath = null;
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
DisablePrefabUsageRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren);
}
}
}
#endif
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 100bcc9db4f7fc64e95ecc1abca8c97d
timeCreated: 1438106980
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,378 @@
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace UltimateGameTools
{
namespace MeshSimplifier
{
/// <summary>
/// Class that will take a Mesh as input and will build internal data to identify which vertices are repeated due to
/// different vertex data (UV, vertex colors etc).
/// </summary>
[Serializable]
public class MeshUniqueVertices
{
#region Public types
/////////////////////////////////////////////////////////////////////////////////////////////////
// Public types
/////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// A list of vertex indices. We use this in order to be able to serialize a list of lists.
/// </summary>
[Serializable]
public class ListIndices
{
public ListIndices()
{
m_listIndices = new List<int>();
}
public List<int> m_listIndices;
}
/// <summary>
/// Our serializable version of Unity's BoneWeight
/// </summary>
[Serializable]
public class SerializableBoneWeight
{
public SerializableBoneWeight(BoneWeight boneWeight)
{
_boneIndex0 = boneWeight.boneIndex0;
_boneIndex1 = boneWeight.boneIndex1;
_boneIndex2 = boneWeight.boneIndex2;
_boneIndex3 = boneWeight.boneIndex3;
_boneWeight0 = boneWeight.weight0;
_boneWeight1 = boneWeight.weight1;
_boneWeight2 = boneWeight.weight2;
_boneWeight3 = boneWeight.weight3;
}
public BoneWeight ToBoneWeight()
{
BoneWeight boneWeight = new BoneWeight();
boneWeight.boneIndex0 = _boneIndex0;
boneWeight.boneIndex1 = _boneIndex1;
boneWeight.boneIndex2 = _boneIndex2;
boneWeight.boneIndex3 = _boneIndex3;
boneWeight.weight0 = _boneWeight0;
boneWeight.weight1 = _boneWeight1;
boneWeight.weight2 = _boneWeight2;
boneWeight.weight3 = _boneWeight3;
return boneWeight;
}
public int _boneIndex0;
public int _boneIndex1;
public int _boneIndex2;
public int _boneIndex3;
public float _boneWeight0;
public float _boneWeight1;
public float _boneWeight2;
public float _boneWeight3;
}
/// <summary>
/// Vertex that is has a unique position in space.
/// </summary>
public class UniqueVertex
{
// Overrides from Object
public override bool Equals(object obj)
{
UniqueVertex uniqueVertex = obj as UniqueVertex;
return (uniqueVertex.m_nFixedX == m_nFixedX) && (uniqueVertex.m_nFixedY == m_nFixedY) && (uniqueVertex.m_nFixedZ == m_nFixedZ);
}
public override int GetHashCode()
{
return m_nFixedX + (m_nFixedY << 2) + (m_nFixedZ << 4);
}
// Constructor
public UniqueVertex(Vector3 v3Vertex)
{
FromVertex(v3Vertex);
}
// Public methods
public Vector3 ToVertex()
{
return new Vector3(FixedToCoord(m_nFixedX), FixedToCoord(m_nFixedY), FixedToCoord(m_nFixedZ));
}
// Comparison operators
public static bool operator ==(UniqueVertex a, UniqueVertex b)
{
return a.Equals(b);
}
public static bool operator !=(UniqueVertex a, UniqueVertex b)
{
return !a.Equals(b);
}
// Private methods/vars
private void FromVertex(Vector3 vertex)
{
m_nFixedX = CoordToFixed(vertex.x);
m_nFixedY = CoordToFixed(vertex.y);
m_nFixedZ = CoordToFixed(vertex.z);
}
private int CoordToFixed(float fCoord)
{
int nInteger = Mathf.FloorToInt(fCoord);
int nRemainder = Mathf.FloorToInt((fCoord - nInteger) * fDecimalMultiplier);
return nInteger << 16 | nRemainder;
}
private float FixedToCoord(int nFixed)
{
float fRemainder = (nFixed & 0xFFFF) / fDecimalMultiplier;
float fInteger = nFixed >> 16;
return fInteger + fRemainder;
}
// Private vars
private int m_nFixedX, m_nFixedY, m_nFixedZ;
private const float fDecimalMultiplier = 100000.0f;
}
#endregion
#region Public properties
/////////////////////////////////////////////////////////////////////////////////////////////////
// Public properties
/////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// For each submesh, a list of faces. ListIndices has 3 indices for each face.
/// Each index is a vertex in ListVertices.
/// </summary>
public ListIndices[] SubmeshesFaceList
{
get
{
return m_aFaceList;
}
}
/// <summary>
/// Our list of vertices. Vertices are unique, so no vertex shares the same position in space.
/// </summary>
public List<Vector3> ListVertices
{
get
{
return m_listVertices;
}
}
/// <summary>
/// Our list of vertices in world space.
/// Vertices are unique, so no vertex shares the same position in space.
/// </summary>
public List<Vector3> ListVerticesWorld
{
get
{
return m_listVerticesWorld;
}
}
/// <summary>
/// Our list of vertex bone weights
/// </summary>
public List<SerializableBoneWeight> ListBoneWeights
{
get
{
return m_listBoneWeights;
}
}
#endregion // Public properties
#region Public methods
/////////////////////////////////////////////////////////////////////////////////////////////////
// Public methods
/////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Takes a Mesh as input and will build a new list of faces and vertices. The vertex list will
/// have no vertices sharing position in 3D space. The input mesh may have them, since often
/// a vertex will have different mapping coordinates for each of the faces that share it.
/// </summary>
/// <param name="sourceMesh"></param>
/// <param name="av3VerticesWorld"</param>
public void BuildData(Mesh sourceMesh, Vector3[] av3VerticesWorld)
{
Vector3[] av3Vertices = sourceMesh.vertices;
BoneWeight[] aBoneWeights = sourceMesh.boneWeights;
Dictionary<UniqueVertex, RepeatedVertexList> dicUniqueVertex2RepeatedVertexList = new Dictionary<UniqueVertex, RepeatedVertexList>();
m_listVertices = new List<Vector3>();
m_listVerticesWorld = new List<Vector3>();
m_listBoneWeights = new List<SerializableBoneWeight>();
m_aFaceList = new ListIndices[sourceMesh.subMeshCount];
for (int nSubMesh = 0; nSubMesh < sourceMesh.subMeshCount; nSubMesh++)
{
m_aFaceList[nSubMesh] = new ListIndices();
int[] anFaces = sourceMesh.GetTriangles(nSubMesh);
for (int i = 0; i < anFaces.Length; i++)
{
UniqueVertex vertex = new UniqueVertex(av3Vertices[anFaces[i]]);
if (dicUniqueVertex2RepeatedVertexList.ContainsKey(vertex))
{
dicUniqueVertex2RepeatedVertexList[vertex].Add(new RepeatedVertex(i / 3, anFaces[i]));
m_aFaceList[nSubMesh].m_listIndices.Add(dicUniqueVertex2RepeatedVertexList[vertex].UniqueIndex);
}
else
{
int nNewUniqueIndex = m_listVertices.Count;
dicUniqueVertex2RepeatedVertexList.Add(vertex, new RepeatedVertexList(nNewUniqueIndex, new RepeatedVertex(i / 3, anFaces[i])));
m_listVertices.Add(av3Vertices[anFaces[i]]);
m_listVerticesWorld.Add(av3VerticesWorld[anFaces[i]]);
m_aFaceList[nSubMesh].m_listIndices.Add(nNewUniqueIndex);
if(aBoneWeights != null && aBoneWeights.Length > 0)
{
m_listBoneWeights.Add(new SerializableBoneWeight(aBoneWeights[anFaces[i]]));
}
}
}
}
//Debug.Log("In: " + av3Vertices.Length + " vertices. Out: " + m_listVertices.Count + " vertices.");
}
#endregion // Public methods
#region Private types
/////////////////////////////////////////////////////////////////////////////////////////////////
// Private types
/////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Vertex that has the same position in space as another one, but different vertex data (UV, color...).
/// </summary>
private class RepeatedVertex
{
// Public properties
/// <summary>
/// Face it belongs to. This will be the same index in the source mesh as in the internal created face list.
/// </summary>
public int FaceIndex
{
get
{
return _nFaceIndex;
}
}
/// <summary>
/// Position in the original vertex array.
/// </summary>
public int OriginalVertexIndex
{
get
{
return _nOriginalVertexIndex;
}
}
// Constructor
public RepeatedVertex(int nFaceIndex, int nOriginalVertexIndex)
{
_nFaceIndex = nFaceIndex;
_nOriginalVertexIndex = nOriginalVertexIndex;
}
// Private vars
private int _nFaceIndex;
private int _nOriginalVertexIndex;
}
/// <summary>
/// List of vertices that have the same position in space but different vertex data (UV, color...).
/// </summary>
private class RepeatedVertexList
{
// Public properties
/// <summary>
/// Unique vertex index in our array for this list.
/// </summary>
public int UniqueIndex
{
get
{
return m_nUniqueIndex;
}
}
// Public methods
public RepeatedVertexList(int nUniqueIndex, RepeatedVertex repeatedVertex)
{
m_nUniqueIndex = nUniqueIndex;
m_listRepeatedVertices = new List<RepeatedVertex>();
m_listRepeatedVertices.Add(repeatedVertex);
}
public void Add(RepeatedVertex repeatedVertex)
{
m_listRepeatedVertices.Add(repeatedVertex);
}
// Private vars
private int m_nUniqueIndex;
private List<RepeatedVertex> m_listRepeatedVertices;
}
#endregion // Private types
#region Private vars
/////////////////////////////////////////////////////////////////////////////////////////////////
// Private vars
/////////////////////////////////////////////////////////////////////////////////////////////////
[SerializeField]
private List<Vector3> m_listVertices;
[SerializeField]
private List<Vector3> m_listVerticesWorld;
[SerializeField]
private List<SerializableBoneWeight> m_listBoneWeights;
[SerializeField]
private ListIndices[] m_aFaceList;
#endregion // Private vars
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c9aa0aceed4b66242b713cf6b09e6a9f
timeCreated: 1434653219
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,176 @@
using System.Collections;
using System.Collections.Generic;
using UltimateGameTools.MeshSimplifier;
using UnityEngine;
[RequireComponent(typeof(MeshSimplify))]
public class RuntimeMeshSimplifier : MonoBehaviour
{
public string ProgressTitle
{
get
{
return m_strLastTitle;
}
}
public string ProgressMessage
{
get
{
return m_strLastMessage;
}
}
public int ProgressPercent
{
get
{
return m_nLastProgress;
}
}
public bool Finished
{
get
{
return m_bFinished;
}
}
public void Simplify(float percent)
{
if (m_bFinished == false)
{
StartCoroutine(ComputeMeshWithVertices(Mathf.Clamp01(percent / 100.0f)));
}
}
private void Awake()
{
m_selectedMeshSimplify = GetComponent<MeshSimplify>();
m_objectMaterials = new Dictionary<GameObject, Material[]>();
AddMaterials(m_selectedMeshSimplify.gameObject, m_objectMaterials);
m_bFinished = false;
}
private void AddMaterials(GameObject theGameObject, Dictionary<GameObject, Material[]> dicMaterials)
{
Renderer theRenderer = theGameObject.GetComponent<Renderer>();
if (theRenderer != null && theRenderer.sharedMaterials != null && (MeshSimplify.HasValidMeshData(theGameObject) || theGameObject.GetComponent<MeshSimplify>() != null))
{
dicMaterials.Add(theGameObject, theRenderer.sharedMaterials);
}
if (m_selectedMeshSimplify.RecurseIntoChildren)
{
for (int i = 0; i < theGameObject.transform.childCount; i++)
{
AddMaterials(theGameObject.transform.GetChild(i).gameObject, dicMaterials);
}
}
}
private void Progress(string strTitle, string strMessage, float fT)
{
int nPercent = Mathf.RoundToInt(fT * 100.0f);
if (nPercent != m_nLastProgress || m_strLastTitle != strTitle || m_strLastMessage != strMessage)
{
m_strLastTitle = strTitle;
m_strLastMessage = strMessage;
m_nLastProgress = nPercent;
//Debug.Log(strTitle + " " + strMessage + " " + nPercent);
}
}
private IEnumerator ComputeMeshWithVertices(float fAmount)
{
Simplifier.CoroutineFrameMiliseconds = 20;
foreach (KeyValuePair<GameObject, Material[]> pair in m_objectMaterials)
{
MeshSimplify meshSimplify = pair.Key.GetComponent<MeshSimplify>();
MeshFilter meshFilter = pair.Key.GetComponent<MeshFilter>();
SkinnedMeshRenderer skin = pair.Key.GetComponent<SkinnedMeshRenderer>();
if(meshSimplify == null)
{
meshSimplify = pair.Key.AddComponent<MeshSimplify>();
meshSimplify.m_meshSimplifyRoot = m_selectedMeshSimplify;
m_selectedMeshSimplify.m_listDependentChildren.Add(meshSimplify);
}
if(meshSimplify.MeshSimplifier == null)
{
meshSimplify.MeshSimplifier = meshSimplify.gameObject.AddComponent<Simplifier>();
meshSimplify.MeshSimplifier.hideFlags = HideFlags.HideInInspector;
meshSimplify.ConfigureSimplifier();
}
if (meshSimplify && MeshSimplify.HasValidMeshData(pair.Key))
{
Mesh newMesh = null;
if (meshFilter != null)
{
newMesh = Mesh.Instantiate(meshFilter.sharedMesh);
}
else if (skin != null)
{
newMesh = Mesh.Instantiate(skin.sharedMesh);
}
if (meshSimplify.HasData() == false)
{
meshSimplify.GetMeshSimplifier().CoroutineEnded = false;
StartCoroutine(meshSimplify.GetMeshSimplifier().ProgressiveMesh(pair.Key, meshFilter != null ? meshFilter.sharedMesh : skin.sharedMesh, null, meshSimplify.name, Progress));
while (meshSimplify.GetMeshSimplifier().CoroutineEnded == false)
{
yield return null;
}
}
if (meshSimplify.GetMeshSimplifier() != null)
{
meshSimplify.GetMeshSimplifier().CoroutineEnded = false;
StartCoroutine(meshSimplify.GetMeshSimplifier().ComputeMeshWithVertexCount(pair.Key, newMesh, Mathf.RoundToInt(fAmount * meshSimplify.GetMeshSimplifier().GetOriginalMeshUniqueVertexCount()), meshSimplify.name, Progress));
while (meshSimplify.GetMeshSimplifier().CoroutineEnded == false)
{
yield return null;
}
if (meshFilter != null)
{
meshFilter.mesh = newMesh;
}
else if (skin != null)
{
skin.sharedMesh = newMesh;
}
meshSimplify.m_simplifiedMesh = newMesh;
}
}
}
m_bFinished = true;
}
private Dictionary<GameObject, Material[]> m_objectMaterials;
private MeshSimplify m_selectedMeshSimplify;
private bool m_bFinished = false;
private Mesh m_newMesh;
private int m_nLastProgress = -1;
private string m_strLastTitle = "";
private string m_strLastMessage = "";
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 10b6bfc6d6d946449bd6178082a26d5e
timeCreated: 1496044654
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 90d922b6196aab34697b544f28239ee2
timeCreated: 1434653219
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: