GQ_Communicate/GQ_TongXin/Assets/Obi/Editor/ObiRopeEditor.cs

283 lines
10 KiB
C#

using UnityEditor;
using UnityEngine;
using UnityEditor.SceneManagement;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Obi{
/**
* Custom inspector for ObiRope components.
* Allows particle selection and constraint edition.
*
* Selection:
*
* - To select a particle, left-click on it.
* - You can select multiple particles by holding shift while clicking.
* - To deselect all particles, click anywhere on the object except a particle.
*
* Constraints:
*
* - To edit particle constraints, select the particles you wish to edit.
* - Constraints affecting any of the selected particles will appear in the inspector.
* - To add a new pin constraint to the selected particle(s), click on "Add Pin Constraint".
*
*/
[CustomEditor(typeof(ObiRope)), CanEditMultipleObjects]
public class ObiRopeEditor : ObiParticleActorEditor
{
public class TearableRopeParticleProperty : ParticleProperty
{
public const int TearResistance = 3;
public TearableRopeParticleProperty (int value) : base (value){}
}
[MenuItem("Assets/Create/Obi/Obi Rope Section")]
public static void CreateObiRopeSection ()
{
ObiEditorUtils.CreateAsset<ObiRopeSection> ();
}
[MenuItem("GameObject/3D Object/Obi/Obi Rope (fully set up)",false,4)]
static void CreateObiRope()
{
GameObject c = new GameObject("Obi Rope");
Undo.RegisterCreatedObjectUndo(c,"Create Obi Rope");
ObiRope rope = c.AddComponent<ObiRope>();
ObiCatmullRomCurve path = c.AddComponent<ObiCatmullRomCurve>();
ObiSolver solver = c.AddComponent<ObiSolver>();
rope.Solver = solver;
rope.Section = Resources.Load<ObiRopeSection>("DefaultRopeSection");
rope.ropePath = path;
}
ObiRope rope;
SerializedProperty chainLinks;
public override void OnEnable(){
base.OnEnable();
rope = (ObiRope)target;
chainLinks = serializedObject.FindProperty("chainLinks");
particlePropertyNames.AddRange(new string[]{"Tear Resistance"});
}
public override void OnDisable(){
base.OnDisable();
EditorUtility.ClearProgressBar();
}
public override void UpdateParticleEditorInformation(){
for(int i = 0; i < rope.positions.Length; i++)
{
wsPositions[i] = rope.GetParticlePosition(i);
facingCamera[i] = true;
}
}
protected override void SetPropertyValue(ParticleProperty property,int index, float value){
if (index >= 0 && index < rope.invMasses.Length){
switch(property){
case ParticleProperty.Mass:
rope.invMasses[index] = 1.0f / Mathf.Max(value,0.00001f);
break;
case ParticleProperty.Radius:
rope.solidRadii[index] = value;
break;
case ParticleProperty.Layer:
rope.phases[index] = Oni.MakePhase((int)value,rope.SelfCollisions?Oni.ParticlePhase.SelfCollide:0);;
break;
case TearableRopeParticleProperty.TearResistance:
rope.tearResistance[index] = value;
break;
}
}
}
protected override float GetPropertyValue(ParticleProperty property, int index){
if (index >= 0 && index < rope.invMasses.Length){
switch(property){
case ParticleProperty.Mass:
return 1.0f/rope.invMasses[index];
case ParticleProperty.Radius:
return rope.solidRadii[index];
case ParticleProperty.Layer:
return Oni.GetGroupFromPhase(rope.phases[index]);
case TearableRopeParticleProperty.TearResistance:
return rope.tearResistance[index];
}
}
return 0;
}
public override void OnInspectorGUI() {
serializedObject.Update();
GUI.enabled = rope.Initialized;
EditorGUI.BeginChangeCheck();
editMode = GUILayout.Toggle(editMode,new GUIContent("Edit particles",Resources.Load<Texture2D>("EditParticles")),"LargeButton");
if (EditorGUI.EndChangeCheck()){
SceneView.RepaintAll();
}
GUI.enabled = true;
EditorGUILayout.LabelField("Status: "+ (rope.Initialized ? "Initialized":"Not initialized"));
GUI.enabled = (rope.ropePath != null && rope.Section != null);
if (GUILayout.Button("Initialize")){
if (!rope.Initialized){
CoroutineJob job = new CoroutineJob();
routine = EditorCoroutine.StartCoroutine(job.Start(rope.GeneratePhysicRepresentationForMesh()));
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}else{
if (EditorUtility.DisplayDialog("Actor initialization","Are you sure you want to re-initialize this actor?","Ok","Cancel")){
CoroutineJob job = new CoroutineJob();
routine = EditorCoroutine.StartCoroutine(job.Start(rope.GeneratePhysicRepresentationForMesh()));
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
}
}
}
GUI.enabled = true;
GUI.enabled = rope.Initialized;
if (GUILayout.Button("Set Rest State")){
Undo.RecordObject(rope, "Set rest state");
rope.PullDataFromSolver(ParticleData.POSITIONS | ParticleData.VELOCITIES);
}
GUI.enabled = true;
if (rope.ropePath == null){
EditorGUILayout.HelpBox("Rope path spline is missing.",MessageType.Info);
}
if (rope.Section == null){
EditorGUILayout.HelpBox("Rope section is missing.",MessageType.Info);
}
EditorGUI.BeginChangeCheck();
ObiSolver solver = EditorGUILayout.ObjectField("Solver",rope.Solver, typeof(ObiSolver), true) as ObiSolver;
if (EditorGUI.EndChangeCheck()){
Undo.RecordObject(rope, "Set solver");
rope.Solver = solver;
}
EditorGUI.BeginChangeCheck();
ObiCollisionMaterial material = EditorGUILayout.ObjectField("Collision Material",rope.CollisionMaterial, typeof(ObiCollisionMaterial), false) as ObiCollisionMaterial;
if (EditorGUI.EndChangeCheck()){
Undo.RecordObject(rope, "Set collision material");
rope.CollisionMaterial = material;
}
bool newSelfCollisions = EditorGUILayout.Toggle(new GUIContent("Self collisions","Enabling this allows particles generated by this actor to interact with each other."),rope.SelfCollisions);
if (rope.SelfCollisions != newSelfCollisions){
Undo.RecordObject(rope, "Set self collisions");
rope.SelfCollisions = newSelfCollisions;
}
Editor.DrawPropertiesExcluding(serializedObject,"m_Script","chainLinks");
bool newThicknessFromParticles = EditorGUILayout.Toggle(new GUIContent("Thickness from particles","Enabling this will allow particle radius to influence rope thickness. Use it for variable-thickness ropes."),rope.ThicknessFromParticles);
if (rope.ThicknessFromParticles != newThicknessFromParticles){
Undo.RecordObject(rope, "Set thickness from particles");
rope.ThicknessFromParticles = newThicknessFromParticles;
}
float newTwist = EditorGUILayout.FloatField(new GUIContent("Section twist","Amount of twist applied to each section, in degrees."),rope.SectionTwist);
if (rope.SectionTwist != newTwist){
Undo.RecordObject(rope, "Set section twist");
rope.SectionTwist = newTwist;
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Rendering", EditorStyles.boldLabel);
ObiRope.RenderingMode newRenderMode = (ObiRope.RenderingMode) EditorGUILayout.EnumPopup(rope.RenderMode);
if (rope.RenderMode != newRenderMode){
Undo.RecordObject(rope, "Set rope render mode");
rope.RenderMode = newRenderMode;
}
float newUVAnchor = EditorGUILayout.Slider(new GUIContent("UV anchor","Normalized point along the rope where the V texture coordinate starts. Useful when changing rope length."),rope.UVAnchor,0,1);
if (rope.UVAnchor != newUVAnchor){
Undo.RecordObject(rope, "Set rope uv anchor");
rope.UVAnchor = newUVAnchor;
}
// Render-mode specific stuff:
if (rope.RenderMode != ObiRope.RenderingMode.Chain)
{
ObiRopeSection newSection = EditorGUILayout.ObjectField(new GUIContent("Section","Section asset to be extruded along the rope path.")
,rope.Section, typeof(ObiRopeSection), false) as ObiRopeSection;
if (rope.Section != newSection){
Undo.RecordObject(rope, "Set rope section");
rope.Section = newSection;
}
float newThickness = EditorGUILayout.FloatField(new GUIContent("Section thickness scale","Scales mesh thickness."),rope.SectionThicknessScale);
if (rope.SectionThicknessScale != newThickness){
Undo.RecordObject(rope, "Set rope section thickness");
rope.SectionThicknessScale = newThickness;
}
uint newSmoothness = (uint)EditorGUILayout.IntSlider(new GUIContent("Smoothness","Level of smoothing applied to the rope path."),Convert.ToInt32(rope.Smoothing),0,3);
if (rope.Smoothing != newSmoothness){
Undo.RecordObject(rope, "Set smoothness");
rope.Smoothing = newSmoothness;
}
Vector2 newUVScale = EditorGUILayout.Vector2Field(new GUIContent("UV scale","Scaling of the uv coordinates generated for the rope. The u coordinate wraps around the whole rope section, and the v spans the full length of the rope."),rope.UVScale);
if (rope.UVScale != newUVScale){
Undo.RecordObject(rope, "Set rope uv scale");
rope.UVScale = newUVScale;
}
bool newNormalizeV = EditorGUILayout.Toggle(new GUIContent("Normalize V","Scaling of the uv coordinates generated for the rope. The u coordinate wraps around the whole rope section, and the v spans the full length of the rope."),rope.NormalizeV);
if (rope.NormalizeV != newNormalizeV){
Undo.RecordObject(rope, "Set normalize v");
rope.NormalizeV = newNormalizeV;
}
}else{
Vector3 newLinkScale = EditorGUILayout.Vector3Field(new GUIContent("Link scale","Scale applied to each chain link."),rope.LinkScale);
if (rope.LinkScale != newLinkScale){
Undo.RecordObject(rope, "Set chain link scale");
rope.LinkScale = newLinkScale;
}
bool newRandomizeLinks = EditorGUILayout.Toggle(new GUIContent("Randomize links","Toggling this on this causes each chain link to be selected at random from the set of provided links."),rope.RandomizeLinks);
if (rope.RandomizeLinks != newRandomizeLinks){
Undo.RecordObject(rope, "Set randomize links");
rope.RandomizeLinks = newRandomizeLinks;
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(chainLinks, true);
if (EditorGUI.EndChangeCheck()){
// update the chain representation in response to a change in available link templates:
serializedObject.ApplyModifiedProperties();
rope.GenerateProceduralChainLinks();
}
}
// Progress bar:
EditorCoroutine.ShowCoroutineProgressBar("Generating physical representation...",routine);
// Apply changes to the serializedProperty
if (GUI.changed){
serializedObject.ApplyModifiedProperties();
}
}
}
}