添加插件
This commit is contained in:
@@ -0,0 +1,275 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Obi
|
||||
{
|
||||
[CustomEditor(typeof(ObiMeshBasedActorBlueprint), true)]
|
||||
public abstract class ObiMeshBasedActorBlueprintEditor : ObiActorBlueprintEditor
|
||||
{
|
||||
|
||||
[Flags]
|
||||
public enum ParticleCulling
|
||||
{
|
||||
Off = 0,
|
||||
Back = 1 << 0,
|
||||
Front = 1 << 1
|
||||
}
|
||||
|
||||
protected Mesh visualizationMesh;
|
||||
protected Mesh visualizationWireMesh;
|
||||
public ParticleCulling particleCulling = ParticleCulling.Back;
|
||||
|
||||
protected Material gradientMaterial;
|
||||
protected Material textureExportMaterial;
|
||||
protected Material paddingMaterial;
|
||||
|
||||
public override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
gradientMaterial = Resources.Load<Material>("PropertyGradientMaterial");
|
||||
textureExportMaterial = Resources.Load<Material>("UVSpaceColorMaterial");
|
||||
paddingMaterial = Resources.Load<Material>("PaddingMaterial");
|
||||
}
|
||||
|
||||
public abstract Mesh sourceMesh
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
protected void NonReadableMeshWarning(Mesh mesh)
|
||||
{
|
||||
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
|
||||
Texture2D icon = EditorGUIUtility.Load("icons/console.erroricon.png") as Texture2D;
|
||||
EditorGUILayout.LabelField(new GUIContent("The input mesh is not readable. Read/Write must be enabled in the mesh import settings.", icon), EditorStyles.wordWrappedMiniLabel);
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button("Fix now", GUILayout.MaxWidth(100), GUILayout.MinHeight(32)))
|
||||
{
|
||||
string assetPath = AssetDatabase.GetAssetPath(mesh);
|
||||
ModelImporter modelImporter = AssetImporter.GetAtPath(assetPath) as ModelImporter;
|
||||
if (modelImporter != null)
|
||||
{
|
||||
modelImporter.isReadable = true;
|
||||
}
|
||||
modelImporter.SaveAndReimport();
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
protected override bool ValidateBlueprint()
|
||||
{
|
||||
if (sourceMesh != null)
|
||||
{
|
||||
if (!sourceMesh.isReadable)
|
||||
{
|
||||
NonReadableMeshWarning(sourceMesh);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract int VertexToParticle(int vertexIndex);
|
||||
|
||||
public override void UpdateParticleVisibility(Camera cam)
|
||||
{
|
||||
if (cam != null)
|
||||
{
|
||||
for (int i = 0; i < blueprint.positions.Length; i++)
|
||||
{
|
||||
if (blueprint.IsParticleActive(i))
|
||||
{
|
||||
Vector3 camToParticle = cam.transform.position - blueprint.positions[i];
|
||||
sqrDistanceToCamera[i] = camToParticle.sqrMagnitude;
|
||||
|
||||
Vector3 normal;
|
||||
|
||||
switch (particleCulling)
|
||||
{
|
||||
case ParticleCulling.Off:
|
||||
visible[i] = true;
|
||||
break;
|
||||
case ParticleCulling.Back:
|
||||
normal = blueprint.restOrientations[i] * Vector3.forward;
|
||||
visible[i] = Vector3.Dot(normal, camToParticle) > 0;
|
||||
break;
|
||||
case ParticleCulling.Front:
|
||||
normal = blueprint.restOrientations[i] * Vector3.forward;
|
||||
visible[i] = Vector3.Dot(normal, camToParticle) <= 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((renderModeFlags & 1) != 0)
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawGradientMesh(float[] vertexWeights = null, float[] wireframeWeights = null)
|
||||
{
|
||||
// Due to this Unity bug: https://issuetracker.unity3d.com/issues/drawmeshnow-is-not-drawing-mesh-immediately-dx12
|
||||
// we need to create two meshes insteaf of one :(
|
||||
if (sourceMesh == null)
|
||||
return;
|
||||
|
||||
visualizationMesh = GameObject.Instantiate(sourceMesh);
|
||||
visualizationWireMesh = GameObject.Instantiate(sourceMesh);
|
||||
|
||||
if (gradientMaterial.SetPass(0))
|
||||
{
|
||||
var matrix = Matrix4x4.TRS(Vector3.zero, (blueprint as ObiMeshBasedActorBlueprint).rotation, (blueprint as ObiMeshBasedActorBlueprint).scale);
|
||||
|
||||
Color[] colors = new Color[visualizationMesh.vertexCount];
|
||||
for (int i = 0; i < colors.Length; i++)
|
||||
{
|
||||
int particle = VertexToParticle(i);
|
||||
if (particle >= 0 && particle < blueprint.particleCount)
|
||||
{
|
||||
float weight = 1;
|
||||
if (vertexWeights != null)
|
||||
weight = vertexWeights[particle];
|
||||
|
||||
colors[i] = weight * currentProperty.ToColor(particle);
|
||||
}
|
||||
else
|
||||
colors[i] = Color.gray;
|
||||
}
|
||||
|
||||
visualizationMesh.colors = colors;
|
||||
Graphics.DrawMeshNow(visualizationMesh, matrix);
|
||||
|
||||
Color wireColor = ObiEditorSettings.GetOrCreateSettings().brushWireframeColor;
|
||||
|
||||
if (gradientMaterial.SetPass(1))
|
||||
{
|
||||
for (int i = 0; i < colors.Length; i++)
|
||||
{
|
||||
int particle = VertexToParticle(i);
|
||||
if (particle >= 0 && particle < blueprint.particleCount)
|
||||
{
|
||||
if (wireframeWeights != null)
|
||||
colors[i] = wireColor * wireframeWeights[particle];
|
||||
else
|
||||
colors[i] = wireColor;
|
||||
}
|
||||
else
|
||||
colors[i] = Color.gray;
|
||||
}
|
||||
|
||||
visualizationWireMesh.colors = colors;
|
||||
GL.wireframe = true;
|
||||
Graphics.DrawMeshNow(visualizationWireMesh, matrix);
|
||||
GL.wireframe = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GameObject.DestroyImmediate(visualizationMesh);
|
||||
GameObject.DestroyImmediate(visualizationWireMesh);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reads particle data from a 2D texture. Can be used to adjust per particle mass, skin radius, etc. using
|
||||
* a texture instead of painting it in the editor.
|
||||
*
|
||||
* Will call onReadProperty once for each particle, passing the particle index and the bilinearly interpolated
|
||||
* color of the texture at its coordinate.
|
||||
*
|
||||
* Be aware that, if a particle corresponds to more than
|
||||
* one physical vertex and has multiple uv coordinates,
|
||||
* onReadProperty will be called multiple times for that particle.
|
||||
*/
|
||||
public bool ReadParticlePropertyFromTexture(Texture2D source, Action<int, Color> onReadProperty)
|
||||
{
|
||||
|
||||
if (source == null || onReadProperty == null)
|
||||
return false;
|
||||
|
||||
Vector2[] uvs = sourceMesh.uv;
|
||||
|
||||
// Iterate over all vertices in the mesh reading back colors from the texture:
|
||||
for (int i = 0; i < sourceMesh.vertexCount; ++i)
|
||||
{
|
||||
try
|
||||
{
|
||||
onReadProperty(VertexToParticle(i), source.GetPixelBilinear(uvs[i].x, uvs[i].y));
|
||||
}
|
||||
catch (UnityException e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WriteParticlePropertyToTexture(string path, int width, int height, int padding)
|
||||
{
|
||||
|
||||
if (path == null || textureExportMaterial == null || !textureExportMaterial.SetPass(0))
|
||||
return false;
|
||||
|
||||
if (visualizationMesh == null)
|
||||
{
|
||||
visualizationMesh = GameObject.Instantiate(sourceMesh);
|
||||
}
|
||||
|
||||
RenderTexture tempRT = RenderTexture.GetTemporary(width, height, 0);
|
||||
RenderTexture paddingRT = RenderTexture.GetTemporary(width, height, 0);
|
||||
|
||||
RenderTexture old = RenderTexture.active;
|
||||
RenderTexture.active = tempRT;
|
||||
|
||||
GL.PushMatrix();
|
||||
|
||||
var proj = Matrix4x4.Ortho(0, 1, 0, 1, -1, 1);
|
||||
if (Camera.current != null) proj = proj * Camera.current.worldToCameraMatrix.inverse;
|
||||
GL.LoadProjectionMatrix(proj);
|
||||
|
||||
Color[] colors = new Color[sourceMesh.vertexCount];
|
||||
for (int i = 0; i < colors.Length; i++)
|
||||
colors[i] = currentProperty.ToColor(VertexToParticle(i));
|
||||
|
||||
visualizationMesh.colors = colors;
|
||||
Graphics.DrawMeshNow(visualizationMesh, Matrix4x4.identity);
|
||||
|
||||
GL.PopMatrix();
|
||||
|
||||
// Perform padding/edge dilation
|
||||
paddingMaterial.SetFloat("_Padding", padding);
|
||||
Graphics.Blit(tempRT, paddingRT, paddingMaterial);
|
||||
|
||||
// Read result into our Texture2D.
|
||||
RenderTexture.active = paddingRT;
|
||||
Texture2D texture = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||
texture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
|
||||
|
||||
RenderTexture.active = old;
|
||||
RenderTexture.ReleaseTemporary(paddingRT);
|
||||
RenderTexture.ReleaseTemporary(tempRT);
|
||||
|
||||
byte[] png = texture.EncodeToPNG();
|
||||
GameObject.DestroyImmediate(texture);
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllBytes(path, png);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user