Пример #1
0
        /// <summary>
        /// Cast a ray (in model space) against a mesh.
        /// </summary>
        /// <param name="InRay"></param>
        /// <param name="vertices"></param>
        /// <param name="triangles"></param>
        /// <param name="hit"></param>
        /// <param name="distance"></param>
        /// <param name="cullingMode"></param>
        /// <returns></returns>
        internal static bool MeshRaycast(Ray InRay, Vector3[] vertices, int[] triangles, out PolyRaycastHit hit, float distance = Mathf.Infinity, Culling cullingMode = Culling.Front)
        {
            Vector3 hitNormal = Vector3.zero;   // vars used in loop
            Vector3 vert0, vert1, vert2;
            Vector3 origin = InRay.origin, direction = InRay.direction;

            hit = new PolyRaycastHit(Mathf.Infinity,
                                     Vector3.zero,
                                     Vector3.zero,
                                     -1);

            /**
             * Iterate faces, testing for nearest hit to ray origin.
             */
            for (int CurTri = 0; CurTri < triangles.Length; CurTri += 3)
            {
                if (CurTri + 2 >= triangles.Length)
                {
                    continue;
                }
                if (triangles[CurTri + 2] >= vertices.Length)
                {
                    continue;
                }

                vert0 = vertices[triangles[CurTri + 0]];
                vert1 = vertices[triangles[CurTri + 1]];
                vert2 = vertices[triangles[CurTri + 2]];

                // Second pass, test intersection with triangle
                if (Math.RayIntersectsTriangle2(origin, direction, vert0, vert1, vert2, ref distance, ref hitNormal))
                {
                    if (distance < hit.distance)
                    {
                        hit.distance = distance;
                        hit.triangle = CurTri / 3;
                        hit.position = InRay.GetPoint(hit.distance);
                        hit.normal   = hitNormal;
                    }
                }
            }

            hit = new PolyRaycastHit(hit.distance,
                                     InRay.GetPoint(hit.distance),
                                     hitNormal,
                                     hit.triangle);

            return(hit.triangle > -1);
        }
        /// <summary>
        /// Calculates the per-vertex weight for each raycast hit and fills in brush target weights.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="settings"></param>
        /// <param name="tool"></param>
        /// <param name="bMode"></param>
        internal static void CalculateWeightedVertices(BrushTarget target, BrushSettings settings, BrushTool tool = BrushTool.None, BrushMode bMode = null)
        {
            if (target == null || settings == null)
            {
                return;
            }

            if (target.editableObject == null)
            {
                return;
            }

            bool  uniformScale = Math.VectorIsUniform(target.transform.lossyScale);
            float scale        = uniformScale ? 1f / target.transform.lossyScale.x : 1f;

            PolyMesh mesh = target.editableObject.visualMesh;

            Transform transform   = target.transform;
            int       vertexCount = mesh.vertexCount;

            Vector3[] vertices = mesh.vertices;

            if (!uniformScale)
            {
                // As we only increase size only when it's needed, always make sure to
                // use the vertexCount variable in loop statements and not the buffer length.
                if (s_WorldBuffer.Length < vertexCount)
                {
                    System.Array.Resize <Vector3>(ref s_WorldBuffer, vertexCount);
                }

                for (int i = 0; i < vertexCount; i++)
                {
                    s_WorldBuffer[i] = transform.TransformPoint(vertices[i]);
                }
                vertices = s_WorldBuffer;
            }

            AnimationCurve curve = settings.falloffCurve;
            float          radius = settings.radius * scale, falloff_mag = Mathf.Max((radius - radius * settings.falloff), 0.00001f);

            Vector3        hitPosition = Vector3.zero;
            PolyRaycastHit hit;

            if (tool == BrushTool.Texture && mesh.subMeshCount > 1)
            {
                var   mode           = bMode as BrushModeTexture;
                int[] submeshIndices = mesh.subMeshes[mode.m_CurrentMeshACIndex].indexes;

                for (int n = 0; n < target.raycastHits.Count; n++)
                {
                    hit = target.raycastHits[n];
                    hit.SetVertexCount(vertexCount);

                    for (int i = 0; i < vertexCount; i++)
                    {
                        hit.weights[i] = 0f;
                    }

                    hitPosition = uniformScale ? hit.position : transform.TransformPoint(hit.position);

                    for (int i = 0; i < submeshIndices.Length; i++)
                    {
                        int   currentIndex = submeshIndices[i];
                        float dist         = (hitPosition - vertices[currentIndex]).magnitude;
                        float delta        = radius - dist;

                        if (delta >= 0)
                        {
                            float weight = Mathf.Clamp(curve.Evaluate(1f - Mathf.Clamp(delta / falloff_mag, 0f, 1f)), 0f, 1f);

                            hit.weights[currentIndex] = weight;
                        }
                    }
                }
            }
            else
            {
                int[][] common = PolyMeshUtility.GetCommonVertices(mesh);

                Vector3 buf = Vector3.zero;

                for (int n = 0; n < target.raycastHits.Count; n++)
                {
                    hit = target.raycastHits[n];
                    hit.SetVertexCount(vertexCount);

                    hitPosition = uniformScale ? hit.position : transform.TransformPoint(hit.position);

                    for (int i = 0; i < common.Length; i++)
                    {
                        int[] commonItem       = common[i];
                        int   commonArrayCount = commonItem.Length;

                        Math.Subtract(vertices[commonItem[0]], hitPosition, ref buf);

                        float sqrDist = buf.sqrMagnitude;

                        if (sqrDist > radius * radius)
                        {
                            for (int j = 0; j < commonArrayCount; j++)
                            {
                                hit.weights[commonItem[j]] = 0f;
                            }
                        }
                        else
                        {
                            float weight = Mathf.Clamp(curve.Evaluate(1f - Mathf.Clamp((radius - Mathf.Sqrt(sqrDist)) / falloff_mag, 0f, 1f)), 0f, 1f);

                            for (int j = 0; j < commonArrayCount; j++)
                            {
                                hit.weights[commonItem[j]] = weight;
                            }
                        }
                    }
                }
            }

            target.GetAllWeights(true);
        }