public void OnEnable() { cloth = (ObiCloth)target; // In case the cloth has not been initialized yet, start the initialization routine. if (!cloth.Initialized && !cloth.Initializing){ CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(cloth.GeneratePhysicRepresentationForMesh())); } EditorApplication.update += Update; EditorApplication.playmodeStateChanged += OnPlayModeStateChanged; }
public override void OnInspectorGUI() { serializedObject.UpdateIfDirtyOrScript(); EditorGUI.BeginChangeCheck(); editMode = GUILayout.Toggle(editMode,new GUIContent("Edit particles",EditorGUIUtility.Load("EditParticles.psd") as Texture2D),"LargeButton"); if (EditorGUI.EndChangeCheck()){ SceneView.RepaintAll(); } EditorGUILayout.LabelField("Status: "+ (cloth.Initialized ? "Initialized":"Not initialized")); GUI.enabled = (cloth.sharedTopology != null); if (GUILayout.Button("Initialize")){ if (!cloth.Initialized){ CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(cloth.GeneratePhysicRepresentationForMesh())); }else{ if (EditorUtility.DisplayDialog("Actor initialization","Are you sure you want to re-initialize this actor?","Ok","Cancel")){ CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(cloth.GeneratePhysicRepresentationForMesh())); } } } GUI.enabled = true; if (GUILayout.Button("Set Rest State")){ cloth.PullDataFromSolver(new ObiSolverData(ObiSolverData.ParticleData.POSITIONS | ObiSolverData.ParticleData.VELOCITIES)); } if (cloth.sharedTopology == null){ EditorGUILayout.HelpBox("No ObiMeshConnectivity asset present.",MessageType.Info); } GUILayout.BeginHorizontal(); if (GUILayout.Button("Optimize")){ Undo.RecordObject(cloth, "Optimize"); cloth.Optimize(); EditorUtility.SetDirty(cloth); } if (GUILayout.Button("Unoptimize")){ Undo.RecordObject(cloth, "Unoptimize"); cloth.Unoptimize(); EditorUtility.SetDirty(cloth); } GUILayout.EndHorizontal(); Editor.DrawPropertiesExcluding(serializedObject,"m_Script"); // Progress bar: EditorCoroutine.ShowCoroutineProgressBar("Generating physical representation...",routine); // Apply changes to the serializedProperty if (GUI.changed){ serializedObject.ApplyModifiedProperties(); } }
void UpdateEditMode() { EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins); EditorGUILayout.PropertyField(barycentricWeight); EditorGUILayout.PropertyField(normalAlignmentWeight); EditorGUILayout.PropertyField(elevationWeight); EditorGUI.BeginChangeCheck(); paintMode = GUILayout.Toggle(paintMode, new GUIContent("Paint skin", Resources.Load <Texture2D>("PaintButton")), "LargeButton"); Tools.hidden = paintMode || subject == SubjectBeingEdited.Master; if (EditorGUI.EndChangeCheck()) { SceneView.RepaintAll(); } // Buttons: GUILayout.BeginHorizontal(); if (GUILayout.Button("Bind") && masterObject != null && slaveObject != null) { EditorUtility.SetDirty(target); CoroutineJob job = new CoroutineJob(); routine = job.Start(skinMap.Bind()); EditorCoroutine.ShowCoroutineProgressBar("Generating skinmap...", ref routine); EditorGUIUtility.ExitGUI(); } if (GUILayout.Button("Done")) { EditorApplication.delayCall += ExitSkinEditMode; } GUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); // skin channel selector: if (paintMode) { EditorGUILayout.Space(); GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle()); EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins); // Brush parameters: paintBrush.radius = EditorGUILayout.Slider("Brush size", paintBrush.radius, 0.0001f, 0.5f); paintBrush.innerRadius = 1; paintBrush.opacity = 1; EditorGUI.BeginChangeCheck(); if (paintBrush.brushMode.needsInputValue) { currentProperty.PropertyField(); } if (EditorGUI.EndChangeCheck()) { SceneView.RepaintAll(); } GUILayout.BeginHorizontal(); if (GUILayout.Button(new GUIContent("Fill"), EditorStyles.miniButtonLeft)) { if (subject == SubjectBeingEdited.Master) { skinMap.FillChannel(skinMap.m_MasterChannels, currentProperty.GetDefault()); } else { skinMap.FillChannel(skinMap.m_SlaveChannels, currentProperty.GetDefault()); } SceneView.RepaintAll(); } if (GUILayout.Button(new GUIContent("Clear"), EditorStyles.miniButtonMid)) { if (subject == SubjectBeingEdited.Master) { skinMap.ClearChannel(skinMap.m_MasterChannels, currentProperty.GetDefault()); } else { skinMap.ClearChannel(skinMap.m_SlaveChannels, currentProperty.GetDefault()); } SceneView.RepaintAll(); } if (GUILayout.Button(new GUIContent("Copy"), EditorStyles.miniButtonMid)) { targetSkinChannel = currentProperty.GetDefault(); } if (GUILayout.Button(new GUIContent("Paste"), EditorStyles.miniButtonRight)) { if (subject == SubjectBeingEdited.Master) { skinMap.CopyChannel(skinMap.m_MasterChannels, targetSkinChannel, currentProperty.GetDefault()); } else { skinMap.CopyChannel(skinMap.m_SlaveChannels, targetSkinChannel, currentProperty.GetDefault()); } SceneView.RepaintAll(); } GUILayout.EndHorizontal(); EditorGUILayout.EndVertical(); } EditorGUILayout.Space(); GUILayout.Box(GUIContent.none, ObiEditorUtils.GetSeparatorLineStyle()); EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Slave transform", EditorStyles.boldLabel); if (GUILayout.Button("Reset", EditorStyles.miniButton)) { skinMap.m_SlaveTransform.Reset(); } EditorGUILayout.EndHorizontal(); EditorGUILayout.PropertyField(serializedObject.FindProperty("m_SlaveTransform")); EditorGUILayout.EndVertical(); }
public override void OnInspectorGUI() { serializedObject.UpdateIfDirtyOrScript(); GUI.enabled = cloth.Initialized; EditorGUI.BeginChangeCheck(); editMode = GUILayout.Toggle(editMode, new GUIContent("Edit particles", EditorGUIUtility.Load("Obi/EditParticles.psd") as Texture2D), "LargeButton"); if (EditorGUI.EndChangeCheck()) { // show wireframe EditorUtility.SetSelectedWireframeHidden(cloth.GetComponent <Renderer>(), false); SceneView.RepaintAll(); } GUI.enabled = true; EditorGUILayout.LabelField("Status: " + (cloth.Initialized ? "Initialized":"Not initialized")); GUI.enabled = (cloth.SharedTopology != null); if (GUILayout.Button("Initialize")) { if (!cloth.Initialized) { CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(cloth.GeneratePhysicRepresentationForMesh())); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } else { if (EditorUtility.DisplayDialog("Actor initialization", "Are you sure you want to re-initialize this actor?", "Ok", "Cancel")) { CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(cloth.GeneratePhysicRepresentationForMesh())); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } } } GUI.enabled = true; if (cloth.SharedTopology == null) { EditorGUILayout.HelpBox("No ObiMeshTopology asset present.", MessageType.Info); } GUI.enabled = cloth.Initialized; if (GUILayout.Button("Set Rest State")) { cloth.PullDataFromSolver(ParticleData.POSITIONS | ParticleData.VELOCITIES); } GUILayout.BeginHorizontal(); if (GUILayout.Button("Optimize")) { Undo.RecordObject(cloth, "Optimize"); cloth.Optimize(); } if (GUILayout.Button("Unoptimize")) { Undo.RecordObject(cloth, "Unoptimize"); cloth.Unoptimize(); } GUILayout.EndHorizontal(); GUI.enabled = true; EditorGUI.BeginChangeCheck(); ObiSolver solver = EditorGUILayout.ObjectField("Solver", cloth.Solver, typeof(ObiSolver), true) as ObiSolver; if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(cloth, "Set solver"); cloth.Solver = solver; } EditorGUI.BeginChangeCheck(); ObiMeshTopology topology = EditorGUILayout.ObjectField("Shared Topology", cloth.SharedTopology, typeof(ObiMeshTopology), true) as ObiMeshTopology; if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(cloth, "Set topology"); cloth.SharedTopology = topology; } bool newSelfCollisions = EditorGUILayout.Toggle(new GUIContent("Self collisions", "Enabling this allows particles generated by this actor to interact with each other."), cloth.SelfCollisions); if (cloth.SelfCollisions != newSelfCollisions) { Undo.RecordObject(cloth, "Set self collisions"); cloth.SelfCollisions = newSelfCollisions; } bool newUpdateTangents = EditorGUILayout.Toggle(new GUIContent("Update tangents", "If enabled, tangent space will be updated after each simulation step. Enable this if your cloth uses normal maps."), cloth.UpdateTangents); if (cloth.UpdateTangents != newUpdateTangents) { Undo.RecordObject(cloth, "Set update tangents"); cloth.UpdateTangents = newUpdateTangents; } Oni.NormalsUpdate newNormalsUpdate = (Oni.NormalsUpdate)EditorGUILayout.EnumPopup(new GUIContent("Update normals", "If set to recalculate, smooth normals will be recalculated each step. If set to skin, the original mesh normals will be rotated based on surface orientation."), cloth.NormalsUpdate); if (cloth.NormalsUpdate != newNormalsUpdate) { Undo.RecordObject(cloth, "Set normals update"); cloth.NormalsUpdate = newNormalsUpdate; } Editor.DrawPropertiesExcluding(serializedObject, "m_Script"); // Progress bar: EditorCoroutine.ShowCoroutineProgressBar("Generating physical representation...", routine); // Apply changes to the serializedProperty if (GUI.changed) { serializedObject.ApplyModifiedProperties(); } }
/** * Draws a window with cloth info: */ void DrawUIWindow(int windowID) { previewVirtualParticles = GUILayout.Toggle(previewVirtualParticles,"Preview virtual particles"); previewSpatialGrid = GUILayout.Toggle(previewSpatialGrid,"Preview grid"); if (cloth.IsSkinned) previewSkin = GUILayout.Toggle(previewSkin,"Preview skin"); GUILayout.BeginHorizontal(); EditorGUI.showMixedValue = mixedMass; newMass = EditorGUILayout.FloatField(newMass); EditorGUI.showMixedValue = false; if (GUILayout.Button("Set Mass")){ selectionMass = newMass; foreach(int particleIndex in selectedParticles){ ObiClothParticle particle = cloth.particles[particleIndex]; particle.mass = selectionMass; } } if (GUILayout.Button(new GUIContent(EditorGUIUtility.Load("PinIcon.psd") as Texture2D,"Fix/unfix particles."),GUILayout.MaxHeight(18),GUILayout.MaxWidth(25))){ foreach(int particleIndex in selectedParticles){ ObiClothParticle particle = cloth.particles[particleIndex]; if (particle.w == 0){ particle.mass = 1; }else{ newMass = particle.mass = float.PositiveInfinity; particle.velocity = Vector3.zero; } } } GUILayout.EndHorizontal(); if (GUILayout.Button("Invert selection")){ List<ObiClothParticle> unselectedParticles = cloth.particles.FindAll(x => !selectedParticles.Contains(x.index)); selectedParticles.Clear(); foreach(ObiClothParticle p in unselectedParticles){ SelectParticle(p.index); } } GUILayout.BeginHorizontal(); GUI.enabled = !EditorApplication.isPlaying; if (GUILayout.Button(EditorGUIUtility.Load("RewindButton.psd") as Texture2D,GUILayout.MaxHeight(24))){ cloth.ResetGeometry(); accumulatedTime = 0; } if (GUILayout.Button(EditorGUIUtility.Load("StopButton.psd") as Texture2D,GUILayout.MaxHeight(24))){ isPlaying = false; } if (GUILayout.Button(EditorGUIUtility.Load("PlayButton.psd") as Texture2D,GUILayout.MaxHeight(24))){ lastFrameTime = Time.realtimeSinceStartup; isPlaying = true; } if (GUILayout.Button(EditorGUIUtility.Load("StepButton.psd") as Texture2D,GUILayout.MaxHeight(24))){ isPlaying = false; cloth.SimulateStep(Time.fixedDeltaTime); cloth.CommitResultsToMesh(); } GUI.enabled = true; GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Reset Cloth")){ accumulatedTime = 0; CoroutineJob job = new CoroutineJob(); job.asyncThreshold = 1000; routine = EditorCoroutine.StartCoroutine(job.Start(cloth.ResetAll())); } if (GUILayout.Button("Optimize")){ if (EditorUtility.DisplayDialog("Cloth optimization","About to remove fixed particles that do not contribute to the simulation. The only way to undo this is reset or recreate the cloth. Do you want to continue?","Ok","Cancel")) cloth.Optimize(); } GUILayout.EndHorizontal(); }
public override void OnInspectorGUI() { serializedObject.Update(); GUI.enabled = rope.Initialized; EditorGUI.BeginChangeCheck(); editMode = GUILayout.Toggle(editMode, new GUIContent("Edit particles", Resources.Load <Texture2D>("EditParticles")), "LargeButton"); if (EditorGUI.EndChangeCheck()) { SceneView.RepaintAll(); } GUI.enabled = true; EditorGUILayout.LabelField("Status: " + (rope.Initialized ? "Initialized":"Not initialized")); GUI.enabled = (rope.ropePath != null && rope.Section != null); if (GUILayout.Button("Initialize")) { if (!rope.Initialized) { CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(rope.GeneratePhysicRepresentationForMesh())); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } else { if (EditorUtility.DisplayDialog("Actor initialization", "Are you sure you want to re-initialize this actor?", "Ok", "Cancel")) { CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(rope.GeneratePhysicRepresentationForMesh())); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } } } GUI.enabled = true; GUI.enabled = rope.Initialized; if (GUILayout.Button("Set Rest State")) { Undo.RecordObject(rope, "Set rest state"); rope.PullDataFromSolver(ParticleData.POSITIONS | ParticleData.VELOCITIES); } GUI.enabled = true; if (rope.ropePath == null) { EditorGUILayout.HelpBox("Rope path spline is missing.", MessageType.Info); } if (rope.Section == null) { EditorGUILayout.HelpBox("Rope section is missing.", MessageType.Info); } EditorGUI.BeginChangeCheck(); ObiSolver solver = EditorGUILayout.ObjectField("Solver", rope.Solver, typeof(ObiSolver), true) as ObiSolver; if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(rope, "Set solver"); rope.Solver = solver; } EditorGUI.BeginChangeCheck(); ObiCollisionMaterial material = EditorGUILayout.ObjectField("Collision Material", rope.CollisionMaterial, typeof(ObiCollisionMaterial), false) as ObiCollisionMaterial; if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(rope, "Set collision material"); rope.CollisionMaterial = material; } bool newSelfCollisions = EditorGUILayout.Toggle(new GUIContent("Self collisions", "Enabling this allows particles generated by this actor to interact with each other."), rope.SelfCollisions); if (rope.SelfCollisions != newSelfCollisions) { Undo.RecordObject(rope, "Set self collisions"); rope.SelfCollisions = newSelfCollisions; } Editor.DrawPropertiesExcluding(serializedObject, "m_Script", "chainLinks"); bool newThicknessFromParticles = EditorGUILayout.Toggle(new GUIContent("Thickness from particles", "Enabling this will allow particle radius to influence rope thickness. Use it for variable-thickness ropes."), rope.ThicknessFromParticles); if (rope.ThicknessFromParticles != newThicknessFromParticles) { Undo.RecordObject(rope, "Set thickness from particles"); rope.ThicknessFromParticles = newThicknessFromParticles; } float newTwist = EditorGUILayout.FloatField(new GUIContent("Section twist", "Amount of twist applied to each section, in degrees."), rope.SectionTwist); if (rope.SectionTwist != newTwist) { Undo.RecordObject(rope, "Set section twist"); rope.SectionTwist = newTwist; } EditorGUILayout.Space(); EditorGUILayout.LabelField("Rendering", EditorStyles.boldLabel); ObiRope.RenderingMode newRenderMode = (ObiRope.RenderingMode)EditorGUILayout.EnumPopup(rope.RenderMode); if (rope.RenderMode != newRenderMode) { Undo.RecordObject(rope, "Set rope render mode"); rope.RenderMode = newRenderMode; } float newUVAnchor = EditorGUILayout.Slider(new GUIContent("UV anchor", "Normalized point along the rope where the V texture coordinate starts. Useful when changing rope length."), rope.UVAnchor, 0, 1); if (rope.UVAnchor != newUVAnchor) { Undo.RecordObject(rope, "Set rope uv anchor"); rope.UVAnchor = newUVAnchor; } // Render-mode specific stuff: if (rope.RenderMode != ObiRope.RenderingMode.Chain) { ObiRopeSection newSection = EditorGUILayout.ObjectField(new GUIContent("Section", "Section asset to be extruded along the rope path.") , rope.Section, typeof(ObiRopeSection), false) as ObiRopeSection; if (rope.Section != newSection) { Undo.RecordObject(rope, "Set rope section"); rope.Section = newSection; } float newThickness = EditorGUILayout.FloatField(new GUIContent("Section thickness scale", "Scales mesh thickness."), rope.SectionThicknessScale); if (rope.SectionThicknessScale != newThickness) { Undo.RecordObject(rope, "Set rope section thickness"); rope.SectionThicknessScale = newThickness; } uint newSmoothness = (uint)EditorGUILayout.IntSlider(new GUIContent("Smoothness", "Level of smoothing applied to the rope path."), Convert.ToInt32(rope.Smoothing), 0, 3); if (rope.Smoothing != newSmoothness) { Undo.RecordObject(rope, "Set smoothness"); rope.Smoothing = newSmoothness; } Vector2 newUVScale = EditorGUILayout.Vector2Field(new GUIContent("UV scale", "Scaling of the uv coordinates generated for the rope. The u coordinate wraps around the whole rope section, and the v spans the full length of the rope."), rope.UVScale); if (rope.UVScale != newUVScale) { Undo.RecordObject(rope, "Set rope uv scale"); rope.UVScale = newUVScale; } bool newNormalizeV = EditorGUILayout.Toggle(new GUIContent("Normalize V", "Scaling of the uv coordinates generated for the rope. The u coordinate wraps around the whole rope section, and the v spans the full length of the rope."), rope.NormalizeV); if (rope.NormalizeV != newNormalizeV) { Undo.RecordObject(rope, "Set normalize v"); rope.NormalizeV = newNormalizeV; } } else { Vector3 newLinkScale = EditorGUILayout.Vector3Field(new GUIContent("Link scale", "Scale applied to each chain link."), rope.LinkScale); if (rope.LinkScale != newLinkScale) { Undo.RecordObject(rope, "Set chain link scale"); rope.LinkScale = newLinkScale; } bool newRandomizeLinks = EditorGUILayout.Toggle(new GUIContent("Randomize links", "Toggling this on this causes each chain link to be selected at random from the set of provided links."), rope.RandomizeLinks); if (rope.RandomizeLinks != newRandomizeLinks) { Undo.RecordObject(rope, "Set randomize links"); rope.RandomizeLinks = newRandomizeLinks; } EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(chainLinks, true); if (EditorGUI.EndChangeCheck()) { // update the chain representation in response to a change in available link templates: serializedObject.ApplyModifiedProperties(); rope.GenerateProceduralChainLinks(); } } // Progress bar: EditorCoroutine.ShowCoroutineProgressBar("Generating physical representation...", routine); // Apply changes to the serializedProperty if (GUI.changed) { serializedObject.ApplyModifiedProperties(); } }
public override void OnInspectorGUI() { serializedObject.Update(); GUI.enabled = rope.Initialized; EditorGUI.BeginChangeCheck(); editMode = GUILayout.Toggle(editMode, new GUIContent("Edit particles", Resources.Load <Texture2D>("EditParticles")), "LargeButton"); if (EditorGUI.EndChangeCheck()) { SceneView.RepaintAll(); } GUI.enabled = true; EditorGUILayout.LabelField("Status: " + (rope.Initialized ? "Initialized":"Not initialized")); GUI.enabled = (rope.ropePath != null); if (GUILayout.Button("Initialize")) { if (!rope.Initialized) { EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); CoroutineJob job = new CoroutineJob(); routine = job.Start(rope.GeneratePhysicRepresentationForMesh()); EditorCoroutine.ShowCoroutineProgressBar("Generating physical representation...", ref routine); EditorGUIUtility.ExitGUI(); } else { if (EditorUtility.DisplayDialog("Actor initialization", "Are you sure you want to re-initialize this actor?", "Ok", "Cancel")) { EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); CoroutineJob job = new CoroutineJob(); routine = job.Start(rope.GeneratePhysicRepresentationForMesh()); EditorCoroutine.ShowCoroutineProgressBar("Generating physical representation...", ref routine); EditorGUIUtility.ExitGUI(); } } } GUI.enabled = true; GUI.enabled = rope.Initialized; if (GUILayout.Button("Set Rest State")) { Undo.RecordObject(rope, "Set rest state"); rope.PullDataFromSolver(ParticleData.POSITIONS | ParticleData.VELOCITIES); } GUI.enabled = true; if (rope.ropePath == null) { EditorGUILayout.HelpBox("Rope path spline is missing.", MessageType.Info); } Editor.DrawPropertiesExcluding(serializedObject, "m_Script", "chainLinks"); // Apply changes to the serializedProperty if (GUI.changed) { serializedObject.ApplyModifiedProperties(); } }
public IEnumerator Generate() { nodes.Clear(); if (mesh == null) yield break; vertices = mesh.vertices; int[] triangles = mesh.triangles; float size = Mathf.Max(mesh.bounds.size.x,mesh.bounds.size.y,mesh.bounds.size.z) + boundsPadding; Bounds bounds = new Bounds(mesh.bounds.center,Vector3.one*size); // Use the half-edge structure to generate angle-weighted normals: HalfEdge he = new HalfEdge(mesh); if (Application.isPlaying){ CoroutineJob.RunSynchronously(he.Generate()); //While playing, do this synchronously. We don't want to wait too much. }else{ CoroutineJob generateHalfEdge = new CoroutineJob(); generateHalfEdge.asyncThreshold = 2000; //If this takes more than 2 seconds in the editor, do it asynchronously. EditorCoroutine.StartCoroutine(generateHalfEdge.Start(he.Generate())); //Wait for the half-edge generation to complete. CoroutineJob.ProgressInfo progress = null; while(!generateHalfEdge.IsDone){ try{ progress = generateHalfEdge.Result as CoroutineJob.ProgressInfo; }catch(Exception e){ Debug.LogException(e); yield break; } yield return progress; } } //Calculate angle weighted normals, for correct inside/outside determination. Vector3[] normals = he.AngleWeightedNormals(); yield return new CoroutineJob.ProgressInfo("Building BIH...",0.1f); // Generate BIH to speed up NN triangle queries. bih = new BIH(); bih.Generate(bounds,vertices,normals,triangles,8,0.8f); // Breadth first construction: Queue<ADFNode> queue = new Queue<ADFNode>(); ADFNode root = new ADFNode(bounds); queue.Enqueue(root); nodes.Add(root); int counter = 0; while(queue.Count > 0) { ADFNode node = queue.Dequeue(); // Here provide an upper-bound estimation of remaining time. Note that in some cases (high maxDepth and high maxError) the process will probably finish sooner than predicted. if (counter % 10 == 0) yield return new CoroutineJob.ProgressInfo("Generating distance field level "+node.depth+"...",0.1f + (node.depth/(float)maxDepth)*0.9f); node.distances = new float[8]; if (highQualityGradient) node.gradients = new Vector3[8]; // Sample distance at the 8 node corners: for (int i = 0; i < 8; i++){ BIH.SurfaceInfo si = bih.DistanceToSurface(node.bounds.center + Vector3.Scale(node.bounds.extents,corners[i])); node.distances[i] = si.signedDistance; if (highQualityGradient) node.gradients[i] = si.vectorToSurface; } if (node.depth >= maxDepth) continue; // Measure distances at the 6 node faces, and the center of the node. float[] realDistances = new float[7]; for (int i = 0; i < 7; i++) realDistances[i] = bih.DistanceToSurface(node.bounds.center + Vector3.Scale(node.bounds.extents,errorSamples[i] * 0.5f)).signedDistance; // Get interpolated estimation of distance at the center of possible child nodes: float[] interpolatedDistances = new float[7]; for (int i = 0; i < 7; i++) interpolatedDistances[i] = node.SampleDistanceAt(node.bounds.center + Vector3.Scale(node.bounds.extents,errorSamples[i] * 0.5f)); // Calculate mean squared error between measured distances and interpolated ones: float mse = 0; for (int i = 0; i < 7; i++){ float d = realDistances[i] - interpolatedDistances[i]; mse += d*d; } mse /= 7f; // If error > threshold, subdivide the node. if (mse > maxError){ node.children = new int[8]; for (int i = 0; i < 8; i++){ // Calculate child bounds and create the node: Vector3 childCenter = node.bounds.center + Vector3.Scale(node.bounds.extents,corners[i] * 0.5f); Vector3 childSize = node.bounds.size*0.5f; ADFNode child = new ADFNode(new Bounds(childCenter,childSize)); child.depth = node.depth+1; // Set our children index. node.children[i] = nodes.Count; // Add it to nodes list and store it for evaluation. nodes.Add(child); queue.Enqueue(child); } } counter++; } // Get rid of octree. bih = null; }
public override void OnInspectorGUI() { serializedObject.Update(); GUI.enabled = bone.Initialized; EditorGUI.BeginChangeCheck(); editMode = GUILayout.Toggle(editMode, new GUIContent("Edit particles", Resources.Load <Texture2D>("EditParticles")), "LargeButton"); if (EditorGUI.EndChangeCheck()) { SceneView.RepaintAll(); } GUI.enabled = true; EditorGUILayout.LabelField("Status: " + (bone.Initialized ? "Initialized":"Not initialized")); if (GUILayout.Button("Initialize")) { if (!bone.Initialized) { CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(bone.GeneratePhysicRepresentationForMesh())); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } else { if (EditorUtility.DisplayDialog("Actor initialization", "Are you sure you want to re-initialize this actor?", "Ok", "Cancel")) { CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(bone.GeneratePhysicRepresentationForMesh())); EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); } } } EditorGUI.BeginChangeCheck(); ObiSolver solver = EditorGUILayout.ObjectField("Solver", bone.Solver, typeof(ObiSolver), true) as ObiSolver; if (EditorGUI.EndChangeCheck()) { Undo.RecordObject(bone, "Set solver"); bone.Solver = solver; } bool newSelfCollisions = EditorGUILayout.Toggle(new GUIContent("Self collisions", "Enabling this allows particles generated by this actor to interact with each other."), bone.SelfCollisions); if (bone.SelfCollisions != newSelfCollisions) { Undo.RecordObject(bone, "Set self collisions"); bone.SelfCollisions = newSelfCollisions; } Editor.DrawPropertiesExcluding(serializedObject, "m_Script", "chainLinks"); // Progress bar: EditorCoroutine.ShowCoroutineProgressBar("Generating physical representation...", routine); // Apply changes to the serializedProperty if (GUI.changed) { serializedObject.ApplyModifiedProperties(); } }
public override void OnInspectorGUI() { serializedObject.UpdateIfDirtyOrScript(); EditorGUI.BeginChangeCheck(); editMode = GUILayout.Toggle(editMode, new GUIContent("Edit particles", EditorGUIUtility.Load("EditParticles.psd") as Texture2D), "LargeButton"); if (EditorGUI.EndChangeCheck()) { SceneView.RepaintAll(); } EditorGUILayout.LabelField("Status: " + (cloth.Initialized ? "Initialized":"Not initialized")); GUI.enabled = (cloth.sharedTopology != null); if (GUILayout.Button("Initialize")) { if (!cloth.Initialized) { CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(cloth.GeneratePhysicRepresentationForMesh())); } else { if (EditorUtility.DisplayDialog("Actor initialization", "Are you sure you want to re-initialize this actor?", "Ok", "Cancel")) { CoroutineJob job = new CoroutineJob(); routine = EditorCoroutine.StartCoroutine(job.Start(cloth.GeneratePhysicRepresentationForMesh())); } } } GUI.enabled = true; if (GUILayout.Button("Set Rest State")) { cloth.PullDataFromSolver(new ObiSolverData(ObiSolverData.ParticleData.POSITIONS | ObiSolverData.ParticleData.VELOCITIES)); } if (cloth.sharedTopology == null) { EditorGUILayout.HelpBox("No ObiMeshConnectivity asset present.", MessageType.Info); } GUILayout.BeginHorizontal(); if (GUILayout.Button("Optimize")) { Undo.RecordObject(cloth, "Optimize"); cloth.Optimize(); EditorUtility.SetDirty(cloth); } if (GUILayout.Button("Unoptimize")) { Undo.RecordObject(cloth, "Unoptimize"); cloth.Unoptimize(); EditorUtility.SetDirty(cloth); } GUILayout.EndHorizontal(); Editor.DrawPropertiesExcluding(serializedObject, "m_Script"); // Progress bar: EditorCoroutine.ShowCoroutineProgressBar("Generating physical representation...", routine); // Apply changes to the serializedProperty if (GUI.changed) { serializedObject.ApplyModifiedProperties(); } }