예제 #1
0
        private int AddParticles(int amount)
        {
            // get constraint batches:
            ObiDistanceConstraintBatch distanceBatch = rope.DistanceConstraints.GetFirstBatch();
            ObiBendConstraintBatch     bendingBatch  = rope.BendingConstraints.GetFirstBatch();

            amount = Mathf.Min(amount, rope.PooledParticles);

            // if no particles can be added, just return.
            if (amount == 0)
            {
                return(0);
            }

            // find current constraint and hot constraint:
            int constraint = rope.GetConstraintIndexAtNormalizedCoordinate(normalizedCoord);

            rope.DistanceConstraints.RemoveFromSolver(null);
            rope.BendingConstraints.RemoveFromSolver(null);

            // find indices of first N inactive particles. we'll need them to create new rope.
            // the first and last particle indices in this array will be the ones in the current constraint.
            int[] newParticleIndices = new int[amount + 2];
            for (int i = 0, j = 0; i < amount && j < rope.TotalParticles; ++j)
            {
                if (!rope.active[j])
                {
                    newParticleIndices[i + 1] = j;
                    rope.active[j]            = true;
                    rope.invMasses[j]         = 1.0f / ObiRope.DEFAULT_PARTICLE_MASS;
                    ++i;
                }
            }

            // TODO: closed curves have a different amount of bend constraints!

            Vector4[] zeroVelocity = new Vector4[] { Vector4.zero };
            Vector4[] refPosition1 = new Vector4[1];
            Vector4[] refPosition2 = new Vector4[1];

            if (direction)
            {
                // fill first and last indices of the new particles array with the ones in the current constraint:
                newParticleIndices[0] = distanceBatch.springIndices[constraint * 2];
                newParticleIndices[newParticleIndices.Length - 1] = distanceBatch.springIndices[constraint * 2 + 1];

                // update normalized coord:
                normalizedCoord = constraint / (float)(distanceBatch.ConstraintCount + amount);

                Oni.GetParticlePositions(rope.Solver.OniSolver, refPosition1, 1, rope.particleIndices[newParticleIndices[0]]);
                Oni.GetParticlePositions(rope.Solver.OniSolver, refPosition2, 1, rope.particleIndices[newParticleIndices[newParticleIndices.Length - 1]]);

                // update constraints:
                distanceBatch.SetParticleIndex(constraint, newParticleIndices[newParticleIndices.Length - 2], ObiDistanceConstraintBatch.DistanceIndexType.First, rope.Closed);
                bendingBatch.SetParticleIndex(constraint, newParticleIndices[newParticleIndices.Length - 2], ObiBendConstraintBatch.BendIndexType.First, rope.Closed);
                bendingBatch.SetParticleIndex(constraint - 1, newParticleIndices[1], ObiBendConstraintBatch.BendIndexType.Second, rope.Closed);

                // add constraints and particles:
                for (int i = 1; i < newParticleIndices.Length - 1; ++i)
                {
                    Vector4[] pos = new Vector4[] { refPosition1[0] + (refPosition2[0] - refPosition1[0]) * i / (float)(newParticleIndices.Length - 1) * 0.5f };
                    Oni.SetParticlePositions(rope.Solver.OniSolver, pos, 1, rope.particleIndices[newParticleIndices[i]]);
                    Oni.SetParticleVelocities(rope.Solver.OniSolver, zeroVelocity, 1, rope.particleIndices[newParticleIndices[i]]);

                    int newConstraintIndex = constraint + i - 1;
                    distanceBatch.InsertConstraint(newConstraintIndex, newParticleIndices[i - 1], newParticleIndices[i], rope.InterparticleDistance, 0, 0);
                    bendingBatch.InsertConstraint(newConstraintIndex, newParticleIndices[i - 1], newParticleIndices[i + 1], newParticleIndices[i], 0, 0, 0);
                }
            }
            else
            {
                // fill first and last indices of the new particles array with the ones in the current constraint:
                newParticleIndices[0] = distanceBatch.springIndices[constraint * 2 + 1];
                newParticleIndices[newParticleIndices.Length - 1] = distanceBatch.springIndices[constraint * 2];

                // update normalized coord:
                normalizedCoord = (constraint + amount) / (float)(distanceBatch.ConstraintCount + amount);

                Oni.GetParticlePositions(rope.Solver.OniSolver, refPosition1, 1, rope.particleIndices[newParticleIndices[0]]);
                Oni.GetParticlePositions(rope.Solver.OniSolver, refPosition2, 1, rope.particleIndices[newParticleIndices[newParticleIndices.Length - 1]]);

                // update constraints:
                distanceBatch.SetParticleIndex(constraint, newParticleIndices[newParticleIndices.Length - 2], ObiDistanceConstraintBatch.DistanceIndexType.Second, rope.Closed);
                bendingBatch.SetParticleIndex(constraint, newParticleIndices[1], ObiBendConstraintBatch.BendIndexType.First, rope.Closed);
                bendingBatch.SetParticleIndex(constraint - 1, newParticleIndices[newParticleIndices.Length - 2], ObiBendConstraintBatch.BendIndexType.Second, rope.Closed);

                // add constraints and particles:
                for (int i = 1; i < newParticleIndices.Length - 1; ++i)
                {
                    Vector4[] pos = new Vector4[] { refPosition1[0] + (refPosition2[0] - refPosition1[0]) * i / (float)(newParticleIndices.Length - 1) * 0.5f };
                    Oni.SetParticlePositions(rope.Solver.OniSolver, pos, 1, rope.particleIndices[newParticleIndices[i]]);
                    Oni.SetParticleVelocities(rope.Solver.OniSolver, zeroVelocity, 1, rope.particleIndices[newParticleIndices[i]]);

                    distanceBatch.InsertConstraint(constraint + 1, newParticleIndices[i], newParticleIndices[i - 1], rope.InterparticleDistance, 0, 0);
                    bendingBatch.InsertConstraint(constraint, newParticleIndices[i + 1], newParticleIndices[i - 1], newParticleIndices[i], 0, 0, 0);
                }
            }

            rope.DistanceConstraints.AddToSolver(null);
            rope.BendingConstraints.AddToSolver(null);
            rope.PushDataToSolver(ParticleData.ACTIVE_STATUS);

            rope.UsedParticles += amount;

            rope.RegenerateRestPositions();

            return(amount);
        }
예제 #2
0
        public override void OnInspectorGUI()
        {
            serializedObject.Update();

            GUI.enabled = rope.Initialized;
            EditorGUI.BeginChangeCheck();
            editMode = GUILayout.Toggle(editMode, new GUIContent("Edit particles", Resources.Load <Texture2D>("EditParticles")), "LargeButton");
            if (EditorGUI.EndChangeCheck())
            {
                SceneView.RepaintAll();
            }
            GUI.enabled = true;

            EditorGUILayout.LabelField("Status: " + (rope.Initialized ? "Initialized":"Not initialized"));

            GUI.enabled = (rope.ropePath != null && rope.Section != null);
            if (GUILayout.Button("Initialize"))
            {
                if (!rope.Initialized)
                {
                    CoroutineJob job = new CoroutineJob();
                    routine = EditorCoroutine.StartCoroutine(job.Start(rope.GeneratePhysicRepresentationForMesh()));
                    EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
                }
                else
                {
                    if (EditorUtility.DisplayDialog("Actor initialization", "Are you sure you want to re-initialize this actor?", "Ok", "Cancel"))
                    {
                        CoroutineJob job = new CoroutineJob();
                        routine = EditorCoroutine.StartCoroutine(job.Start(rope.GeneratePhysicRepresentationForMesh()));
                        EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
                    }
                }
            }
            GUI.enabled = true;

            GUI.enabled = rope.Initialized;
            if (GUILayout.Button("Set Rest State"))
            {
                Undo.RecordObject(rope, "Set rest state");
                rope.PullDataFromSolver(ParticleData.POSITIONS | ParticleData.VELOCITIES);
            }
            if (GUILayout.Button("Set Particles to Layer"))
            {
                if (EditorUtility.DisplayDialog("Particle phases", "This will reset all per-particle layer values to the GameObject layer. Are you sure?", "Ok", "Cancel"))
                {
                    Undo.RecordObject(rope, "Set particles to layer");
                    for (int i = 0; i < rope.phases.Length; i++)
                    {
                        rope.phases[i] = Oni.MakePhase(rope.gameObject.layer, rope.SelfCollisions?Oni.ParticlePhase.SelfCollide:0);
                    }
                    rope.PushDataToSolver(ParticleData.PHASES);
                }
            }
            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;
            }

            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();
            }
        }