升级obi

This commit is contained in:
2026-01-22 22:08:21 +08:00
parent 120b8cda26
commit 20f14322bc
1067 changed files with 149894 additions and 29583 deletions

View File

@@ -85,7 +85,7 @@ namespace Obi
EditorGUI.BeginChangeCheck();
meshBasedEditor.particleCulling = (ObiMeshBasedActorBlueprintEditor.ParticleCulling)EditorGUILayout.EnumPopup("Culling", meshBasedEditor.particleCulling);
if (editor.selectedCount == 0)
if (ObiActorBlueprintEditor.selectedCount == 0)
{
EditorGUILayout.HelpBox("Select at least one particle to use selection mask.", MessageType.Info);
selectionMask = false;
@@ -111,13 +111,16 @@ namespace Obi
public override bool Editable(int index)
{
return editor.visible[index] && (!selectionMask || editor.selectionStatus[index]);
return editor.visible[index] && (!selectionMask || ObiActorBlueprintEditor.selectionStatus[index]);
}
public override void OnSceneGUI(SceneView view)
{
if (Camera.current != null)
{
var blueprint = meshBasedEditor.blueprint as ObiMeshBasedActorBlueprint;
paintBrush.raycastTransform = blueprint != null ? Matrix4x4.TRS(Vector3.zero, blueprint.rotation, blueprint.scale) : Matrix4x4.identity;
paintBrush.raycastTarget = meshBasedEditor.sourceMesh;
paintBrush.DoBrush(editor.blueprint.positions);
}

View File

@@ -32,8 +32,8 @@ namespace Obi
public override string GetHelpString()
{
if (editor.selectedCount > 0)
return "" + editor.selectedCount + " selected particles.";
if (ObiActorBlueprintEditor.selectedCount > 0)
return "" + ObiActorBlueprintEditor.selectedCount + " selected particles.";
else
return "No particles selected. Click and drag over particles to select them.";
}
@@ -65,12 +65,12 @@ namespace Obi
{
if ((Event.current.modifiers & EventModifiers.Shift) == 0)
{
for (int p = 0; p < editor.selectionStatus.Length; p++)
editor.selectionStatus[p] = false;
for (int p = 0; p < ObiActorBlueprintEditor.selectionStatus.Length; p++)
ObiActorBlueprintEditor.selectionStatus[p] = false;
}
foreach (int p in group.particleIndices)
editor.selectionStatus[p] = true;
ObiActorBlueprintEditor.selectionStatus[p] = true;
UpdateSelection();
}
@@ -78,9 +78,9 @@ namespace Obi
if (GUI.Button(new Rect(rect.x + rect.width * 0.5f, rect.y, rect.width * 0.5f, EditorGUIUtility.singleLineHeight), "Set", EditorStyles.miniButtonRight))
{
group.particleIndices.Clear();
for (int p = 0; p < editor.selectionStatus.Length; p++)
for (int p = 0; p < ObiActorBlueprintEditor.selectionStatus.Length; p++)
{
if (editor.selectionStatus[p])
if (ObiActorBlueprintEditor.selectionStatus[p])
group.particleIndices.Add(p);
}
}
@@ -95,9 +95,9 @@ namespace Obi
var group = editor.blueprint.AppendNewParticleGroup("new group");
for (int i = 0; i < editor.selectionStatus.Length; i++)
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (editor.selectionStatus[i])
if (ObiActorBlueprintEditor.selectionStatus[i])
group.particleIndices.Add(i);
}
@@ -116,33 +116,33 @@ namespace Obi
GUILayout.FlexibleSpace();
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("InvertButton"), "Invert selection"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
{
for (int i = 0; i < editor.selectionStatus.Length; i++)
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (editor.blueprint.IsParticleActive(i))
editor.selectionStatus[i] = !editor.selectionStatus[i];
ObiActorBlueprintEditor.selectionStatus[i] = !ObiActorBlueprintEditor.selectionStatus[i];
}
UpdateSelection();
}
GUI.enabled = editor.selectedCount > 0;
GUI.enabled = ObiActorBlueprintEditor.selectedCount > 0;
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("ClearButton"), "Clear selection"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
{
for (int i = 0; i < editor.selectionStatus.Length; i++)
editor.selectionStatus[i] = false;
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
ObiActorBlueprintEditor.selectionStatus[i] = false;
UpdateSelection();
}
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("OptimizeButton"), "Optimize selected"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
{
Undo.RecordObject(editor.blueprint, "Optimize particles away");
editor.blueprint.RemoveSelectedParticles(ref editor.selectionStatus);
editor.blueprint.RemoveSelectedParticles(ref ObiActorBlueprintEditor.selectionStatus);
editor.Refresh();
}
if (GUILayout.Button(new GUIContent(Resources.Load<Texture2D>("RemoveButton"), "Remove selected"), GUILayout.MaxHeight(24), GUILayout.MaxWidth(48)))
{
Undo.RecordObject(editor.blueprint, "Remove particles");
editor.blueprint.RemoveSelectedParticles(ref editor.selectionStatus, false);
editor.blueprint.RemoveSelectedParticles(ref ObiActorBlueprintEditor.selectionStatus, false);
editor.Refresh();
}
GUI.enabled = true;
@@ -175,12 +175,12 @@ namespace Obi
maxSelectionValue = EditorGUILayout.FloatField("Maximum " + property.name, maxSelectionValue);
if (EditorGUI.EndChangeCheck())
{
for (int i = 0; i < editor.selectionStatus.Length; i++)
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (editor.blueprint.IsParticleActive(i))
{
var value = property.Get(i);
editor.selectionStatus[i] = value >= minSelectionValue && value <= maxSelectionValue;
ObiActorBlueprintEditor.selectionStatus[i] = value >= minSelectionValue && value <= maxSelectionValue;
}
}
UpdateSelection();
@@ -244,9 +244,9 @@ namespace Obi
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(editor.blueprint, "Set particle property");
for (int i = 0; i < editor.selectionStatus.Length; i++)
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (!editor.selectionStatus[i]) continue;
if (!ObiActorBlueprintEditor.selectionStatus[i]) continue;
editor.currentProperty.SetDefaultToIndex(i);
}
editor.Refresh();
@@ -287,7 +287,7 @@ namespace Obi
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
editor.RenderModeSelector();
editor.dotRadiusScale = EditorGUILayout.Slider(new GUIContent("Particle dot size"), editor.dotRadiusScale, 0, 5);
ObiActorBlueprintEditor.dotRadiusScale = EditorGUILayout.Slider(new GUIContent("Particle dot size"), ObiActorBlueprintEditor.dotRadiusScale, 0, 5);
editor.currentProperty.VisualizationOptions();
EditorGUILayout.EndVertical();
@@ -301,31 +301,31 @@ namespace Obi
protected void UpdateSelection()
{
editor.selectedCount = 0;
ObiActorBlueprintEditor.selectedCount = 0;
mixedPropertyValue = false;
// Find out how many selected particles we have, and whether they all have the same value for the current property:
for (int i = 0; i < editor.selectionStatus.Length; i++)
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; i++)
{
if (editor.blueprint.IsParticleActive(i) && editor.selectionStatus[i])
if (editor.blueprint.IsParticleActive(i) && ObiActorBlueprintEditor.selectionStatus[i])
{
editor.selectedCount++;
ObiActorBlueprintEditor.selectedCount++;
if (editor.activeParticle >= 0)
if (ObiActorBlueprintEditor.activeParticle >= 0)
{
if (!editor.currentProperty.Equals(editor.activeParticle, i))
if (!editor.currentProperty.Equals(ObiActorBlueprintEditor.activeParticle, i))
mixedPropertyValue = true;
}
else
editor.activeParticle = i;
ObiActorBlueprintEditor.activeParticle = i;
}
else if (editor.activeParticle == i)
editor.activeParticle = -1;
else if (ObiActorBlueprintEditor.activeParticle == i)
ObiActorBlueprintEditor.activeParticle = -1;
}
// Set initial property value:
if (!mixedPropertyValue && editor.activeParticle >= 0)
editor.currentProperty.GetDefaultFromIndex(editor.activeParticle);
if (!mixedPropertyValue && ObiActorBlueprintEditor.activeParticle >= 0)
editor.currentProperty.GetDefaultFromIndex(ObiActorBlueprintEditor.activeParticle);
editor.Repaint();
SceneView.RepaintAll();

View File

@@ -52,7 +52,7 @@ namespace Obi
private void FloatFromTexture(int i, Color color)
{
if (!selectionMask || editor.selectionStatus[i])
if (!selectionMask || ObiActorBlueprintEditor.selectionStatus[i])
{
float value = minPropertyValue + color[(int)textureChannel] * (maxPropertyValue - minPropertyValue);
floatProperty.Set(i, value);
@@ -61,7 +61,7 @@ namespace Obi
private void ColorFromTexture(int i, Color color)
{
if (!selectionMask || editor.selectionStatus[i])
if (!selectionMask || ObiActorBlueprintEditor.selectionStatus[i])
colorProperty.Set(i, color);
}

View File

@@ -57,20 +57,20 @@ namespace Obi
if (GUILayout.Button("Generate tethers",GUILayout.MinHeight(32)))
{
// Select all particles in the tethered groups:
for (int i = 0; i < editor.selectionStatus.Length; ++i)
for (int i = 0; i < ObiActorBlueprintEditor.selectionStatus.Length; ++i)
{
editor.selectionStatus[i] = false;
ObiActorBlueprintEditor.selectionStatus[i] = false;
for (int j = 0; j < tetheredGroups.Length; ++j)
{
if (tetheredGroups[j] && editor.blueprint.groups[j].ContainsParticle(i))
{
editor.selectionStatus[i] = true;
ObiActorBlueprintEditor.selectionStatus[i] = true;
break;
}
}
}
editor.blueprint.GenerateTethers(editor.selectionStatus);
editor.blueprint.GenerateTethers(ObiActorBlueprintEditor.selectionStatus);
editor.Refresh();
}

View File

@@ -17,7 +17,7 @@ namespace Obi
protected override float WeightFromDistance(float distance)
{
// anything outside the brush should have zero weight:
if (distance > radius)
if (distance * EditorGUIUtility.pixelsPerPoint > radius)
return 0;
return 1;
}

View File

@@ -14,29 +14,27 @@ namespace Obi
[CustomEditor(typeof(ObiActorBlueprint), true)]
public class ObiActorBlueprintEditor : Editor, IObiSelectableParticleProvider
{
protected IEnumerator routine;
public List<ObiBlueprintEditorTool> tools = new List<ObiBlueprintEditorTool>();
public int currentToolIndex = 0;
protected List<ObiBlueprintPropertyBase> properties = new List<ObiBlueprintPropertyBase>();
public List<ObiBlueprintPropertyBase> properties = new List<ObiBlueprintPropertyBase>();
public int currentPropertyIndex = 0;
protected List<ObiBlueprintRenderMode> renderModes = new List<ObiBlueprintRenderMode>();
public List<ObiBlueprintRenderMode> renderModes = new List<ObiBlueprintRenderMode>();
public int renderModeFlags = 0;
BooleanPreference showRenderModes;
public bool autoGenerate = false;
public bool editMode = false;
public bool isEditing = false;
protected List<SceneStateCache> m_SceneStates;
protected SceneSetup[] oldSetup;
protected UnityEngine.Object oldSelection;
//Additional status info for all particles:
public float dotRadiusScale = 1;
public int selectedCount = 0;
public int activeParticle = -1;
public bool[] selectionStatus = new bool[0];
public static float dotRadiusScale = 1;
public static int selectedCount = 0;
public static int activeParticle = -1;
public static bool[] selectionStatus = new bool[0];
public bool[] visible = new bool[0];
public Color[] tint = new Color[0];
protected float[] sqrDistanceToCamera = new float[0];
@@ -78,6 +76,10 @@ namespace Obi
public virtual void OnEnable()
{
properties.Clear();
renderModes.Clear();
tools.Clear();
properties.Add(new ObiBlueprintMass(this));
properties.Add(new ObiBlueprintRadius(this));
properties.Add(new ObiBlueprintFilterCategory(this));
@@ -88,11 +90,12 @@ namespace Obi
#if (UNITY_2019_1_OR_NEWER)
renderCallback = new System.Action<ScriptableRenderContext, Camera>((cntxt, cam) => { DrawWithCamera(cam); });
RenderPipelineManager.beginCameraRendering -= renderCallback;
RenderPipelineManager.beginCameraRendering += renderCallback;
#endif
Camera.onPreCull -= DrawWithCamera;
Camera.onPreCull += DrawWithCamera;
SceneView.duringSceneGui += OnSceneGUI;
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
}
public virtual void OnDisable()
@@ -103,8 +106,8 @@ namespace Obi
RenderPipelineManager.beginCameraRendering -= renderCallback;
#endif
Camera.onPreCull -= DrawWithCamera;
ObiParticleEditorDrawing.DestroyParticlesMesh();
SceneView.duringSceneGui -= OnSceneGUI;
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
foreach (var tool in tools)
{
@@ -116,51 +119,77 @@ namespace Obi
{
renderMode.OnDestroy();
}
properties.Clear();
renderModes.Clear();
}
protected void Generate()
void OnPlayModeStateChanged(PlayModeStateChange playmodeState)
{
if (blueprint.empty)
if (playmodeState == PlayModeStateChange.ExitingEditMode)
{
if (StageUtility.GetCurrentStage() is ObiActorBlueprintEditorStage)
StageUtility.GoToMainStage();
}
}
protected bool Generate()
{
if (!blueprint.edited)
{
EditorUtility.SetDirty(target);
CoroutineJob job = new CoroutineJob();
routine = job.Start(blueprint.Generate());
EditorCoroutine.ShowCoroutineProgressBar("Generating blueprint...", ref routine);
IEnumerator routine = job.Start(blueprint.Generate());
EditorCoroutine.ShowCoroutineProgressBar("Generating blueprint...", routine);
Refresh();
EditorGUIUtility.ExitGUI();
}
else
{
if (EditorUtility.DisplayDialog("Blueprint generation", "This blueprint already contains data. Are you sure you want to re-generate this blueprint from scratch?", "Ok", "Cancel"))
if (EditorUtility.DisplayDialog("Blueprint generation", "This blueprint contains manually edited data. If you regenerate the blueprint, these changes will be lost. Are you sure you want to proceed?", "Ok", "Cancel"))
{
EditorUtility.SetDirty(target);
CoroutineJob job = new CoroutineJob();
routine = job.Start(blueprint.Generate());
EditorCoroutine.ShowCoroutineProgressBar("Generating blueprint...", ref routine);
IEnumerator routine = job.Start(blueprint.Generate());
EditorCoroutine.ShowCoroutineProgressBar("Generating blueprint...", routine);
Refresh();
EditorGUIUtility.ExitGUI();
}
else return false;
}
return true;
}
protected virtual bool ValidateBlueprint() { return true; }
private void DrawGenerationControls()
{
GUILayout.BeginHorizontal();
float originalLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = 72;
autoGenerate = EditorGUILayout.ToggleLeft("Auto Generate", autoGenerate, GUILayout.ExpandWidth(false));
EditorGUIUtility.labelWidth = originalLabelWidth;
GUI.enabled = !autoGenerate;
if (GUILayout.Button("Generate", GUI.skin.FindStyle("LargeButton"), GUILayout.Height(32)))
Generate();
GUILayout.EndHorizontal();
}
public override void OnInspectorGUI()
{
serializedObject.UpdateIfRequiredOrScript();
EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
EditorGUI.BeginChangeCheck();
DrawBlueprintProperties();
bool blueprintPropertiesChanged = EditorGUI.EndChangeCheck();
bool blueprintValid = ValidateBlueprint();
GUILayout.Space(10);
GUI.enabled = ValidateBlueprint();
if (GUILayout.Button("Generate", GUI.skin.FindStyle("LargeButton"), GUILayout.Height(32)))
Generate();
GUI.enabled = blueprintValid;
DrawGenerationControls();
GUI.enabled = (blueprint != null && !blueprint.empty && !Application.isPlaying);
EditorGUI.BeginChangeCheck();
@@ -180,7 +209,10 @@ namespace Obi
if (GUI.changed)
{
serializedObject.ApplyModifiedProperties();
serializedObject.ApplyModifiedPropertiesWithoutUndo();
if (autoGenerate && blueprintValid && blueprintPropertiesChanged)
blueprint.GenerateImmediate();
// There might be blueprint editing operations that have no undo entry, so do this to
// ensure changes are serialized to disk by Unity.
@@ -206,51 +238,17 @@ namespace Obi
}
}
[System.Serializable]
protected class SceneStateCache
{
public SceneView view;
public SceneView.SceneViewState state;
}
void EnterBlueprintEditMode()
{
if (!isEditing)
{
#if (UNITY_2019_1_OR_NEWER)
SceneView.duringSceneGui -= this.OnSceneGUI;
SceneView.duringSceneGui += this.OnSceneGUI;
#else
SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
SceneView.onSceneGUIDelegate += this.OnSceneGUI;
#endif
ActiveEditorTracker.sharedTracker.isLocked = true;
oldSelection = Selection.activeObject;
if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
{
ActiveEditorTracker.sharedTracker.isLocked = true;
string assetPath = AssetDatabase.GetAssetPath(blueprint);
ObiActorBlueprintEditorStage stage = ObiActorBlueprintEditorStage.CreateStage(assetPath, this);
StageUtility.GoToStage(stage, true);
oldSetup = EditorSceneManager.GetSceneManagerSetup();
EditorSceneManager.NewScene(NewSceneSetup.EmptyScene);
// Set properties for all scene views:
m_SceneStates = new List<SceneStateCache>();
foreach (SceneView s in SceneView.sceneViews)
{
m_SceneStates.Add(new SceneStateCache { state = new SceneView.SceneViewState(s.sceneViewState), view = s });
s.sceneViewState.showFlares = false;
s.sceneViewState.alwaysRefresh = false;
s.sceneViewState.showFog = false;
s.sceneViewState.showSkybox = false;
s.sceneViewState.showImageEffects = false;
s.sceneViewState.showParticleSystems = false;
s.Frame(blueprint.bounds);
}
isEditing = true;
Repaint();
}
isEditing = true;
}
}
@@ -258,52 +256,18 @@ namespace Obi
{
if (isEditing)
{
isEditing = false;
AssetDatabase.SaveAssets();
// Reset all scene views:
foreach (var state in m_SceneStates)
{
if (state.view == null)
continue;
state.view.sceneViewState.showFog = state.state.showFog;
state.view.sceneViewState.showFlares = state.state.showFlares;
state.view.sceneViewState.alwaysRefresh = state.state.alwaysRefresh;
state.view.sceneViewState.showSkybox = state.state.showSkybox;
state.view.sceneViewState.showImageEffects = state.state.showImageEffects;
state.view.sceneViewState.showParticleSystems = state.state.showParticleSystems;
}
ActiveEditorTracker.sharedTracker.isLocked = false;
if (SceneManager.GetActiveScene().path.Length <= 0)
{
if (oldSetup != null && oldSetup.Length > 0)
{
EditorSceneManager.RestoreSceneManagerSetup(oldSetup);
oldSetup = null;
}
else
{
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);
}
}
Selection.activeObject = oldSelection;
#if (UNITY_2019_1_OR_NEWER)
SceneView.duringSceneGui -= this.OnSceneGUI;
#else
SceneView.onSceneGUIDelegate -= this.OnSceneGUI;
#endif
Repaint();
StageUtility.GoToMainStage();
}
}
public void CleanupEditor()
{
ActiveEditorTracker.sharedTracker.isLocked = false;
ObiParticleEditorDrawing.DestroyParticlesMesh();
}
public virtual void OnSceneGUI(SceneView sceneView)
{
@@ -318,7 +282,7 @@ namespace Obi
{
// Update camera facing status and world space positions array:
UpdateParticleVisibility();
UpdateParticleVisibility(sceneView.camera);
// Generate sorted indices for back-to-front rendering:
for (int i = 0; i < sortedIndices.Length; i++)
@@ -339,7 +303,7 @@ namespace Obi
UpdateTintColor();
// Draw particle handles:
ObiParticleEditorDrawing.DrawParticles(sceneView.camera, blueprint, activeParticle, visible, tint, sortedIndices, dotRadiusScale);
ObiParticleEditorDrawing.DrawParticles(sceneView.camera, blueprint, visible, tint, sortedIndices, dotRadiusScale);
}
@@ -370,6 +334,7 @@ namespace Obi
{
if (blueprint.positions != null)
{
activeParticle = Mathf.Min(activeParticle, blueprint.positions.Length - 1);
Array.Resize(ref selectionStatus, blueprint.positions.Length);
Array.Resize(ref visible, blueprint.positions.Length);
Array.Resize(ref tint, blueprint.positions.Length);
@@ -413,7 +378,9 @@ namespace Obi
public void Refresh()
{
currentProperty.RecalculateMinMax();
// currentProperty might be null after reloading editor during
// asset saving.
currentProperty?.RecalculateMinMax();
// refresh render modes:
for (int i = 0; i < renderModes.Count; ++i)
@@ -425,7 +392,7 @@ namespace Obi
SceneView.RepaintAll();
}
public virtual void UpdateParticleVisibility()
public virtual void UpdateParticleVisibility(Camera cam)
{
for (int i = 0; i < blueprint.positions.Length; i++)
@@ -436,7 +403,7 @@ namespace Obi
if (Camera.current != null)
{
Vector3 camToParticle = Camera.current.transform.position - blueprint.positions[i];
Vector3 camToParticle = cam.transform.position - blueprint.positions[i];
sqrDistanceToCamera[i] = camToParticle.sqrMagnitude;
}
}

View File

@@ -0,0 +1,72 @@
using System;
using System.IO;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
namespace Obi
{
[Serializable]
class ObiActorBlueprintEditorStage : PreviewSceneStage
{
ObiActorBlueprintEditor m_BlueprintEditor;
string m_AssetPath;
public override string assetPath { get { return m_AssetPath; } }
internal static ObiActorBlueprintEditorStage CreateStage(string assetPath, ObiActorBlueprintEditor avatarEditor)
{
ObiActorBlueprintEditorStage stage = CreateInstance<ObiActorBlueprintEditorStage>();
stage.Init(assetPath, avatarEditor);
return stage;
}
private void Init(string modelAssetPath, ObiActorBlueprintEditor avatarEditor)
{
m_AssetPath = modelAssetPath;
m_BlueprintEditor = avatarEditor;
}
protected override bool OnOpenStage()
{
base.OnOpenStage();
if (!File.Exists(assetPath))
{
Debug.LogError("ActivateStage called on BlueprintStage with an invalid path: Blueprint file not found " + assetPath);
return false;
}
return true;
}
protected override void OnCloseStage()
{
m_BlueprintEditor.CleanupEditor();
base.OnCloseStage();
}
protected override void OnFirstTimeOpenStageInSceneView(SceneView sceneView)
{
// Frame in scene view
sceneView.Frame(m_BlueprintEditor.blueprint.bounds);
// Setup Scene view state
sceneView.sceneViewState.showFlares = false;
sceneView.sceneViewState.alwaysRefresh = false;
sceneView.sceneViewState.showFog = false;
sceneView.sceneViewState.showSkybox = false;
sceneView.sceneViewState.showImageEffects = false;
sceneView.sceneViewState.showParticleSystems = false;
sceneView.sceneLighting = true;
}
protected override GUIContent CreateHeaderContent()
{
return new GUIContent(
"Blueprint Editor",
Resources.Load<Texture2D>("Icons/ObiActorBlueprint Icon"));
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 7971633b9741349f3add282a07b0d69b
guid: 4c8d9d8042d49436c89c515b001088ac
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -18,6 +18,7 @@ namespace Obi
}
protected Mesh visualizationMesh;
protected Mesh visualizationWireMesh;
public ParticleCulling particleCulling = ParticleCulling.Back;
protected Material gradientMaterial;
@@ -75,46 +76,50 @@ namespace Obi
public abstract int VertexToParticle(int vertexIndex);
public override void UpdateParticleVisibility()
public override void UpdateParticleVisibility(Camera cam)
{
if (sourceMesh != null && Camera.current != null)
if (cam != null)
{
Vector3[] meshNormals = sourceMesh.normals;
for (int i = 0; i < sourceMesh.vertexCount; i++)
for (int i = 0; i < blueprint.positions.Length; i++)
{
int particle = VertexToParticle(i);
if (particle >= 0 && particle < blueprint.positions.Length)
if (blueprint.IsParticleActive(i))
{
Vector3 camToParticle = Camera.current.transform.position - blueprint.positions[particle];
Vector3 camToParticle = cam.transform.position - blueprint.positions[i];
sqrDistanceToCamera[i] = camToParticle.sqrMagnitude;
sqrDistanceToCamera[particle] = camToParticle.sqrMagnitude;
Vector3 normal;
switch (particleCulling)
{
case ParticleCulling.Off:
visible[particle] = true;
visible[i] = true;
break;
case ParticleCulling.Back:
visible[particle] = Vector3.Dot(meshNormals[i], camToParticle) > 0;
normal = blueprint.restOrientations[i] * Vector3.forward;
visible[i] = Vector3.Dot(normal, camToParticle) > 0;
break;
case ParticleCulling.Front:
visible[particle] = Vector3.Dot(meshNormals[i], camToParticle) <= 0;
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))
{
@@ -157,15 +162,16 @@ namespace Obi
colors[i] = Color.gray;
}
visualizationMesh.colors = colors;
visualizationWireMesh.colors = colors;
GL.wireframe = true;
Graphics.DrawMeshNow(visualizationMesh, matrix);
Graphics.DrawMeshNow(visualizationWireMesh, matrix);
GL.wireframe = false;
}
}
GameObject.DestroyImmediate(visualizationMesh);
GameObject.DestroyImmediate(visualizationWireMesh);
}
@@ -223,7 +229,8 @@ namespace Obi
RenderTexture.active = tempRT;
GL.PushMatrix();
GL.LoadProjectionMatrix(Matrix4x4.Ortho(0, 1, 0, 1, -1, 1));
var proj = Matrix4x4.Ortho(0, 1, 0, 1, -1, 1);
if (Camera.current != null) proj = proj * Camera.current.worldToCameraMatrix.inverse;
GL.LoadProjectionMatrix(proj);

View File

@@ -32,7 +32,7 @@ namespace Obi
GameObject.DestroyImmediate(particlesMesh);
}
public static void DrawParticles(Camera cam, ObiActorBlueprint blueprint, int activeParticle, bool[] visible, Color[] baseColor, int[] sortedIndices, float radiusScale = 1)
public static void DrawParticles(Camera cam, ObiActorBlueprint blueprint, bool[] visible, Color[] baseColor, int[] sortedIndices, float radiusScale = 1)
{
CreateParticlesMesh();
CreateParticleMaterials();

View File

@@ -22,6 +22,7 @@ namespace Obi
public override void Set(int index, Color value)
{
editor.blueprint.colors[index] = value;
editor.blueprint.edited = true;
}
public override bool Masked(int index)
{

View File

@@ -22,6 +22,7 @@ namespace Obi
public override void Set(int index, int value)
{
editor.blueprint.filters[index] = ObiUtils.MakeFilter(ObiUtils.GetMaskFromFilter(editor.blueprint.filters[index]), value);
editor.blueprint.edited = true;
}
public override bool Masked(int index)
{

View File

@@ -22,6 +22,7 @@
public override void Set(int index, int value)
{
editor.blueprint.filters[index] = ObiUtils.MakeFilter(value,ObiUtils.GetCategoryFromFilter(editor.blueprint.filters[index]));
editor.blueprint.edited = true;
}
public override bool Masked(int index)
{

View File

@@ -23,6 +23,7 @@ namespace Obi
public override void Set(int index, float value)
{
editor.blueprint.invMasses[index] = ObiUtils.MassToInvMass(value);
editor.blueprint.edited = true;
}
public override bool Masked(int index)
{

View File

@@ -27,6 +27,7 @@ namespace Obi
value = Mathf.Max(0.0000001f, value);
float ratio = value / Get(index);
editor.blueprint.principalRadii[index] = editor.blueprint.principalRadii[index] * ratio;
editor.blueprint.edited = true;
}
public override bool Masked(int index)
{

View File

@@ -24,10 +24,10 @@ namespace Obi
{
ObiPaintBrushEditorTool paintTool = (ObiPaintBrushEditorTool)meshBasedEditor.currentTool;
float[] weights = new float[editor.selectionStatus.Length];
float[] weights = new float[ObiActorBlueprintEditor.selectionStatus.Length];
for (int i = 0; i < weights.Length; i++)
{
if (paintTool.selectionMask && !editor.selectionStatus[i])
if (paintTool.selectionMask && !ObiActorBlueprintEditor.selectionStatus[i])
weights[i] = 0;
else
weights[i] = 1;

View File

@@ -13,11 +13,13 @@ namespace Obi
private Shader shader;
private Material material;
private ParticleImpostorRendering impostorDrawer;
private MaterialPropertyBlock mpb;
public ObiBlueprintRenderModeParticles(ObiActorBlueprintEditor editor) :base(editor)
{
impostorDrawer = new ParticleImpostorRendering();
impostorDrawer.UpdateMeshes(editor.blueprint);
mpb = new MaterialPropertyBlock();
}
void CreateMaterialIfNeeded()
@@ -43,8 +45,10 @@ namespace Obi
public override void DrawWithCamera(Camera camera)
{
CreateMaterialIfNeeded();
mpb.SetFloat("_RadiusScale", 1);
mpb.SetColor("_ParticleColor", Color.white);
foreach (Mesh mesh in impostorDrawer.Meshes)
Graphics.DrawMesh(mesh, Matrix4x4.identity, material, 0, camera);
Graphics.DrawMesh(mesh, Matrix4x4.identity, material, 0, camera, 0, mpb);
}
public override void Refresh()

View File

@@ -1,11 +1,12 @@
using UnityEditor;
using UnityEngine;
namespace Obi{
[CustomEditor(typeof(ObiColliderBase), true), CanEditMultipleObjects]
public class ObiColliderEditor : Editor
{
namespace Obi
{
[CustomEditor(typeof(ObiColliderBase), true), CanEditMultipleObjects]
public class ObiColliderEditor : Editor
{
ObiColliderBase collider;
SerializedProperty collisionFilter;
@@ -16,11 +17,42 @@ namespace Obi{
collisionFilter = serializedObject.FindProperty("filter");
}
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();
}
public override void OnInspectorGUI()
{
serializedObject.UpdateIfRequiredOrScript();
foreach (ObiColliderBase t in targets)
{
ObiMeshShapeTracker meshTracker = t.Tracker as ObiMeshShapeTracker;
if (meshTracker != null)
{
if (meshTracker.targetMesh != null && !meshTracker.targetMesh.isReadable)
NonReadableMeshWarning(meshTracker.targetMesh);
}
}
var rect = EditorGUILayout.GetControlRect();
var label = EditorGUI.BeginProperty(rect, new GUIContent("Collision category"), collisionFilter);
@@ -56,8 +88,13 @@ namespace Obi{
}
EditorGUI.EndProperty();
DrawPropertiesExcluding(serializedObject, "m_Script", "CollisionMaterial", "filter", "Thickness", "Inverted");
DrawPropertiesExcluding(serializedObject, "m_Script", "CollisionMaterial", "filter", "Thickness");
foreach (ObiColliderBase t in targets)
{
if (!t.gameObject.isStatic)
t.ForceUpdate();
}
// Apply changes to the serializedProperty
if (GUI.changed)

View File

@@ -68,7 +68,7 @@ namespace Obi{
EditorUtility.SetDirty(target);
CoroutineJob job = new CoroutineJob();
routine = job.Start( distanceField.Generate());
EditorCoroutine.ShowCoroutineProgressBar("Generating distance field",ref routine);
EditorCoroutine.ShowCoroutineProgressBar("Generating distance field", routine);
UpdatePreview();
EditorGUIUtility.ExitGUI();
}

View File

@@ -0,0 +1,30 @@
using UnityEditor;
using UnityEngine;
namespace Obi
{
/**
* Custom inspector for ObiForceZone component.
*/
[CustomEditor(typeof(ObiForceZone)), CanEditMultipleObjects]
public class ObiForceZoneEditor : Editor
{
public override void OnInspectorGUI()
{
serializedObject.UpdateIfRequiredOrScript();
DrawPropertiesExcluding(serializedObject, "m_Script");
// Apply changes to the serializedProperty
if (GUI.changed)
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e97d151316d5f4d16ac5ae6e68acccb6
guid: 724435a7a84154b27bb0c8ea49b611df
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -24,10 +24,20 @@ namespace Obi
GUI.Box(position,"",ObiEditorUtils.GetToggleablePropertyGroupStyle());
GUI.enabled = true;
// Draw main constraint toggle:
enabled.boolValue = EditorGUI.ToggleLeft(contRect, label.text, enabled.boolValue, EditorStyles.boldLabel);
// Draw main constraint toggle:
EditorGUI.BeginProperty(position, label, enabled);
EditorGUI.BeginChangeCheck();
var newEnabled = EditorGUI.ToggleLeft(contRect, label.text, enabled.boolValue, EditorStyles.boldLabel);
// Only assign the value back if it was actually changed by the user.
// Otherwise a single value will be assigned to all objects when multi-object editing,
// even when the user didn't touch the control.
if (EditorGUI.EndChangeCheck())
{
enabled.boolValue = newEnabled;
}
EditorGUI.EndProperty();
if (enabled.boolValue){
if (enabled.boolValue){
Rect evalRect = new Rect(position.x+padding, position.y+propHeight+padding, position.width-padding*2, propHeight);
Rect iterRect = new Rect(position.x+padding, position.y+propHeight*2+padding, position.width-padding*2, propHeight);

View File

@@ -1,83 +0,0 @@
using UnityEngine;
using UnityEditor;
using System.Collections;
namespace Obi
{
class ObiEditorSettings : ScriptableObject
{
public const string m_ObiEditorSettingsPath = "Assets/ObiEditorSettings.asset";
[SerializeField] private Color m_ParticleBrush;
[SerializeField] private Color m_BrushWireframe;
[SerializeField] private Color m_Particle;
[SerializeField] private Color m_SelectedParticle;
[SerializeField] private Color m_ActiveParticle;
[SerializeField] private Gradient m_PropertyGradient;
public Color brushColor
{
get { return m_ParticleBrush; }
}
public Color brushWireframeColor
{
get { return m_BrushWireframe; }
}
public Color particleColor
{
get { return m_Particle; }
}
public Color selectedParticleColor
{
get { return m_SelectedParticle; }
}
public Color activeParticleColor
{
get { return m_ActiveParticle; }
}
public Gradient propertyGradient
{
get { return m_PropertyGradient; }
}
internal static ObiEditorSettings GetOrCreateSettings()
{
var settings = AssetDatabase.LoadAssetAtPath<ObiEditorSettings>(m_ObiEditorSettingsPath);
if (settings == null)
{
settings = ScriptableObject.CreateInstance<ObiEditorSettings>();
settings.m_ParticleBrush = new Color32(243, 77, 43, 255);
settings.m_BrushWireframe = new Color32(0, 0, 0, 128);
settings.m_Particle = new Color32(240, 240, 240, 255);
settings.m_SelectedParticle = new Color32(243, 77, 43, 255);
settings.m_ActiveParticle = new Color32(243, 243, 43, 255);
settings.m_PropertyGradient = new Gradient();
// Populate the color keys at the relative time 0 and 1 (0 and 100%)
var colorKey = new GradientColorKey[2];
colorKey[0].color = Color.grey * 0.7f;
colorKey[0].time = 0.0f;
colorKey[1].color = Color.white;
colorKey[1].time = 1.0f;
// Populate the alpha keys at relative time 0 and 1 (0 and 100%)
var alphaKey = new GradientAlphaKey[2];
alphaKey[0].alpha = 1.0f;
alphaKey[0].time = 0.0f;
alphaKey[1].alpha = 1.0f;
alphaKey[1].time = 1.0f;
settings.m_PropertyGradient.SetKeys(colorKey, alphaKey);
AssetDatabase.CreateAsset(settings, m_ObiEditorSettingsPath);
AssetDatabase.SaveAssets();
}
return settings;
}
internal static SerializedObject GetSerializedSettings()
{
return new SerializedObject(GetOrCreateSettings());
}
}
}

View File

@@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using UnityEditor;
namespace Obi
{
[InitializeOnLoad]
public class ObiOniInitialize
{
private static BuildTargetGroup[] supportedBuildTargetGroups =
{
BuildTargetGroup.Standalone,
BuildTargetGroup.Android,
BuildTargetGroup.iOS
};
static ObiOniInitialize()
{
foreach(var group in supportedBuildTargetGroups)
{
var defines = GetDefinesList(group);
if (!defines.Contains("OBI_ONI_SUPPORTED"))
{
defines.Add("OBI_ONI_SUPPORTED");
PlayerSettings.SetScriptingDefineSymbolsForGroup(group, string.Join(";", defines.ToArray()));
}
}
}
private static List<string> GetDefinesList(BuildTargetGroup group)
{
return new List<string>(PlayerSettings.GetScriptingDefineSymbolsForGroup(group).Split(';'));
}
}
}

View File

@@ -15,7 +15,9 @@ namespace Obi
public static GUIContent brushWireframe = new GUIContent("Brush wireframe");
public static GUIContent particle = new GUIContent("Particle");
public static GUIContent selectedParticle = new GUIContent("Selected particle");
public static GUIContent activeParticle = new GUIContent("Active particle");
public static GUIContent propertyGradient = new GUIContent("Property gradient");
public static GUIContent particlePicking = new GUIContent("Particle GO picking");
}
const string m_ObiEditorSettingsPath = "Assets/ObiEditorSettings.asset";
@@ -52,7 +54,11 @@ namespace Obi
EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_BrushWireframe"),Styles.brushWireframe);
EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_Particle"),Styles.particle);
EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_SelectedParticle"),Styles.selectedParticle);
EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_ActiveParticle"), Styles.activeParticle);
EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_PropertyGradient"), Styles.propertyGradient);
EditorGUILayout.LabelField("Scene view", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(m_ObiSettings.FindProperty("m_ParticlePicking"), Styles.particlePicking);
}
// Register the SettingsProvider

View File

@@ -1,5 +1,6 @@
using UnityEditor;
using UnityEngine;
using UnityEditor.IMGUI.Controls;
using UnityEditorInternal;
using System;
using System.Collections;
@@ -40,13 +41,34 @@ namespace Obi
ObiSolver solver;
SerializedProperty backend;
SerializedProperty substeps;
SerializedProperty maxStepsPerFrame;
SerializedProperty synchronization;
SerializedProperty simulateWhenInvisible;
SerializedProperty parameters;
SerializedProperty gravity;
SerializedProperty gravitySpace;
SerializedProperty ambientWind;
SerializedProperty windSpace;
SerializedProperty useLimits;
SerializedProperty boundaryLimits;
SerializedProperty killOffLimitsParticles;
SerializedProperty worldLinearInertiaScale;
SerializedProperty worldAngularInertiaScale;
SerializedProperty foamSubsteps;
SerializedProperty foamMinNeighbors;
SerializedProperty foamCollisions;
SerializedProperty foamRadiusScale;
SerializedProperty foamVolumeDensity;
SerializedProperty foamAmbientDensity;
SerializedProperty foamScatterColor;
SerializedProperty foamAmbientColor;
SerializedProperty maxFoamVelocityStretch;
SerializedProperty foamFade;
SerializedProperty foamAccelAgingRange;
SerializedProperty foamAccelAging;
SerializedProperty distanceConstraintParameters;
SerializedProperty bendingConstraintParameters;
SerializedProperty particleCollisionConstraintParameters;
@@ -58,37 +80,72 @@ namespace Obi
SerializedProperty shapeMatchingConstraintParameters;
SerializedProperty tetherConstraintParameters;
SerializedProperty pinConstraintParameters;
SerializedProperty pinholeConstraintParameters;
SerializedProperty stitchConstraintParameters;
SerializedProperty densityConstraintParameters;
SerializedProperty stretchShearConstraintParameters;
SerializedProperty bendTwistConstraintParameters;
SerializedProperty chainConstraintParameters;
SerializedProperty maxSurfaceChunks;
SerializedProperty maxQueryResults;
SerializedProperty maxFoamParticles;
SerializedProperty maxParticleNeighbors;
SerializedProperty maxParticleContacts;
BooleanPreference solverFoldout;
BooleanPreference simulationFoldout;
BooleanPreference advectionFoldout;
BooleanPreference collisionsFoldout;
BooleanPreference constraintsFoldout;
BooleanPreference memoryFoldout;
GUIContent constraintLabelContent;
BoxBoundsHandle limitsBoxHandle;
public void OnEnable()
{
solver = (ObiSolver)target;
constraintLabelContent = new GUIContent();
limitsBoxHandle = new BoxBoundsHandle();
solverFoldout = new BooleanPreference($"{target.GetType()}.solverFoldout", true);
simulationFoldout = new BooleanPreference($"{target.GetType()}.simulationFoldout", false);
advectionFoldout = new BooleanPreference($"{target.GetType()}.advectionFoldout", false);
collisionsFoldout = new BooleanPreference($"{target.GetType()}.collisionsFoldout", false);
constraintsFoldout = new BooleanPreference($"{target.GetType()}.constraintsFoldout", false);
memoryFoldout = new BooleanPreference($"{target.GetType()}.memoryFoldout", false);
backend = serializedObject.FindProperty("m_Backend");
substeps = serializedObject.FindProperty("substeps");
maxStepsPerFrame = serializedObject.FindProperty("maxStepsPerFrame");
synchronization = serializedObject.FindProperty("synchronization");
simulateWhenInvisible = serializedObject.FindProperty("simulateWhenInvisible");
parameters = serializedObject.FindProperty("parameters");
gravity = serializedObject.FindProperty("gravity");
gravitySpace = serializedObject.FindProperty("gravitySpace");
ambientWind = serializedObject.FindProperty("ambientWind");
windSpace = serializedObject.FindProperty("windSpace");
useLimits = serializedObject.FindProperty("useLimits");
boundaryLimits = serializedObject.FindProperty("boundaryLimits");
killOffLimitsParticles = serializedObject.FindProperty("killOffLimitsParticles");
worldLinearInertiaScale = serializedObject.FindProperty("worldLinearInertiaScale");
worldAngularInertiaScale = serializedObject.FindProperty("worldAngularInertiaScale");
foamSubsteps = serializedObject.FindProperty("foamSubsteps");
foamMinNeighbors = serializedObject.FindProperty("foamMinNeighbors");
foamCollisions = serializedObject.FindProperty("foamCollisions");
foamRadiusScale = serializedObject.FindProperty("foamRadiusScale");
foamVolumeDensity = serializedObject.FindProperty("foamVolumeDensity");
foamAmbientDensity = serializedObject.FindProperty("foamAmbientDensity");
foamScatterColor = serializedObject.FindProperty("foamScatterColor");
foamAmbientColor = serializedObject.FindProperty("foamAmbientColor");
maxFoamVelocityStretch = serializedObject.FindProperty("maxFoamVelocityStretch");
foamFade = serializedObject.FindProperty("foamFade");
foamAccelAgingRange = serializedObject.FindProperty("foamAccelAgingRange");
foamAccelAging = serializedObject.FindProperty("foamAccelAging");
distanceConstraintParameters = serializedObject.FindProperty("distanceConstraintParameters");
bendingConstraintParameters = serializedObject.FindProperty("bendingConstraintParameters");
particleCollisionConstraintParameters = serializedObject.FindProperty("particleCollisionConstraintParameters");
@@ -100,19 +157,45 @@ namespace Obi
shapeMatchingConstraintParameters = serializedObject.FindProperty("shapeMatchingConstraintParameters");
tetherConstraintParameters = serializedObject.FindProperty("tetherConstraintParameters");
pinConstraintParameters = serializedObject.FindProperty("pinConstraintParameters");
pinholeConstraintParameters = serializedObject.FindProperty("pinholeConstraintParameters");
stitchConstraintParameters = serializedObject.FindProperty("stitchConstraintParameters");
densityConstraintParameters = serializedObject.FindProperty("densityConstraintParameters");
stretchShearConstraintParameters = serializedObject.FindProperty("stretchShearConstraintParameters");
bendTwistConstraintParameters = serializedObject.FindProperty("bendTwistConstraintParameters");
chainConstraintParameters = serializedObject.FindProperty("chainConstraintParameters");
maxSurfaceChunks = serializedObject.FindProperty("m_MaxSurfaceChunks");
maxQueryResults = serializedObject.FindProperty("maxQueryResults");
maxFoamParticles = serializedObject.FindProperty("maxFoamParticles");
maxParticleNeighbors = serializedObject.FindProperty("maxParticleNeighbors");
maxParticleContacts = serializedObject.FindProperty("maxParticleContacts");
}
public void OnSceneGUI()
{
if (solver.useLimits)
{
using (new Handles.DrawingScope(Color.red, solver.transform.localToWorldMatrix))
{
limitsBoxHandle.center = solver.boundaryLimits.center;
limitsBoxHandle.size = solver.boundaryLimits.size;
EditorGUI.BeginChangeCheck();
limitsBoxHandle.DrawHandle();
if (EditorGUI.EndChangeCheck())
{
solver.boundaryLimits = new Bounds(limitsBoxHandle.center, limitsBoxHandle.size);
EditorUtility.SetDirty(target);
}
}
}
}
public override void OnInspectorGUI()
{
serializedObject.UpdateIfRequiredOrScript();
EditorGUILayout.HelpBox("Particles:" + solver.allocParticleCount +"\n"+
"Simplices:" + solver.simplexCounts.simplexCount+"\n" +
EditorGUILayout.HelpBox("Particles:" + solver.allocParticleCount + "\n" +
"Simplices:" + solver.simplexCounts.simplexCount + "\n" +
"Contacts:" + solver.contactCount + "\n" +
"Simplex contacts:" + solver.particleContactCount, MessageType.None);
@@ -123,13 +206,14 @@ namespace Obi
EditorGUILayout.PropertyField(backend);
#if !(OBI_BURST && OBI_MATHEMATICS && OBI_COLLECTIONS)
if (backend.enumValueIndex == (int)ObiSolver.BackendType.Burst)
EditorGUILayout.HelpBox("The Burst backend depends on the following packages: Mathematics, Collections, Jobs and Burst. The default backend (Oni) will be used instead, if possible.", MessageType.Warning);
#endif
#if !(OBI_ONI_SUPPORTED)
if (backend.enumValueIndex == (int)ObiSolver.BackendType.Oni)
EditorGUILayout.HelpBox("The Oni backend is not compatible with the target platform. Please switch to a compatible platform, or use the Burst backend instead.", MessageType.Warning);
if (backend.enumValueIndex == (int)ObiSolver.BackendType.Burst)
EditorGUILayout.HelpBox("The Burst backend depends on the following packages: Mathematics, Collections, Jobs and Burst. Please install the required dependencies. The solver will try to fall back to the Compute backend instead.", MessageType.Warning);
#endif
if (!SystemInfo.supportsComputeShaders)
{
EditorGUILayout.HelpBox("This platform doesn't support compute shaders. Please switch to the Burst backend.", MessageType.Error);
}
if (EditorGUI.EndChangeCheck())
{
@@ -138,9 +222,11 @@ namespace Obi
(t as ObiSolver).UpdateBackend();
}
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("mode"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("interpolation"));
EditorGUILayout.PropertyField(synchronization);
EditorGUILayout.PropertyField(substeps);
EditorGUILayout.PropertyField(maxStepsPerFrame);
}
EditorGUILayout.EndFoldoutHeaderGroup();
@@ -149,24 +235,57 @@ namespace Obi
{
EditorGUILayout.PropertyField(gravitySpace);
EditorGUILayout.PropertyField(gravity);
EditorGUILayout.PropertyField(windSpace);
EditorGUILayout.PropertyField(ambientWind);
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("sleepThreshold"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("maxVelocity"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("maxAngularVelocity"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("damping"));
EditorGUILayout.PropertyField(worldLinearInertiaScale);
EditorGUILayout.PropertyField(worldAngularInertiaScale);
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("maxAnisotropy"));
EditorGUILayout.PropertyField(simulateWhenInvisible);
EditorGUILayout.PropertyField(useLimits);
if (useLimits.boolValue)
{
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(killOffLimitsParticles);
EditorGUILayout.PropertyField(boundaryLimits);
EditorGUI.indentLevel--;
}
}
EditorGUILayout.EndFoldoutHeaderGroup();
advectionFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(advectionFoldout, "Foam settings");
if (advectionFoldout)
{
EditorGUILayout.PropertyField(foamSubsteps);
EditorGUILayout.PropertyField(foamMinNeighbors);
EditorGUILayout.PropertyField(foamCollisions, new GUIContent("Foam Collisions (Compute only)"));
EditorGUILayout.PropertyField(foamRadiusScale);
EditorGUILayout.PropertyField(foamVolumeDensity);
EditorGUILayout.PropertyField(foamAmbientDensity);
EditorGUILayout.PropertyField(foamScatterColor);
EditorGUILayout.PropertyField(foamAmbientColor);
EditorGUILayout.PropertyField(maxFoamVelocityStretch);
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("foamGravityScale"));
EditorGUILayout.PropertyField(foamFade);
EditorGUILayout.PropertyField(foamAccelAgingRange);
EditorGUILayout.PropertyField(foamAccelAging);
}
EditorGUILayout.EndFoldoutHeaderGroup();
collisionsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(collisionsFoldout, "Collision settings");
if (collisionsFoldout)
{
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("continuousCollisionDetection"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("colliderCCD"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("particleCCD"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("collisionMargin"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("maxDepenetration"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("shockPropagation"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("surfaceCollisionIterations"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("surfaceCollisionTolerance"));
EditorGUILayout.PropertyField(parameters.FindPropertyRelative("diffusionMask"));
}
EditorGUILayout.EndFoldoutHeaderGroup();
@@ -206,6 +325,9 @@ namespace Obi
constraintLabelContent.text = "Pin";
EditorGUILayout.PropertyField(pinConstraintParameters, constraintLabelContent);
constraintLabelContent.text = "Pinhole";
EditorGUILayout.PropertyField(pinholeConstraintParameters, constraintLabelContent);
constraintLabelContent.text = "Stitch";
EditorGUILayout.PropertyField(stitchConstraintParameters, constraintLabelContent);
@@ -223,13 +345,46 @@ namespace Obi
}
EditorGUILayout.EndFoldoutHeaderGroup();
memoryFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(memoryFoldout, "Memory budget");
if (memoryFoldout)
{
EditorGUILayout.PropertyField(maxQueryResults);
EditorGUILayout.PropertyField(maxFoamParticles);
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(maxSurfaceChunks);
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
foreach (var t in targets)
(t as ObiSolver).dirtyRendering |= (int)Oni.RenderingSystemType.Fluid;
}
EditorGUILayout.PropertyField(maxParticleNeighbors);
EditorGUILayout.PropertyField(maxParticleContacts);
uint usedChunks = solver.usedSurfaceChunks;
float usagePercentage = usedChunks / (float)maxSurfaceChunks.intValue;
uint foamParticles = solver.initialized ? solver.implementation.activeFoamParticleCount : 0;
// memory consumption per chunk:
// (8 + 12 + 64*4 + 64*6*4 + 64*16) = 2836 bytes
EditorGUILayout.HelpBox("Active foam particles: " + foamParticles + "/" + maxFoamParticles.intValue + "\n"+
"Surface memory (Mb): " + string.Format("{0:N2}", maxSurfaceChunks.intValue * 0.002836f)+ "\n"+
"Used surface chunks: "+ usedChunks + "/"+ maxSurfaceChunks.intValue + ", hashtable usage "+ string.Format("{0:N1}", usagePercentage * 100) + "%", MessageType.None);
if (usagePercentage >= 0.5f)
{
EditorGUILayout.HelpBox("Hashtable usage should be below 50% for best performance. Increase max surface chunks if % is too high.", MessageType.Warning);
}
}
EditorGUILayout.EndFoldoutHeaderGroup();
// Apply changes to the serializedProperty
if (GUI.changed)
{
serializedObject.ApplyModifiedProperties();
solver.PushSolverParameters();
}
}
@@ -237,15 +392,12 @@ namespace Obi
[DrawGizmo(GizmoType.InSelectionHierarchy | GizmoType.Selected)]
static void DrawGizmoForSolver(ObiSolver solver, GizmoType gizmoType)
{
if ((gizmoType & GizmoType.InSelectionHierarchy) != 0)
{
Gizmos.color = new Color(1, 1, 1, 0.5f);
Bounds bounds = solver.Bounds;
var bounds = solver.bounds;
Gizmos.DrawWireCube(bounds.center, bounds.size);
}
}
}

View File

@@ -4,6 +4,7 @@ using UnityEngine.SceneManagement;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.IO;
using UnityEngine.Rendering;
namespace Obi{
@@ -127,17 +128,7 @@ namespace Obi{
public static GameObject CreateNewSolver()
{
// Root for the actors.
var root = new GameObject("Obi Solver");
ObiSolver solver = root.AddComponent<ObiSolver>();
// Try to find a fixed updater in the scene (though other kinds of updaters can exist, updating in FixedUpdate is the preferred option).
ObiFixedUpdater updater = StageUtility.GetCurrentStageHandle().FindComponentOfType<ObiFixedUpdater>();
// If we could not find an fixed updater in the scene, add one to the solver object.
if (updater == null)
updater = root.AddComponent<ObiFixedUpdater>();
// Add the solver to the updater:
updater.solvers.Add(solver);
var root = new GameObject("Obi Solver", typeof(ObiSolver));
// Works for all stages.
StageUtility.PlaceGameObjectInCurrentStage(root);
@@ -230,7 +221,34 @@ namespace Obi{
// Return the currently selected item's index
return selected;
}
}
public static void DrawArrowHandle(Vector3 posA, Vector3 posB, float headAngle = 30, float headLength = 0.18f)
{
Handles.DrawLine(posA, posB);
var look = Quaternion.LookRotation(posA - posB, Camera.current.transform.forward);
var one = look * Quaternion.Euler(0, 180 + headAngle, 0) * new Vector3(0, 0, 1);
var two = look * Quaternion.Euler(0, 180 - headAngle, 0) * new Vector3(0, 0, 1);
var sizeA = HandleUtility.GetHandleSize(posA) * headLength;
Handles.DrawLine(posA, posA + one * sizeA);
Handles.DrawLine(posA, posA + two * sizeA);
var sizeB = HandleUtility.GetHandleSize(posB) * headLength;
Handles.DrawLine(posB, posB - one * sizeB);
Handles.DrawLine(posB, posB - two * sizeB);
}
public static Material GetDefaultMaterial()
{
if (GraphicsSettings.defaultRenderPipeline != null)
{
return GraphicsSettings.defaultRenderPipeline.defaultMaterial;
}
else
{
return AssetDatabase.GetBuiltinExtraResource<Material>("Default-Diffuse.mat");
}
}
}
}

View File

@@ -0,0 +1,24 @@
using UnityEditor;
using UnityEngine;
namespace Obi
{
[CustomEditor(typeof(ObiFoamGenerator)), CanEditMultipleObjects]
public class ObiFoamGeneratorEditor : Editor
{
public override void OnInspectorGUI()
{
serializedObject.UpdateIfRequiredOrScript();
DrawPropertiesExcluding(serializedObject, "m_Script");
// Apply changes to the serializedProperty
if (GUI.changed)
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b9656e2c54d9e4c478c74ca6d97428f8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -15,6 +15,7 @@ namespace Obi
SerializedProperty targetTransform;
SerializedProperty particleGroup;
SerializedProperty attachmentType;
SerializedProperty projectPosition;
SerializedProperty constrainOrientation;
SerializedProperty compliance;
SerializedProperty breakThreshold;
@@ -28,9 +29,10 @@ namespace Obi
targetTransform = serializedObject.FindProperty("m_Target");
particleGroup = serializedObject.FindProperty("m_ParticleGroup");
attachmentType = serializedObject.FindProperty("m_AttachmentType");
projectPosition = serializedObject.FindProperty("m_Projection");
constrainOrientation = serializedObject.FindProperty("m_ConstrainOrientation");
compliance = serializedObject.FindProperty("m_Compliance");
breakThreshold = serializedObject.FindProperty("m_BreakThreshold");
breakThreshold = serializedObject.FindProperty("breakThreshold");
}
public override void OnInspectorGUI()
@@ -55,7 +57,16 @@ namespace Obi
}
}
EditorGUILayout.PropertyField(targetTransform, new GUIContent("Target"));
EditorGUI.BeginChangeCheck();
Transform trget = EditorGUILayout.ObjectField("Target", attachment.target, typeof(Transform), true) as Transform;
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(attachment, "Set target");
attachment.target = trget;
PrefabUtility.RecordPrefabInstancePropertyModifications(attachment);
}
var blueprint = attachment.actor.sourceBlueprint;
if (blueprint != null)
@@ -89,6 +100,7 @@ namespace Obi
if (attachment.attachmentType == ObiParticleAttachment.AttachmentType.Dynamic)
{
EditorGUILayout.PropertyField(projectPosition, new GUIContent("Projection"));
EditorGUILayout.PropertyField(compliance, new GUIContent("Compliance"));
EditorGUILayout.PropertyField(breakThreshold, new GUIContent("Break threshold"));
}

View File

@@ -42,6 +42,9 @@ namespace Obi{
if (EditorGUI.EndChangeCheck()){
Undo.RecordObject(stitcher, "Set first actor");
stitcher.Actor1 = actor1;
if (actor1 != null)
sewingToolHandle1 = actor1.transform.position;
PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
}
EditorGUI.BeginChangeCheck();
@@ -49,7 +52,10 @@ namespace Obi{
if (EditorGUI.EndChangeCheck()){
Undo.RecordObject(stitcher, "Set second actor");
stitcher.Actor2 = actor2;
}
if (actor2 != null)
sewingToolHandle2 = actor2.transform.position;
PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
}
if (stitcher.Actor1 != null && stitcher.Actor2 != null && stitcher.Actor1.solver != stitcher.Actor2.solver){
EditorGUILayout.HelpBox("Both actors must be managed by the same solver.",MessageType.Error);
@@ -63,14 +69,13 @@ namespace Obi{
if (editing){
EditorGUILayout.HelpBox("Remember that when working with the sewing tool, you can use Unity's snap to vertex feature by pressing 'V' in your keyboard.",MessageType.Info);
// Clear all stitches
if (GUILayout.Button("Clear all stitches")){
if (EditorUtility.DisplayDialog("Clearing stitches","Are you sure you want to remove all stitches?","Ok","Cancel")){
Undo.RecordObject(stitcher, "Clear all stitches");
stitcher.Clear();
}
PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
}
}
// Remove selected stitches
@@ -93,19 +98,22 @@ namespace Obi{
foreach(int i in removedStitches.OrderByDescending(i => i)){
stitcher.RemoveStitch(i);
}
}
PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
}
}
// Add stitch:
if (GUILayout.Button("Add Stitch")){
Undo.RecordObject(stitcher, "Add stitch");
if (GUILayout.Button("Add Stitch"))
{
FindClosestParticles(out int particle1, out int particle2);
int particle1 = 0;
int particle2 = 0;
UseSewingTool(ref particle1, ref particle2);
stitcher.AddStitch(particle1,particle2);
}
if (particle1 >= 0 && particle2 >= 0)
{
Undo.RecordObject(stitcher, "Add stitch");
stitcher.AddStitch(particle1, particle2);
PrefabUtility.RecordPrefabInstancePropertyModifications(stitcher);
}
}
}
GUI.enabled = true;
@@ -120,16 +128,28 @@ namespace Obi{
}
public void UseSewingTool(ref int particle1, ref int particle2){
public void FindClosestParticles(out int particle1, out int particle2)
{
particle1 = -1;
particle2 = -1;
float minDistance = float.MaxValue;
float minDistance = float.MaxValue;
if (stitcher.Actor1 == null || stitcher.Actor2 == null)
return;
if (stitcher.Actor1 == stitcher.Actor2){
var handle1 = HandleUtility.WorldToGUIPointWithDepth(sewingToolHandle1);
var handle2 = HandleUtility.WorldToGUIPointWithDepth(sewingToolHandle2);
if (stitcher.Actor1 == stitcher.Actor2)
{
float minDistance2 = float.MaxValue;
for (int i = 0; i < stitcher.Actor1.particleCount;++i){
for (int i = 0; i < stitcher.Actor1.activeParticleCount;++i)
{
Vector3 pos = stitcher.Actor1.GetParticlePosition(stitcher.Actor1.solverIndices[i]);
float distance1 = (pos - sewingToolHandle1).sqrMagnitude;
float distance2 = (pos - sewingToolHandle2).sqrMagnitude;
pos = HandleUtility.WorldToGUIPointWithDepth(pos);
float distance1 = (pos - handle1).sqrMagnitude;
float distance2 = (pos - handle2).sqrMagnitude;
if (distance1 < minDistance){
minDistance = distance1;
particle1 = i;
@@ -142,24 +162,28 @@ namespace Obi{
}else{
// find closest particle to each end of the sewing tool:
for (int i = 0; i < stitcher.Actor1.particleCount;++i){
for (int i = 0; i < stitcher.Actor1.activeParticleCount; ++i)
{
Vector3 pos = stitcher.Actor1.GetParticlePosition(stitcher.Actor1.solverIndices[i]);
float distance1 = (pos - sewingToolHandle1).sqrMagnitude;
float distance2 = (pos - sewingToolHandle2).sqrMagnitude;
float min = Mathf.Min(distance1,distance2);
if (min < minDistance){
pos = HandleUtility.WorldToGUIPointWithDepth(pos);
float min = (pos - handle1).sqrMagnitude;
if (min < minDistance)
{
minDistance = min;
particle1 = i;
}
}
minDistance = float.MaxValue;
for (int i = 0; i < stitcher.Actor2.particleCount;++i){
for (int i = 0; i < stitcher.Actor2.activeParticleCount; ++i)
{
Vector3 pos = stitcher.Actor2.GetParticlePosition(stitcher.Actor2.solverIndices[i]);
float distance1 = (pos - sewingToolHandle1).sqrMagnitude;
float distance2 = (pos - sewingToolHandle2).sqrMagnitude;
float min = Mathf.Min(distance1,distance2);
if (min < minDistance){
pos = HandleUtility.WorldToGUIPointWithDepth(pos);
float min = (pos - handle2).sqrMagnitude;
if (min < minDistance)
{
minDistance = min;
particle2 = i;
}
@@ -167,10 +191,32 @@ namespace Obi{
}
}
public void DrawSewingTool(){
var fmh_171_72_639027316145683117 = Quaternion.identity; sewingToolHandle1 = Handles.FreeMoveHandle(sewingToolHandle1,HandleUtility.GetHandleSize(sewingToolHandle1)*0.05f,new Vector3(.5f,.5f,.5f),Handles.RectangleHandleCap);
var fmh_172_66_639027316145718628 = Quaternion.identity; sewingToolHandle2 = Handles.FreeMoveHandle(sewingToolHandle2,HandleUtility.GetHandleSize(sewingToolHandle2)*0.05f,new Vector3(.5f,.5f,.5f),Handles.RectangleHandleCap);
Handles.DrawDottedLine(sewingToolHandle1,sewingToolHandle2,2);
public void DrawSewingTool()
{
FindClosestParticles(out int particle1, out int particle2);
if (particle1 >= 0 && particle2 >= 0)
{
sewingToolHandle1 = stitcher.Actor1.GetParticlePosition(stitcher.Actor1.solverIndices[particle1]);
sewingToolHandle2 = stitcher.Actor2.GetParticlePosition(stitcher.Actor2.solverIndices[particle2]);
float radius1 = stitcher.Actor1.GetParticleMaxRadius(stitcher.Actor1.solverIndices[particle1]);
float radius2 = stitcher.Actor2.GetParticleMaxRadius(stitcher.Actor2.solverIndices[particle2]);
Handles.color = Color.white;
#if (UNITY_2022_1_OR_NEWER)
sewingToolHandle1 = Handles.FreeMoveHandle(sewingToolHandle1, radius1 * 2, new Vector3(.5f,.5f,.5f),Handles.SphereHandleCap);
sewingToolHandle2 = Handles.FreeMoveHandle(sewingToolHandle2, radius2 * 2, new Vector3(.5f,.5f,.5f),Handles.SphereHandleCap);
#else
sewingToolHandle1 = Handles.FreeMoveHandle(sewingToolHandle1, Quaternion.identity, radius1 * 2, new Vector3(.5f, .5f, .5f), Handles.SphereHandleCap);
sewingToolHandle2 = Handles.FreeMoveHandle(sewingToolHandle2, Quaternion.identity, radius2 * 2, new Vector3(.5f, .5f, .5f), Handles.SphereHandleCap);
#endif
Vector3 direction = Vector3.Normalize(sewingToolHandle2 - sewingToolHandle1);
Handles.color = Color.yellow;
ObiEditorUtils.DrawArrowHandle(sewingToolHandle1 + direction*(radius1 + 0.05f), sewingToolHandle2 - direction*(radius2+0.05f));
}
}
/**
@@ -221,7 +267,7 @@ namespace Obi{
}
break;
case EventType.Repaint:
Handles.color = selectionStatus[i]?Color.red:Color.green;
Handles.color = selectionStatus[i]?Color.red:Color.cyan;
Handles.DrawDottedLine(pos1,pos2,2);
break;
}

View File

@@ -81,8 +81,8 @@ Material:
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _AABBMax: {r: 1.3624613, g: 1.3624613, b: 1.3624613, a: 0}
- _AABBMin: {r: -1.3624613, g: -1.3624613, b: -1.3624613, a: 0}
- _AABBMax: {r: 1.1746451, g: 1.1746451, b: 1.1746451, a: 0}
- _AABBMin: {r: -1.1746451, g: -1.1746451, b: -1.1746451, a: 0}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _InsideColor: {r: 1, g: 1, b: 1, a: 1}

View File

@@ -18,8 +18,8 @@
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "../../Resources/ObiMaterials/ObiEllipsoids.cginc"
#include "../../Resources/ObiMaterials/ObiUtils.cginc"
#include "../../Resources/ObiMaterials/Common/ObiEllipsoids.cginc"
#include "../../Resources/ObiMaterials/Common/ObiUtils.cginc"
fixed4 _Color;
@@ -42,6 +42,7 @@
float3 lightDir : TEXCOORD2;
float3 a2 : TEXCOORD3;
float3 a3 : TEXCOORD4;
//float3x3 P : TEXCOORD5;
};
struct fout
@@ -65,6 +66,7 @@
o.mapping = float4(v.corner.xy,1/length(eye),radius); // A[1]
o.viewRay = mul((float3x3)UNITY_MATRIX_V,view); // A[0]
o.color = v.color * _Color;
//o.P = float3x3(v.t0.xyz,v.t1.xyz,v.t2.xyz);
BuildAuxiliaryNormalVectors(v.vertex,worldPos,view,P,IP,o.a2,o.a3);
@@ -86,6 +88,19 @@
// clip space position:
float4 pos = mul(UNITY_MATRIX_P,float4(p,1.0));
// local space normal, use to calculate UVs
/*float3 ln = mul(mul((float3x3)i.P,UNITY_MATRIX_I_V) ,n);
float2 uv = float2(
// atan returns a value between -pi and pi
// so we divide by pi * 2 to get -0.5 to 0.5
atan2(ln.x, ln.y) / (3.1415 * 2.0),
// acos returns 0.0 at the top, pi at the bottom
// so we flip the y to align with Unity's OpenGL style
// texture UVs so 0.0 is at the bottom
acos(-ln.z) / 3.1415
);*/
// simple lighting: ambient
float3 modelUp = mul (UNITY_MATRIX_IT_MV,float3(0,1,0));
float vecHemi = dot(n, modelUp) * 0.5f + 0.5f;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -1,12 +1,12 @@
fileFormatVersion: 2
guid: 4e2c952f509ae40bdaf836136058d487
guid: b7cec6e680e3a479ca03a89eccd4e052
TextureImporter:
fileIDToRecycleName: {}
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 5
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
@@ -21,6 +21,10 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
@@ -29,12 +33,12 @@ TextureImporter:
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
filterMode: 1
aniso: 1
mipBias: -1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: -1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
@@ -52,11 +56,15 @@ TextureImporter:
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 2
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -67,7 +75,8 @@ TextureImporter:
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
@@ -78,19 +87,9 @@ TextureImporter:
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Android
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
@@ -100,6 +99,7 @@ TextureImporter:
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
@@ -107,11 +107,16 @@ TextureImporter:
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -1,17 +1,18 @@
fileFormatVersion: 2
guid: 092f06332c018434b8c8ea86164ef4fd
timeCreated: 1482503923
licenseType: Store
guid: 8791eecf125744cbeadea65319c29d5a
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
@@ -20,6 +21,10 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
@@ -27,10 +32,13 @@ TextureImporter:
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: -1
wrapMode: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
@@ -39,54 +47,76 @@ TextureImporter:
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -1,17 +1,18 @@
fileFormatVersion: 2
guid: 7b6e7fb3568d24300be305b5d1d7554d
timeCreated: 1454660299
licenseType: Store
guid: 214df93f7c2ed4c1094bb6105c050575
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 0
linearTexture: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
@@ -20,17 +21,24 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: -1
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: -1
wrapMode: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
@@ -39,54 +47,76 @@ TextureImporter:
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: iPhone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,122 @@
fileFormatVersion: 2
guid: eac6271e2e50d4b2dbf2dfeff9b65604
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -8,8 +8,8 @@
Pass {
Offset 0, -50
Cull Back
Offset -0.5, -0.5
Cull Back
Fog { Mode Off }
CGPROGRAM
@@ -49,7 +49,7 @@
Pass {
Offset 0, -100
Offset -1, -1
Cull Back
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha

View File

@@ -1,17 +1,18 @@
fileFormatVersion: 2
guid: 931c48569a82e4dae84d4702bf6da199
timeCreated: 1478802054
licenseType: Store
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
@@ -20,40 +21,78 @@ TextureImporter:
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 0
generateCubemap: 6
cubemapConvolution: 0
cubemapConvolutionSteps: 7
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -1
maxTextureSize: 2048
textureSettings:
filterMode: -1
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: -1
wrapMode: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
allowsAlphaSplitting: 0
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
buildTargetSettings: []
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 1
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 1
pSDShowRemoveMatteOption: 1
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -33,6 +33,10 @@ namespace Obi
SerializedProperty plasticYield;
SerializedProperty plasticCreep;
SerializedProperty aerodynamicsEnabled;
SerializedProperty drag;
SerializedProperty lift;
SerializedProperty fixRoot;
SerializedProperty stretchBones;
SerializedProperty ignored;
@@ -69,6 +73,9 @@ namespace Obi
plasticYield = serializedObject.FindProperty("_plasticYield");
plasticCreep = serializedObject.FindProperty("_plasticCreep");
aerodynamicsEnabled = serializedObject.FindProperty("_aerodynamicsEnabled");
drag = serializedObject.FindProperty("_drag");
lift = serializedObject.FindProperty("_lift");
}
public void OnDisable()
@@ -144,6 +151,12 @@ namespace Obi
EditorGUILayout.PropertyField(plasticCreep, new GUIContent("Plastic creep"));
});
ObiEditorUtils.DoToggleablePropertyGroup(aerodynamicsEnabled, new GUIContent("Aerodynamics", Resources.Load<Texture2D>("Icons/ObiAerodynamicConstraints Icon")),
() => {
EditorGUILayout.PropertyField(drag, new GUIContent("Drag"));
EditorGUILayout.PropertyField(lift, new GUIContent("Lift"));
});
if (GUI.changed)
serializedObject.ApplyModifiedProperties();

View File

@@ -2,12 +2,38 @@ using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
using System;
using UnityEditor.Overlays;
using UnityEngine.UIElements;
namespace Obi
{
[EditorTool("Obi Path Editor Tool",typeof(ObiRopeBase))]
public class ObiPathEditor : EditorTool
{
[Overlay(typeof(SceneView), "Obi Path Editor", "Obi Path Editor", "Obi Path Editor", true)]
[Icon("Assets/Obi/Editor/Resources/EditCurves.psd")]
class PathEditorOverlay : Overlay, ITransientOverlay
{
public static ObiPathEditor editor;
public override VisualElement CreatePanelContent()
{
var root = new VisualElement();
root.Add(new IMGUIContainer(editor.DrawToolPanel));
return root;
}
// Use the visible property to hide or show this instance from within the class.
public bool visible
{
get
{
return ToolManager.activeToolType == typeof(ObiPathEditor);
}
}
}
enum PathEditorTool
{
TranslatePoints,
@@ -64,6 +90,7 @@ namespace Obi
{
this.useOrientation = target is ObiRod;
selectedStatus = new bool[0];
PathEditorOverlay.editor = this;
}
public void ResizeCPArrays()
@@ -71,7 +98,6 @@ namespace Obi
Array.Resize(ref selectedStatus, path.ControlPointCount);
}
int windowId;
public override void OnToolGUI(EditorWindow window)
{
needsRepaint = false;
@@ -82,11 +108,7 @@ namespace Obi
ResizeCPArrays();
HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
// get a window ID:
if (Event.current.type != EventType.Used)
windowId = GUIUtility.GetControlID(FocusType.Passive);
HandleUtility.AddDefaultControl(GUIUtility.GetControlID("PathEditor".GetHashCode(), FocusType.Passive));
Matrix4x4 prevMatrix = Handles.matrix;
Handles.matrix = matrix;
@@ -98,9 +120,6 @@ namespace Obi
needsRepaint |= DrawControlPoint(i);
}
// Control point selection handle:
needsRepaint |= ObiPathHandles.SplineCPSelector(path, selectedStatus);
// Count selected and calculate average position:
selectionAverage = GetControlPointAverage(out lastSelected, out selectedCount);
@@ -110,10 +129,8 @@ namespace Obi
if (showThicknessHandles)
needsRepaint |= DoThicknessHandles(thicknessScale);
// Sceneview GUI:
Handles.BeginGUI();
GUILayout.Window(windowId, new Rect(10, 28, 0, 0), DrawUIWindow, "Path editor");
Handles.EndGUI();
// Control point selection handle:
needsRepaint |= ObiPathHandles.SplineCPSelector(path, selectedStatus);
Handles.matrix = prevMatrix;
@@ -545,7 +562,7 @@ namespace Obi
return false;
}
public void DrawUIWindow(int windowID)
public void DrawToolPanel()
{
DrawToolButtons();
@@ -1056,7 +1073,7 @@ namespace Obi
}
EditorGUI.BeginChangeCheck();
color = EditorGUILayout.ColorField("Color", color, GUILayout.MinWidth(94));
color = EditorGUILayout.ColorField(new GUIContent("Color"), color, true, true, true, GUILayout.MinWidth(94));
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck())
{
@@ -1153,7 +1170,7 @@ namespace Obi
for (int index = 0; index < 4; ++index)
{
int controlId = GUIUtility.GetControlID("ObiPathThicknessHandle".GetHashCode(), FocusType.Keyboard);
int controlId = GUIUtility.GetControlID("ObiPathThicknessHandle".GetHashCode(), FocusType.Passive);
Vector3 position1 = position + radius * vector3Array[index];
bool changed = GUI.changed;
GUI.changed = false;
@@ -1197,7 +1214,7 @@ namespace Obi
Vector2 currentPoint = HandleUtility.WorldToGUIPoint(path.m_Points.Evaluate(_p, p, p_, p__, i * step));
float mu;
float distance = Vector2.SqrMagnitude((Vector2)ObiUtils.ProjectPointLine(screenPoint, lastPoint, currentPoint, out mu) - screenPoint);
float distance = Vector2.SqrMagnitude((Vector2)ObiUtils.ProjectPointLine(lastPoint, currentPoint, screenPoint, out mu) - screenPoint);
if (distance < minDistance)
{

View File

@@ -28,27 +28,9 @@ namespace Obi
// select vertex on mouse click:
switch (Event.current.GetTypeForControl(controlID))
{
case EventType.MouseDown:
{
if ((Event.current.modifiers & EventModifiers.Control) == 0 &&
(HandleUtility.nearestControl != controlID || Event.current.button != 0)) break;
startPos = Event.current.mousePosition;
marquee.Set(0, 0, 0, 0);
// If the user is pressing shift, accumulate selection.
if ((Event.current.modifiers & EventModifiers.Shift) == 0 && (Event.current.modifiers & EventModifiers.Alt) == 0)
{
for (int i = 0; i < selectionStatus.Length; i++)
selectionStatus[i] = false;
}
// If the user is holding down control, dont allow selection of other objects and use marquee tool.
if ((Event.current.modifiers & EventModifiers.Control) != 0)
GUIUtility.hotControl = controlID;
case EventType.Layout:
case EventType.MouseMove:
float minSqrDistance = System.Single.MaxValue;
float sqrMinSelectionDistance = minSelectionDistance * minSelectionDistance;
@@ -59,50 +41,94 @@ namespace Obi
Vector2 pos = HandleUtility.WorldToGUIPoint(path.points[i].position);
// get distance from mouse position to particle position:
float sqrDistance = Vector2.SqrMagnitude(startPos - pos);
float sqrDistance = Vector2.SqrMagnitude(Event.current.mousePosition - pos);
// check if this control point is closer to the cursor that any previously considered point.
if (sqrDistance < sqrMinSelectionDistance && sqrDistance < minSqrDistance)
{
{
minSqrDistance = sqrDistance;
selectedCPIndex = i;
}
}
HandleUtility.AddControl(controlID, Mathf.Sqrt(minSqrDistance));
break;
if (selectedCPIndex >= 0)
{ // toggle particle selection status.
case EventType.MouseDown:
marquee.Set(0, 0, 0, 0);
startPos = Event.current.mousePosition;
selectionStatus[selectedCPIndex] = !selectionStatus[selectedCPIndex];
selectionStatusChanged = true;
if (Event.current.button == 0)
{
// Prevent spline deselection if we have selected a particle:
GUIUtility.hotControl = controlID;
Event.current.Use();
if (HandleUtility.nearestControl == controlID)
{
GUIUtility.hotControl = controlID;
// If the user is pressing shift or ctrl, accumulate selection.
if ((Event.current.modifiers & (EventModifiers.Shift | EventModifiers.Control)) == 0 && (Event.current.modifiers & EventModifiers.Alt) == 0)
{
for (int i = 0; i < selectionStatus.Length; i++)
selectionStatus[i] = false;
selectionStatusChanged = true;
}
minSqrDistance = System.Single.MaxValue;
sqrMinSelectionDistance = minSelectionDistance * minSelectionDistance;
for (int i = 0; i < path.ControlPointCount; i++)
{
// get particle position in gui space:
Vector2 pos = HandleUtility.WorldToGUIPoint(path.points[i].position);
// get distance from mouse position to particle position:
float sqrDistance = Vector2.SqrMagnitude(startPos - pos);
// check if this control point is closer to the cursor that any previously considered point.
if (sqrDistance < sqrMinSelectionDistance && sqrDistance < minSqrDistance)
{
minSqrDistance = sqrDistance;
selectedCPIndex = i;
}
}
if (selectedCPIndex >= 0)
{ // toggle particle selection status.
selectionStatus[selectedCPIndex] = !selectionStatus[selectedCPIndex];
selectionStatusChanged = true;
// Prevent spline deselection if we have selected a particle:
Event.current.Use();
}
}
else if ((Event.current.modifiers & (EventModifiers.Shift | EventModifiers.Control)) == 0 && (Event.current.modifiers & EventModifiers.Alt) == 0)
{
for (int i = 0; i < selectionStatus.Length; i++)
selectionStatus[i] = false;
selectionStatusChanged = true;
}
}
else if (Event.current.modifiers == EventModifiers.None)
{ // deselect all particles:
for (int i = 0; i < selectionStatus.Length; i++)
selectionStatus[i] = false;
selectionStatusChanged = true;
}
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == controlID)
if (Event.current.button == 0 && (Event.current.modifiers & EventModifiers.Alt) == 0)
{
currentPos = Event.current.mousePosition;
if (!dragging && Vector2.Distance(startPos, currentPos) > 5)
{
dragging = true;
}
else
if (dragging)
{
GUIUtility.hotControl = controlID;
Event.current.Use();
@@ -161,34 +187,6 @@ namespace Obi
break;
case EventType.Layout:
{
float minSqrDistance = System.Single.MaxValue;
float sqrMinSelectionDistance = minSelectionDistance * minSelectionDistance;
for (int i = 0; i < path.ControlPointCount; i++)
{
// get particle position in gui space:
Vector2 pos = HandleUtility.WorldToGUIPoint(path.points[i].position);
// get distance from mouse position to particle position:
float sqrDistance = Vector2.SqrMagnitude(Event.current.mousePosition - pos);
// check if this control point is closer to the cursor that any previously considered point.
if (sqrDistance < sqrMinSelectionDistance && sqrDistance < minSqrDistance)
{ //magic number 900 = 30*30, where 30 is min distance in pixels to select a particle.
minSqrDistance = sqrDistance;
}
}
HandleUtility.AddControl(controlID, Mathf.Sqrt(minSqrDistance));
}
break;
}
return selectionStatusChanged;

View File

@@ -17,6 +17,8 @@ namespace Obi
static void CreateObiRod(MenuCommand menuCommand)
{
GameObject go = new GameObject("Obi Rod", typeof(ObiRod), typeof(ObiRopeExtrudedRenderer));
var renderer = go.GetComponent<ObiRopeExtrudedRenderer>();
renderer.material = ObiEditorUtils.GetDefaultMaterial();
ObiEditorUtils.PlaceActorRoot(go, menuCommand);
}
@@ -26,7 +28,8 @@ namespace Obi
SerializedProperty collisionMaterial;
SerializedProperty selfCollisions;
SerializedProperty surfaceCollisions;
SerializedProperty surfaceCollisions;
SerializedProperty massScale;
SerializedProperty stretchShearConstraintsEnabled;
SerializedProperty stretchCompliance;
@@ -40,6 +43,10 @@ namespace Obi
SerializedProperty plasticYield;
SerializedProperty plasticCreep;
SerializedProperty aerodynamicsEnabled;
SerializedProperty drag;
SerializedProperty lift;
SerializedProperty chainConstraintsEnabled;
SerializedProperty tightness;
@@ -54,6 +61,7 @@ namespace Obi
collisionMaterial = serializedObject.FindProperty("m_CollisionMaterial");
selfCollisions = serializedObject.FindProperty("m_SelfCollisions");
surfaceCollisions = serializedObject.FindProperty("m_SurfaceCollisions");
massScale = serializedObject.FindProperty("m_MassScale");
stretchShearConstraintsEnabled = serializedObject.FindProperty("_stretchShearConstraintsEnabled");
stretchCompliance = serializedObject.FindProperty("_stretchCompliance");
@@ -67,6 +75,10 @@ namespace Obi
plasticYield = serializedObject.FindProperty("_plasticYield");
plasticCreep = serializedObject.FindProperty("_plasticCreep");
aerodynamicsEnabled = serializedObject.FindProperty("_aerodynamicsEnabled");
drag = serializedObject.FindProperty("_drag");
lift = serializedObject.FindProperty("_lift");
chainConstraintsEnabled = serializedObject.FindProperty("_chainConstraintsEnabled");
tightness = serializedObject.FindProperty("_tightness");
}
@@ -110,8 +122,30 @@ namespace Obi
using (new EditorGUI.DisabledScope(ToolManager.activeToolType == typeof(ObiPathEditor)))
{
GUILayout.BeginHorizontal();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(rodBlueprint, new GUIContent("Blueprint"));
if (actor.rodBlueprint == null)
{
if (GUILayout.Button("Create", EditorStyles.miniButton, GUILayout.MaxWidth(80)))
{
string path = EditorUtility.SaveFilePanel("Save blueprint", "Assets/", "RodBlueprint", "asset");
if (!string.IsNullOrEmpty(path))
{
path = FileUtil.GetProjectRelativePath(path);
ObiRodBlueprint asset = ScriptableObject.CreateInstance<ObiRodBlueprint>();
AssetDatabase.CreateAsset(asset, path);
AssetDatabase.SaveAssets();
actor.rodBlueprint = asset;
}
}
}
if (EditorGUI.EndChangeCheck())
{
foreach (var t in targets)
@@ -123,8 +157,12 @@ namespace Obi
foreach (var t in targets)
(t as ObiRod).AddToSolver();
}
GUILayout.EndHorizontal();
}
EditorGUILayout.PropertyField(massScale, new GUIContent("m_MassScale"));
DoEditButton();
EditorGUILayout.Space();
@@ -150,6 +188,12 @@ namespace Obi
EditorGUILayout.PropertyField(plasticCreep, new GUIContent("Plastic creep"));
});
ObiEditorUtils.DoToggleablePropertyGroup(aerodynamicsEnabled, new GUIContent("Aerodynamics", Resources.Load<Texture2D>("Icons/ObiAerodynamicConstraints Icon")),
() => {
EditorGUILayout.PropertyField(drag, new GUIContent("Drag"));
EditorGUILayout.PropertyField(lift, new GUIContent("Lift"));
});
ObiEditorUtils.DoToggleablePropertyGroup(chainConstraintsEnabled, new GUIContent("Chain Constraints", Resources.Load<Texture2D>("Icons/ObiChainConstraints Icon")),
() => {
EditorGUILayout.PropertyField(tightness, new GUIContent("Tightness"));

View File

@@ -15,8 +15,27 @@ namespace Obi{
public void OnEnable(){
renderer = (ObiRopeChainRenderer)target;
}
public override void OnInspectorGUI() {
[MenuItem("CONTEXT/ObiRopeChainRenderer/Bake mesh")]
static void Bake(MenuCommand command)
{
ObiRopeChainRenderer renderer = (ObiRopeChainRenderer)command.context;
if (renderer.actor.isLoaded)
{
var system = renderer.actor.solver.GetRenderSystem<ObiRopeChainRenderer>() as ObiChainRopeRenderSystem;
if (system != null)
{
var mesh = new Mesh();
system.BakeMesh(renderer, ref mesh, true);
ObiEditorUtils.SaveMesh(mesh, "Save chain mesh", "chain mesh");
GameObject.DestroyImmediate(mesh);
}
}
}
public override void OnInspectorGUI() {
serializedObject.UpdateIfRequiredOrScript();
@@ -25,12 +44,7 @@ namespace Obi{
// Apply changes to the serializedProperty
if (GUI.changed){
serializedObject.ApplyModifiedProperties();
renderer.ClearChainLinkInstances();
renderer.CreateChainLinkInstances(renderer.GetComponent<ObiRopeBase>());
renderer.UpdateRenderer(renderer.GetComponent<ObiRopeBase>());
serializedObject.ApplyModifiedProperties();
}
}

View File

@@ -65,17 +65,19 @@ namespace Obi
private static void DrawGizmos(ObiRopeCursor cursor, GizmoType gizmoType)
{
var rope = cursor.GetComponent<ObiRope>();
if (rope.solver != null)
if (rope.isLoaded)
{
Gizmos.color = new Color(1, 0.5f, 0, 0.75f);
Handles.matrix = rope.solver.transform.localToWorldMatrix;
Handles.color = new Color(1, 0.5f, 0.2f, 1);
// draw source particle:
int sourceIndex = cursor.sourceParticleIndex;
if (sourceIndex >= 0 && rope.IsParticleActive(rope.solver.particleToActor[sourceIndex].indexInActor))
{
Vector3 pos = rope.GetParticlePosition(sourceIndex);
Gizmos.DrawWireSphere(pos, HandleUtility.GetHandleSize(pos) * 0.4f);
Vector3 pos = rope.solver.positions[sourceIndex];
float size = HandleUtility.GetHandleSize(pos) * 0.15f;
Handles.SphereHandleCap(0, pos, Quaternion.identity, size, EventType.Repaint);
}
// draw cursor:
@@ -83,13 +85,12 @@ namespace Obi
if (element != null && element.particle1 != element.particle2)
{
Vector3 pos = rope.GetParticlePosition(cursor.direction ? element.particle1 : element.particle2);
Vector3 pos2 = rope.GetParticlePosition(cursor.direction ? element.particle2 : element.particle1);
Vector3 pos = rope.solver.positions[cursor.direction ? element.particle1 : element.particle2];
Vector3 pos2 = rope.solver.positions[cursor.direction ? element.particle2 : element.particle1];
Vector3 direction = pos2 - pos;
float size = HandleUtility.GetHandleSize(pos) * 0.4f;
Gizmos.matrix = Matrix4x4.TRS(pos, Quaternion.LookRotation(direction), Vector3.one * size);
DrawArrow();
float size = HandleUtility.GetHandleSize(pos) * 0.25f;
Handles.ConeHandleCap(0, pos + Vector3.Normalize(direction)*size*0.5f, Quaternion.LookRotation(direction), size, EventType.Repaint);
}
}
}

View File

@@ -1,11 +1,6 @@
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditorInternal;
using UnityEngine;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Obi
{
@@ -18,6 +13,8 @@ namespace Obi
static void CreateObiRope(MenuCommand menuCommand)
{
GameObject go = new GameObject("Obi Rope", typeof(ObiRope), typeof(ObiRopeExtrudedRenderer));
var renderer = go.GetComponent<ObiRopeExtrudedRenderer>();
renderer.material = ObiEditorUtils.GetDefaultMaterial();
ObiEditorUtils.PlaceActorRoot(go, menuCommand);
}
@@ -28,6 +25,7 @@ namespace Obi
SerializedProperty collisionMaterial;
SerializedProperty selfCollisions;
SerializedProperty surfaceCollisions;
SerializedProperty massScale;
SerializedProperty distanceConstraintsEnabled;
SerializedProperty stretchingScale;
@@ -40,6 +38,10 @@ namespace Obi
SerializedProperty plasticYield;
SerializedProperty plasticCreep;
SerializedProperty aerodynamicsEnabled;
SerializedProperty drag;
SerializedProperty lift;
SerializedProperty tearingEnabled;
SerializedProperty tearResistanceMultiplier;
SerializedProperty tearRate;
@@ -55,6 +57,7 @@ namespace Obi
collisionMaterial = serializedObject.FindProperty("m_CollisionMaterial");
selfCollisions = serializedObject.FindProperty("m_SelfCollisions");
surfaceCollisions = serializedObject.FindProperty("m_SurfaceCollisions");
massScale = serializedObject.FindProperty("m_MassScale");
distanceConstraintsEnabled = serializedObject.FindProperty("_distanceConstraintsEnabled");
stretchingScale = serializedObject.FindProperty("_stretchingScale");
@@ -67,6 +70,10 @@ namespace Obi
plasticYield = serializedObject.FindProperty("_plasticYield");
plasticCreep = serializedObject.FindProperty("_plasticCreep");
aerodynamicsEnabled = serializedObject.FindProperty("_aerodynamicsEnabled");
drag = serializedObject.FindProperty("_drag");
lift = serializedObject.FindProperty("_lift");
tearingEnabled = serializedObject.FindProperty("tearingEnabled");
tearResistanceMultiplier = serializedObject.FindProperty("tearResistanceMultiplier");
tearRate = serializedObject.FindProperty("tearRate");
@@ -112,8 +119,29 @@ namespace Obi
using (new EditorGUI.DisabledScope(ToolManager.activeToolType == typeof(ObiPathEditor)))
{
GUILayout.BeginHorizontal();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(ropeBlueprint, new GUIContent("Blueprint"));
if (actor.ropeBlueprint == null)
{
if (GUILayout.Button("Create", EditorStyles.miniButton, GUILayout.MaxWidth(80)))
{
string path = EditorUtility.SaveFilePanel("Save blueprint", "Assets/", "RopeBlueprint", "asset");
if (!string.IsNullOrEmpty(path))
{
path = FileUtil.GetProjectRelativePath(path);
ObiRopeBlueprint asset = ScriptableObject.CreateInstance<ObiRopeBlueprint>();
AssetDatabase.CreateAsset(asset, path);
AssetDatabase.SaveAssets();
actor.ropeBlueprint = asset;
}
}
}
if (EditorGUI.EndChangeCheck())
{
foreach (var t in targets)
@@ -125,8 +153,14 @@ namespace Obi
foreach (var t in targets)
(t as ObiRope).AddToSolver();
}
GUILayout.EndHorizontal();
}
GUI.enabled = !Application.isPlaying;
EditorGUILayout.PropertyField(massScale, new GUIContent("Mass scale"));
GUI.enabled = true;
DoEditButton();
EditorGUILayout.Space();
@@ -159,6 +193,11 @@ namespace Obi
EditorGUILayout.PropertyField(plasticCreep, new GUIContent("Plastic creep"));
});
ObiEditorUtils.DoToggleablePropertyGroup(aerodynamicsEnabled, new GUIContent("Aerodynamics", Resources.Load<Texture2D>("Icons/ObiAerodynamicConstraints Icon")),
() => {
EditorGUILayout.PropertyField(drag, new GUIContent("Drag"));
EditorGUILayout.PropertyField(lift, new GUIContent("Lift"));
});
if (GUI.changed)
serializedObject.ApplyModifiedProperties();

View File

@@ -16,22 +16,28 @@ namespace Obi{
renderer = (ObiRopeExtrudedRenderer)target;
}
private void BakeMesh()
[MenuItem("CONTEXT/ObiRopeExtrudedRenderer/Bake mesh")]
static void Bake(MenuCommand command)
{
if (renderer != null && renderer.extrudedMesh != null)
ObiRopeExtrudedRenderer renderer = (ObiRopeExtrudedRenderer)command.context;
if (renderer.actor.isLoaded)
{
ObiEditorUtils.SaveMesh(renderer.extrudedMesh, "Save extruded mesh", "rope mesh");
var system = renderer.actor.solver.GetRenderSystem<ObiRopeExtrudedRenderer>() as ObiExtrudedRopeRenderSystem;
if (system != null)
{
var mesh = new Mesh();
system.BakeMesh(renderer, ref mesh, true);
ObiEditorUtils.SaveMesh(mesh, "Save rope mesh", "rope mesh");
GameObject.DestroyImmediate(mesh);
}
}
}
public override void OnInspectorGUI() {
serializedObject.UpdateIfRequiredOrScript();
if (GUILayout.Button("BakeMesh"))
{
BakeMesh();
}
Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
@@ -40,8 +46,6 @@ namespace Obi{
serializedObject.ApplyModifiedProperties();
renderer.UpdateRenderer(renderer.GetComponent<ObiRopeBase>());
}
}

View File

@@ -27,7 +27,7 @@ namespace Obi{
serializedObject.ApplyModifiedProperties();
renderer.UpdateRenderer(null);
//renderer.UpdateRenderer(null);
}

View File

@@ -1,8 +1,5 @@
using UnityEditor;
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Obi{
@@ -11,28 +8,34 @@ namespace Obi{
{
ObiRopeMeshRenderer renderer;
public void OnEnable(){
renderer = (ObiRopeMeshRenderer)target;
}
private void BakeMesh()
[MenuItem("CONTEXT/ObiRopeMeshRenderer/Bake mesh")]
static void Bake(MenuCommand command)
{
if (renderer != null && renderer.deformedMesh != null)
ObiRopeMeshRenderer renderer = (ObiRopeMeshRenderer)command.context;
if (renderer.actor.isLoaded)
{
ObiEditorUtils.SaveMesh(renderer.deformedMesh, "Save deformed mesh", "rope mesh");
var system = renderer.actor.solver.GetRenderSystem<ObiRopeMeshRenderer>() as ObiMeshRopeRenderSystem;
if (system != null)
{
var mesh = new Mesh();
system.BakeMesh(renderer, ref mesh, true);
ObiEditorUtils.SaveMesh(mesh, "Save rope mesh", "rope mesh");
GameObject.DestroyImmediate(mesh);
}
}
}
public void OnEnable(){
renderer = (ObiRopeMeshRenderer)target;
}
public override void OnInspectorGUI() {
serializedObject.UpdateIfRequiredOrScript();
if (GUILayout.Button("BakeMesh"))
{
BakeMesh();
}
Editor.DrawPropertiesExcluding(serializedObject,"m_Script");
// Apply changes to the serializedProperty
@@ -40,8 +43,6 @@ namespace Obi{
serializedObject.ApplyModifiedProperties();
renderer.UpdateRenderer(renderer.GetComponent<ObiRopeBase>());
}
}

View File

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

View File

@@ -0,0 +1,169 @@
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
namespace Obi
{
[CustomEditor(typeof(ObiPinhole))]
public class ObiPinholeEditor : Editor
{
SerializedProperty targetTransform;
SerializedProperty position;
SerializedProperty limitRange;
SerializedProperty range;
SerializedProperty compliance;
SerializedProperty friction;
SerializedProperty motorSpeed;
SerializedProperty motorForce;
SerializedProperty clamp;
SerializedProperty breakThreshold;
ObiPinhole pinhole;
public void OnEnable()
{
pinhole = target as ObiPinhole;
targetTransform = serializedObject.FindProperty("m_Target");
position = serializedObject.FindProperty("m_Position");
limitRange = serializedObject.FindProperty("m_LimitRange");
range = serializedObject.FindProperty("m_Range");
friction = serializedObject.FindProperty("m_Friction");
motorSpeed = serializedObject.FindProperty("m_MotorSpeed");
motorForce = serializedObject.FindProperty("m_MotorForce");
compliance = serializedObject.FindProperty("m_Compliance");
clamp = serializedObject.FindProperty("m_ClampAtEnds");
breakThreshold = serializedObject.FindProperty("breakThreshold");
}
public override void OnInspectorGUI()
{
serializedObject.UpdateIfRequiredOrScript();
// warn about incorrect setups:
if (!targetTransform.hasMultipleDifferentValues)
{
var targetValue = targetTransform.objectReferenceValue as UnityEngine.Component;
if (targetValue != null)
{
var collider = targetValue.GetComponent<ObiColliderBase>();
if (collider == null)
{
EditorGUILayout.HelpBox("Pinholes require the target object to have a ObiCollider component. Please add one.", MessageType.Warning);
}
}
}
EditorGUI.BeginChangeCheck();
Transform trget = EditorGUILayout.ObjectField("Target", pinhole.target, typeof(Transform), true) as Transform;
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(pinhole, "Set target");
pinhole.target = trget;
PrefabUtility.RecordPrefabInstancePropertyModifications(pinhole);
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(position, new GUIContent("Position"));
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
pinhole.CalculateMu();
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(limitRange, new GUIContent("Limit Range"));
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
pinhole.CalculateRange();
}
if (limitRange.boolValue)
{
EditorGUI.indentLevel++;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(range, new GUIContent("Range"));
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
pinhole.CalculateRange();
}
EditorGUI.indentLevel--;
}
EditorGUILayout.PropertyField(clamp, new GUIContent("Clamp at ends"));
EditorGUILayout.PropertyField(friction, new GUIContent("Friction"));
EditorGUILayout.PropertyField(motorSpeed, new GUIContent("Motor Target Speed"));
EditorGUILayout.PropertyField(motorForce, new GUIContent("Motor Max Force"));
EditorGUILayout.PropertyField(compliance, new GUIContent("Compliance"));
EditorGUILayout.PropertyField(breakThreshold, new GUIContent("Break threshold"));
if (GUI.changed)
serializedObject.ApplyModifiedProperties();
}
[DrawGizmo(GizmoType.Selected)]
private static void DrawGizmos(ObiPinhole pinhole, GizmoType gizmoType)
{
var rope = pinhole.GetComponent<ObiRope>();
var ropeBlueprint = rope.sharedBlueprint as ObiRopeBlueprintBase;
if (rope.isLoaded && ropeBlueprint != null && ropeBlueprint.deformableEdges != null)
{
Handles.color = new Color(1, 0.5f, 0.2f, 1);
Handles.matrix = rope.solver.transform.localToWorldMatrix;
// draw limits:
if (pinhole.limitRange)
{
for (int i = pinhole.firstEdge.edgeIndex; i <= pinhole.lastEdge.edgeIndex; ++i)
{
if (i >= 0 && i < ropeBlueprint.deformableEdges.Length)
{
int p1 = ropeBlueprint.deformableEdges[i * 2];
int p2 = ropeBlueprint.deformableEdges[i * 2 + 1];
var pos1 = rope.solver.positions[rope.solverIndices[p1]];
var pos2 = rope.solver.positions[rope.solverIndices[p2]];
if (i == pinhole.firstEdge.edgeIndex)
{
pos1 = Vector4.Lerp(pos1, pos2, pinhole.firstEdge.coordinate);
Handles.DrawSolidDisc(pos1, pos2 - pos1, HandleUtility.GetHandleSize(pos1) * 0.05f);
}
if (i == pinhole.lastEdge.edgeIndex)
{
pos2 = Vector4.Lerp(pos1, pos2, pinhole.lastEdge.coordinate);
Handles.DrawSolidDisc(pos2, pos1 - pos2, HandleUtility.GetHandleSize(pos2) * 0.05f);
}
Handles.DrawLine(pos1, pos2, 2);
}
}
}
// draw source particle:
int edgeIndex = pinhole.edgeIndex;
if (edgeIndex >= 0 && edgeIndex < ropeBlueprint.deformableEdges.Length)
{
int p1 = ropeBlueprint.deformableEdges[edgeIndex * 2];
int p2 = ropeBlueprint.deformableEdges[edgeIndex * 2 + 1];
var pos1 = rope.solver.positions[rope.solverIndices[p1]];
var pos2 = rope.solver.positions[rope.solverIndices[p2]];
Vector4 pos = Vector4.Lerp(pos1, pos2, pinhole.edgeCoordinate);
Handles.DrawWireDisc(pos, pos1 - pos2, HandleUtility.GetHandleSize(pos) * 0.1f, 2);
}
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f58defb5faddb428ea91cd06eecd8729
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: