/// <summary> /// Non-allocating version of Ray / Triangle intersection. /// </summary> /// <param name="origin"></param> /// <param name="dir"></param> /// <param name="vert0"></param> /// <param name="vert1"></param> /// <param name="vert2"></param> /// <param name="distance"></param> /// <param name="normal"></param> /// <returns></returns> internal static bool RayIntersectsTriangle2(Vector3 origin, Vector3 dir, Vector3 vert0, Vector3 vert1, Vector3 vert2, out float distance, out Vector3 normal) { Math.Subtract(vert0, vert1, ref tv1); Math.Subtract(vert0, vert2, ref tv2); normal = Vector3.Cross(tv1, tv2); distance = 0f; // backface culling if (Vector3.Dot(dir, normal) > 0) { return(false); } Math.Cross(dir, tv2, ref tv4); float det = Vector3.Dot(tv1, tv4); if (det < Mathf.Epsilon) { return(false); } Math.Subtract(vert0, origin, ref tv3); float u = Vector3.Dot(tv3, tv4); if (u < 0f || u > det) { return(false); } Math.Cross(tv3, tv1, ref tv4); float v = Vector3.Dot(dir, tv4); if (v < 0f || u + v > det) { return(false); } distance = Vector3.Dot(tv2, tv4) * (1f / det); // no hit if point is behind the ray origin return(distance > 0f); }
/// <summary> /// Non-allocating version of Ray / Triangle intersection. /// </summary> /// <param name="origin"></param> /// <param name="dir"></param> /// <param name="vert0"></param> /// <param name="vert1"></param> /// <param name="vert2"></param> /// <param name="distance"></param> /// <param name="normal"></param> /// <returns></returns> internal static bool RayIntersectsTriangle2(Vector3 origin, Vector3 dir, Vector3 vert0, Vector3 vert1, Vector3 vert2, ref float distance, ref Vector3 normal) { Math.Subtract(vert0, vert1, ref tv1); Math.Subtract(vert0, vert2, ref tv2); Math.Cross(dir, tv2, ref tv4); float det = Vector3.Dot(tv1, tv4); if (det < Mathf.Epsilon) { return(false); } Math.Subtract(vert0, origin, ref tv3); float u = Vector3.Dot(tv3, tv4); if (u < 0f || u > det) { return(false); } Math.Cross(tv3, tv1, ref tv4); float v = Vector3.Dot(dir, tv4); if (v < 0f || u + v > det) { return(false); } distance = Vector3.Dot(tv2, tv4) * (1f / det); Math.Cross(tv1, tv2, ref normal); return(true); }
/// <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); }