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