public void RayIntersectsTriangle2() { //create a triangle Vector3 vert0 = new Vector3(0f, 0f, 0f); Vector3 vert1 = new Vector3(0.5f, 0f, 0.87f); Vector3 vert2 = new Vector3(1f, 0f, 0f); Vector3 origin = new Vector3(0.5f, 0.5f, 0.43f); Vector3 direction = Vector3.down; //result Vector3 hitNormal = Vector3.zero; float distance = 0f; //should intersects bool intersects = PolyMath.RayIntersectsTriangle2(origin, direction, vert0, vert1, vert2, ref distance, ref hitNormal); Assert.IsTrue(intersects); Assert.IsTrue(distance == 0.5f); //the hitnormal is not normalized, I don't know why (????) Assert.IsTrue(hitNormal.normalized == Vector3.up); //should not intersects direction = Vector3.up; intersects = PolyMath.RayIntersectsTriangle2(origin, direction, vert0, vert1, vert2, ref distance, ref hitNormal); Assert.IsFalse(intersects); //should not intersects origin = new Vector3(5f, 0.5f, 0f); direction = Vector3.down; intersects = PolyMath.RayIntersectsTriangle2(origin, direction, vert0, vert1, vert2, ref distance, ref hitNormal); Assert.IsFalse(intersects); }
public void WeightedAverage() { //null checks Assert.DoesNotThrow(() => { PolyMath.WeightedAverage(null, null, null); }); Vector3[] vertices = GetVerticesSample(); //create a list of indexes that will be used List <int> indexes = new List <int>() { 1, 2, 3, 4 }; //create a list of weights, size must be equal to the size of the vertices array float[] weights = new float[] { 0, 1, 1, 1, 1, 0 }; //the weights should not affect the result on this test Vector3 average = PolyMath.WeightedAverage(vertices, indexes, weights); Assert.IsTrue(average == new Vector3(0.5f, 0f, 0.5f)); //this time only the third corner of the square should be returned weights = new float[] { 0, 0, 0, 1, 0, 0 }; average = PolyMath.WeightedAverage(vertices, indexes, weights); Assert.IsTrue(average == new Vector3(1f, 0f, 1f)); //trying with weights higher than 1 weights = new float[] { 0, 0, 1, 3, 0, 0 }; average = PolyMath.WeightedAverage(vertices, indexes, weights); Assert.IsTrue(average == new Vector3(0.75f, 0f, 1f)); }
/// <inheritdoc /> public void Contour( IDualContourable <TVoxel, TSurfaceData> contourable, IMutableDivisibleMesh <NormalColorTextureVertex> meshBuilder) { IDualContourerContracts.Contour(contourable, meshBuilder); foreach (var projection in contourable.GetContourableProjections(this.contourDeterminer)) { Vector3 topLeftVertex, topRightVertex, botLeftVertex, botRightVertex; this.positioner.GenerateValues( projection, out topLeftVertex, out topRightVertex, out botLeftVertex, out botRightVertex); Vector3 normal; QuadDiagonal diagonal; if (projection.AbsoluteIndexOfOrigin.SumCoordinatesLong().IsEven()) { diagonal = QuadDiagonal.Ascending; normal = PolyMath.GetNormalizedAverage( PolyMath.GetSurfaceNormal(topLeftVertex, botLeftVertex, topRightVertex), PolyMath.GetSurfaceNormal(botLeftVertex, botRightVertex, topRightVertex)); } else { diagonal = QuadDiagonal.Descending; normal = PolyMath.GetNormalizedAverage( PolyMath.GetSurfaceNormal(topLeftVertex, botLeftVertex, botRightVertex), PolyMath.GetSurfaceNormal(topLeftVertex, botRightVertex, topRightVertex)); } projection.SurfaceData.Diagonal = diagonal; Color topLeftColor, topRightColor, botLeftColor, botRightColor; this.colorer.GenerateValues( projection, out topLeftColor, out topRightColor, out botLeftColor, out botRightColor); Vector2 topLeftTexture, topRightTexture, botLeftTexture, botRightTexture; this.texturer.GenerateValues( projection, out topLeftTexture, out topRightTexture, out botLeftTexture, out botRightTexture); meshBuilder.AddFlatQuad( topLeft: new NormalColorTextureVertex(topLeftVertex, normal, topLeftColor, topLeftTexture), topRight: new NormalColorTextureVertex(topRightVertex, normal, topRightColor, topRightTexture), bottomLeft: new NormalColorTextureVertex(botLeftVertex, normal, botLeftColor, botLeftTexture), bottomRight: new NormalColorTextureVertex(botRightVertex, normal, botRightColor, botRightTexture), diagonal: diagonal); } }
public void GenerateValues( IVoxelProjection <TVoxel, TSurfaceData> projection, out TValue topLeftValue, out TValue topRightValue, out TValue bottomLeftValue, out TValue bottomRightValue) { if (projection.SurfaceData.Diagonal == QuadDiagonal.Ascending) { projection.SurfaceData.SurfaceArea = PolyMath.GetArea( projection.SurfaceData.TopLeftVertex, projection.SurfaceData.BottomLeftVertex, projection.SurfaceData.TopRightVertex) + PolyMath.GetArea( projection.SurfaceData.BottomLeftVertex, projection.SurfaceData.BottomRightVertex, projection.SurfaceData.TopRightVertex); } else { projection.SurfaceData.SurfaceArea = PolyMath.GetArea( projection.SurfaceData.TopLeftVertex, projection.SurfaceData.BottomLeftVertex, projection.SurfaceData.BottomRightVertex) + PolyMath.GetArea( projection.SurfaceData.TopLeftVertex, projection.SurfaceData.BottomRightVertex, projection.SurfaceData.TopRightVertex); } if (projection.SurfaceData.SurfaceArea >= this.threshold) { this.aboveThresholdGenerator.GenerateValues( projection, out topLeftValue, out topRightValue, out bottomLeftValue, out bottomRightValue); } else { this.belowThresholdGenerator.GenerateValues( projection, out topLeftValue, out topRightValue, out bottomLeftValue, out bottomRightValue); } }
public void Average() { //null checks Assert.DoesNotThrow(() => { PolyMath.Average(null, null); }); Vector3[] vertices = GetVerticesSample(); //create a list of indexes that will be used List <int> indexes = new List <int>() { 1, 2, 3, 4 }; Vector3 average = PolyMath.Average(vertices, indexes); Assert.IsTrue(average == new Vector3(0.5f, 0f, 0.5f)); }
/// <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) { float hitDistance = Mathf.Infinity; Vector3 hitNormal = Vector3.zero; // vars used in loop Vector3 vert0, vert1, vert2; int hitFace = -1; Vector3 origin = InRay.origin, direction = InRay.direction; /** * 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]]; if (PolyMath.RayIntersectsTriangle2(origin, direction, vert0, vert1, vert2, ref distance, ref hitNormal)) { hitFace = CurTri / 3; hitDistance = distance; break; } } hit = new PolyRaycastHit(hitDistance, InRay.GetPoint(hitDistance), hitNormal, hitFace); return(hitFace > -1); }
internal override void OnBrushApply(BrushTarget target, BrushSettings settings) { if (!likelyToSupportVertexSculpt) { return; } int rayCount = target.raycastHits.Count; Vector3[] normals = (s_SmoothDirection == PolyDirection.BrushNormal) ? target.editableObject.editMesh.normals : null; Vector3 v, t, avg, dirVec = s_SmoothDirection.value.ToVector3(); Plane plane = new Plane(Vector3.up, Vector3.zero); PolyMesh mesh = target.editableObject.editMesh; int vertexCount = mesh.vertexCount; // don't use target.GetAllWeights because brush normal needs // to know which ray to use for normal for (int ri = 0; ri < rayCount; ri++) { PolyRaycastHit hit = target.raycastHits[ri]; if (hit.weights == null || hit.weights.Length < vertexCount) { continue; } for (int i = 0; i < commonVertexCount; i++) { int index = commonVertices[i][0]; if (hit.weights[index] < .0001f || (s_IgnoreOpenEdges && nonManifoldIndices.Contains(index))) { continue; } v = vertices[index]; if (s_SmoothDirection == PolyDirection.VertexNormal) { avg = PolyMath.Average(vertices, neighborLookup[index]); } else { avg = PolyMath.WeightedAverage(vertices, neighborLookup[index], hit.weights); if (s_SmoothDirection == PolyDirection.BrushNormal) { if (s_UseFirstNormalVector) { dirVec = brushNormalOnBeginApply[ri]; } else { dirVec = PolyMath.WeightedAverage(normals, neighborLookup[index], hit.weights).normalized; } } plane.SetNormalAndPosition(dirVec, avg); avg = v - dirVec * plane.GetDistanceToPoint(v); } t = Vector3.Lerp(v, avg, hit.weights[index]); List <int> indices = commonVertices[i]; Vector3 pos = v + (t - v) * settings.strength * SMOOTH_STRENGTH_MODIFIER; for (int n = 0; n < indices.Count; n++) { vertices[indices[n]] = pos; } } } mesh.vertices = vertices; if (tempComponent != null) { tempComponent.OnVerticesMoved(mesh); } base.OnBrushApply(target, settings); }
public Vector3 CalculateNormalWithPointsCollection(Vector3[] points) { return(PolyMath.Normal(points)); }
public Vector3 TestMathNormalWithThreePoints(Vector3 v0, Vector3 v1, Vector3 v2) { return(PolyMath.Normal(v0, v1, v2)); }
public void VectorIsUniform() { Assert.IsTrue(PolyMath.VectorIsUniform(Vector3.one)); Assert.IsFalse(PolyMath.VectorIsUniform(Vector3.right)); }
/// <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) { //null checks if (target == null || settings == null) { return; } if (target.editableObject == null) { return; } bool uniformScale = PolyMath.VectorIsUniform(target.transform.lossyScale); float scale = uniformScale ? 1f / target.transform.lossyScale.x : 1f; PolyMesh mesh = target.editableObject.visualMesh; if (tool == BrushTool.Texture && mesh.subMeshCount > 1) { var mode = bMode as BrushModeTexture; int[] submeshIndices = mesh.subMeshes[mode.currentMeshACIndex].indexes; //List<List<int>> common = PolyMeshUtility.GetCommonVertices(mesh); Transform transform = target.transform; int vertexCount = mesh.vertexCount; Vector3[] vertices = mesh.vertices; if (!uniformScale) { Vector3[] world = new Vector3[vertexCount]; for (int i = 0; i < vertexCount; i++) { world[i] = transform.TransformPoint(vertices[i]); } vertices = world; } 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; 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 { List <List <int> > common = PolyMeshUtility.GetCommonVertices(mesh); Transform transform = target.transform; int vertexCount = mesh.vertexCount; Vector3[] vertices = mesh.vertices; if (!uniformScale) { Vector3[] world = new Vector3[vertexCount]; for (int i = 0; i < vertexCount; i++) { world[i] = transform.TransformPoint(vertices[i]); } vertices = world; } 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; 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.Count; i++) { int commonArrayCount = common[i].Count; float sqrDist = (hitPosition - vertices[common[i][0]]).sqrMagnitude; if (sqrDist > radius * radius) { for (int j = 0; j < commonArrayCount; j++) { hit.weights[common[i][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[common[i][j]] = weight; } } } } } target.GetAllWeights(true); }