/// <summary> /// Scales the brush by a local Vector3 scale from its pivot /// </summary> /// <param name="brush">The brush to be rescaled</param> /// <param name="rescaleValue">Local scale to apply</param> public static void Scale(PrimitiveBrush brush, Vector3 scaleValue) { Polygon[] polygons = brush.GetPolygons(); for (int i = 0; i < polygons.Length; i++) { Polygon polygon = polygons[i]; polygons[i].CalculatePlane(); Vector3 previousPlaneNormal = polygons[i].Plane.normal; int vertexCount = polygon.Vertices.Length; Vector3[] newPositions = new Vector3[vertexCount]; Vector2[] newUV = new Vector2[vertexCount]; for (int j = 0; j < vertexCount; j++) { newPositions[j] = polygon.Vertices[j].Position; newUV[j] = polygon.Vertices[j].UV; } for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; Vector3 newPosition = vertex.Position.Multiply(scaleValue); newPositions[j] = newPosition; newUV[j] = GeometryHelper.GetUVForPosition(polygon, newPosition); } // Apply all the changes to the polygon for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; vertex.Position = newPositions[j]; vertex.UV = newUV[j]; } // Polygon geometry has changed, inform the polygon that it needs to recalculate its cached plane polygons[i].CalculatePlane(); Vector3 newPlaneNormal = polygons[i].Plane.normal; // Find the rotation from the original polygon plane to the new polygon plane Quaternion normalRotation = Quaternion.FromToRotation(previousPlaneNormal, newPlaneNormal); // Rotate all the vertex normals by the new rotation for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; vertex.Normal = normalRotation * vertex.Normal; } } #if UNITY_EDITOR EditorHelper.SetDirty(brush); #endif brush.Invalidate(true); }
/// <summary> /// Generates the UV coordinates for a <see cref="Polygon"/> automatically. /// </summary> /// <param name="polygon">The polygon to be updated.</param> private void GenerateUvCoordinates(Polygon polygon) { foreach (Vertex vertex in polygon.Vertices) { vertex.UV = GeometryHelper.GetUVForPosition(polygon, vertex.Position); } }
public static Vector2 GetUVOffset(Polygon polygon) { Vertex vertex1; Vertex vertex2; Vertex vertex3; // Get three vertices which will reliably give us good UV information (i.e. not collinear) SurfaceUtility.GetPrimaryPolygonDescribers(polygon, out vertex1, out vertex2, out vertex3); Vector2 newUV = GeometryHelper.GetUVForPosition(vertex1.Position, vertex2.Position, vertex3.Position, vertex1.UV, vertex2.UV, vertex3.UV, polygon.GetCenterPoint()); return(newUV); }
public override void PerformWeld() { // New position for the vertices is their center Vector3 newPosition = Vector3.zero; for (int i = 0; i < sourceVertices.Count; i++) { newPosition += sourceVertices[i].Position; } newPosition /= sourceVertices.Count; // Update all the selected vertices UVs for (int i = 0; i < sourceVertices.Count; i++) { Polygon polygon = vertexPolygonMappings[sourceVertices[i]]; sourceVertices[i].UV = GeometryHelper.GetUVForPosition(polygon, newPosition); } // Update all the selected vertices to their new position for (int i = 0; i < sourceVertices.Count; i++) { sourceVertices[i].Position = newPosition; } }
public void SnapSelectedVertices(bool isAbsoluteGrid) { // So we know which polygons need to have their normals recalculated List <Polygon> affectedPolygons = new List <Polygon>(); foreach (PrimitiveBrush brush in targetBrushes) { Polygon[] polygons = brush.GetPolygons(); for (int i = 0; i < polygons.Length; i++) { Polygon polygon = polygons[i]; int vertexCount = polygon.Vertices.Length; Vector3[] newPositions = new Vector3[vertexCount]; Vector2[] newUV = new Vector2[vertexCount]; for (int j = 0; j < vertexCount; j++) { newPositions[j] = polygon.Vertices[j].Position; newUV[j] = polygon.Vertices[j].UV; } bool polygonAffected = false; for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; if (selectedVertices.ContainsKey(vertex)) { Vector3 newPosition = vertex.Position; float snapDistance = CurrentSettings.PositionSnapDistance; if (isAbsoluteGrid) { newPosition = brush.transform.TransformPoint(newPosition); } newPosition = MathHelper.RoundVector3(newPosition, snapDistance); if (isAbsoluteGrid) { newPosition = brush.transform.InverseTransformPoint(newPosition); } newPositions[j] = newPosition; newUV[j] = GeometryHelper.GetUVForPosition(polygon, newPosition); polygonAffected = true; } } if (polygonAffected) { affectedPolygons.Add(polygon); } // Apply all the changes to the polygon for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; vertex.Position = newPositions[j]; vertex.UV = newUV[j]; } polygon.CalculatePlane(); } } if (affectedPolygons.Count > 0) { for (int i = 0; i < affectedPolygons.Count; i++) { affectedPolygons[i].ResetVertexNormals(); } foreach (PrimitiveBrush brush in targetBrushes) { brush.Invalidate(true); brush.BreakTypeRelation(); } } }
public void TranslateSelectedVertices(Vector3 worldDelta) { // So we know which polygons need to have their normals recalculated List <Polygon> affectedPolygons = new List <Polygon>(); foreach (PrimitiveBrush brush in targetBrushes) { Polygon[] polygons = brush.GetPolygons(); Vector3 localDelta = brush.transform.InverseTransformDirection(worldDelta); for (int i = 0; i < polygons.Length; i++) { Polygon polygon = polygons[i]; int vertexCount = polygon.Vertices.Length; Vector3[] newPositions = new Vector3[vertexCount]; Vector2[] newUV = new Vector2[vertexCount]; for (int j = 0; j < vertexCount; j++) { newPositions[j] = polygon.Vertices[j].Position; newUV[j] = polygon.Vertices[j].UV; } bool polygonAffected = false; for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; if (selectedVertices.ContainsKey(vertex)) { Vector3 startPosition = startPositions[vertex]; Vector3 newPosition = vertex.Position + localDelta; Vector3 accumulatedDelta = newPosition - startPosition; if (CurrentSettings.PositionSnappingEnabled) { float snapDistance = CurrentSettings.PositionSnapDistance; // newPosition = targetBrush.transform.TransformPoint(newPosition); accumulatedDelta = MathHelper.RoundVector3(accumulatedDelta, snapDistance); // newPosition = targetBrush.transform.InverseTransformPoint(newPosition); } if (accumulatedDelta != Vector3.zero) { newPosition = startPosition + accumulatedDelta; newPositions[j] = newPosition; newUV[j] = GeometryHelper.GetUVForPosition(polygon, newPosition); polygonAffected = true; } } } if (polygonAffected) { affectedPolygons.Add(polygon); } // Apply all the changes to the polygon for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; vertex.Position = newPositions[j]; vertex.UV = newUV[j]; } polygon.CalculatePlane(); } } if (affectedPolygons.Count > 0) { for (int i = 0; i < affectedPolygons.Count; i++) { affectedPolygons[i].ResetVertexNormals(); } foreach (PrimitiveBrush brush in targetBrushes) { brush.Invalidate(true); brush.BreakTypeRelation(); } } }
public static void DisplacePolygons(Polygon[] polygons, float distance) { // Used for determining if two vertices are the same Polygon.VertexComparerEpsilon vertexComparer = new Polygon.VertexComparerEpsilon(); // Used for determining if two positions or normals are the same Polygon.Vector3ComparerEpsilon vectorComparer = new Polygon.Vector3ComparerEpsilon(); // Group overlapping positions and also track their normals List <List <Vertex> > groupedVertices = new List <List <Vertex> >(); List <List <Vector3> > groupedNormals = new List <List <Vector3> >(); // Maps back from a vertex to the polygon it came from, used for UV calculation Dictionary <Vertex, Polygon> vertexPolygonMappings = new Dictionary <Vertex, Polygon>(); for (int polygonIndex = 0; polygonIndex < polygons.Length; polygonIndex++) { Vertex[] vertices = polygons[polygonIndex].Vertices; // Group the selected vertices into clusters for (int vertexIndex = 0; vertexIndex < vertices.Length; vertexIndex++) { Vertex sourceVertex = vertices[vertexIndex]; vertexPolygonMappings[sourceVertex] = polygons[polygonIndex]; bool added = false; for (int groupIndex = 0; groupIndex < groupedVertices.Count; groupIndex++) { if (groupedVertices[groupIndex].Contains(sourceVertex, vertexComparer)) { groupedVertices[groupIndex].Add(sourceVertex); // Add the normal of the polygon if it hasn't already been added (this prevents issues with two polygons that are coplanar) if (!groupedNormals[groupIndex].Contains(polygons[polygonIndex].Plane.normal, vectorComparer)) { groupedNormals[groupIndex].Add(polygons[polygonIndex].Plane.normal); } added = true; break; } } if (!added) { groupedVertices.Add(new List <Vertex>() { sourceVertex }); groupedNormals.Add(new List <Vector3>() { polygons[polygonIndex].Plane.normal }); } } } List <List <Vector3> > groupedPositions = new List <List <Vector3> >(); List <List <Vector2> > groupedUV = new List <List <Vector2> >(); // Calculate the new positions and UVs, but don't assign them as they must be calculated in one go for (int i = 0; i < groupedVertices.Count; i++) { groupedPositions.Add(new List <Vector3>()); groupedUV.Add(new List <Vector2>()); for (int j = 0; j < groupedVertices[i].Count; j++) { Vector3 position = groupedVertices[i][j].Position; for (int k = 0; k < groupedNormals[i].Count; k++) { position += groupedNormals[i][k] * distance; } Polygon primaryPolygon = vertexPolygonMappings[groupedVertices[i][j]]; Vector2 uv = GeometryHelper.GetUVForPosition(primaryPolygon, position); groupedPositions[i].Add(position); groupedUV[i].Add(uv); } } // Apply the new positions and UVs now that they've all been calculated for (int i = 0; i < groupedVertices.Count; i++) { for (int j = 0; j < groupedVertices[i].Count; j++) { Vertex vertex = groupedVertices[i][j]; vertex.Position = groupedPositions[i][j]; vertex.UV = groupedUV[i][j]; } } // Polygon planes have moved, so recalculate them for (int polygonIndex = 0; polygonIndex < polygons.Length; polygonIndex++) { polygons[polygonIndex].CalculatePlane(); } }
/// <summary> /// Translates the specified vertices by a position delta (local to the brush) and updates the UVs /// </summary> /// <param name="brush">Brush from which the vertices belong.</param> /// <param name="specifiedVertices">Specified vertices to be translated.</param> /// <param name="localDelta">Local positional delta.</param> public static void TranslateSpecifiedVertices(Brush brush, List <Vertex> specifiedVertices, Vector3 localDelta) { Polygon.Vector3ComparerEpsilon positionComparer = new Polygon.Vector3ComparerEpsilon(); // Cache the positions as the position of vertices will change while in the for loop List <Vector3> specifiedPositions = specifiedVertices.Select(item => item.Position).ToList(); // So we know which polygons need to have their normals recalculated List <Polygon> affectedPolygons = new List <Polygon>(); Polygon[] polygons = brush.GetPolygons(); for (int i = 0; i < polygons.Length; i++) { Polygon polygon = polygons[i]; int vertexCount = polygon.Vertices.Length; Vector3[] newPositions = new Vector3[vertexCount]; Vector2[] newUV = new Vector2[vertexCount]; for (int j = 0; j < vertexCount; j++) { newPositions[j] = polygon.Vertices[j].Position; newUV[j] = polygon.Vertices[j].UV; } bool polygonAffected = false; for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; if (specifiedPositions.Contains(vertex.Position, positionComparer)) { Vector3 newPosition = vertex.Position + localDelta; newPositions[j] = newPosition; newUV[j] = GeometryHelper.GetUVForPosition(polygon, newPosition); polygonAffected = true; } } if (polygonAffected) { affectedPolygons.Add(polygon); } // Apply all the changes to the polygon for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; vertex.Position = newPositions[j]; vertex.UV = newUV[j]; } polygon.CalculatePlane(); } if (affectedPolygons.Count > 0) { for (int i = 0; i < affectedPolygons.Count; i++) { affectedPolygons[i].ResetVertexNormals(); } } }
public override void PerformWeld() { List <List <Vertex> > groupedVertices = new List <List <Vertex> >(); VertexComparerTolerance comparer = new VertexComparerTolerance(tolerance); // Group the selected vertices into clusters for (int sourceVertexIndex = 0; sourceVertexIndex < sourceVertices.Count; sourceVertexIndex++) { Vertex sourceVertex = sourceVertices[sourceVertexIndex]; bool added = false; for (int groupIndex = 0; groupIndex < groupedVertices.Count; groupIndex++) { if (groupedVertices[groupIndex].Contains(sourceVertex, comparer)) { groupedVertices[groupIndex].Add(sourceVertex); added = true; break; } } if (!added) { groupedVertices.Add(new List <Vertex>() { sourceVertex }); } } for (int groupIndex = 0; groupIndex < groupedVertices.Count; groupIndex++) { List <Vertex> vertices = groupedVertices[groupIndex]; // Ignoring any groups that only contain one vertex if (vertices.Count > 1) { // New position for the vertices is their center Vector3 newPosition = Vector3.zero; for (int vertexIndex = 0; vertexIndex < vertices.Count; vertexIndex++) { newPosition += vertices[vertexIndex].Position; } newPosition /= vertices.Count; // Update all the selected vertices UVs for (int vertexIndex = 0; vertexIndex < vertices.Count; vertexIndex++) { Polygon polygon = vertexPolygonMappings[vertices[vertexIndex]]; vertices[vertexIndex].UV = GeometryHelper.GetUVForPosition(polygon, newPosition); } // Update all the selected vertices to their new position for (int vertexIndex = 0; vertexIndex < vertices.Count; vertexIndex++) { vertices[vertexIndex].Position = newPosition; } } } }
private void CreateBrush(List <Vector3> positions) { Polygon sourcePolygon = PolygonFactory.ConstructPolygon(positions, true); // Early out if it wasn't possible to create the polygon if (sourcePolygon == null) { return; } if (activePolygon != null) { for (int i = 0; i < sourcePolygon.Vertices.Length; i++) { Vector2 newUV = GeometryHelper.GetUVForPosition(activePolygon, sourcePolygon.Vertices[i].Position); sourcePolygon.Vertices[i].UV = newUV; } } Vector3 planeNormal = GetActivePlane().normal; // Debug.Log(Vector3.Dot(sourcePolygon.Plane.normal, planeNormal)); // Flip the polygon if the winding order is wrong if (Vector3.Dot(sourcePolygon.Plane.normal, planeNormal) < 0) { sourcePolygon.Flip(); // Need to flip the UVs across the U (X) direction for (int i = 0; i < sourcePolygon.Vertices.Length; i++) { Vector2 uv = sourcePolygon.Vertices[i].UV; uv.x = 1 - uv.x; sourcePolygon.Vertices[i].UV = uv; } } float extrusionDistance = 1; Vector3 positionOffset = Vector3.zero; if (selectingHeight) { extrusionDistance = prismHeight; } else { if (activePolygon != null && activeBrush != null) { extrusionDistance = activeBrush.CalculateExtentsInAxis(planeNormal); } else { Brush lastSelectedBrush = csgModel.LastSelectedBrush; if (lastSelectedBrush != null) { Bounds lastSelectedBrushBounds = lastSelectedBrush.GetBoundsTransformed(); for (int i = 0; i < 3; i++) { if (!planeNormal[i].EqualsWithEpsilon(0)) { if (lastSelectedBrushBounds.size[i] != 0) { extrusionDistance = lastSelectedBrushBounds.size[i]; if (planeNormal[i] > 0) { positionOffset[i] = lastSelectedBrushBounds.center[i] - lastSelectedBrushBounds.extents[i]; } else { positionOffset[i] = lastSelectedBrushBounds.center[i] + lastSelectedBrushBounds.extents[i]; } } } } } } // Subtractions should go through if (csgMode == CSGMode.Subtract) { sourcePolygon.Flip(); } } Quaternion rotation; Polygon[] polygons; SurfaceUtility.ExtrudePolygon(sourcePolygon, extrusionDistance, out polygons, out rotation); GameObject newObject = csgModel.CreateCustomBrush(polygons); PrimitiveBrush newBrush = newObject.GetComponent <PrimitiveBrush>(); newObject.transform.rotation = rotation; newObject.transform.position += positionOffset; if (activePolygon != null && activePolygon.Material != csgModel.GetDefaultMaterial()) { for (int i = 0; i < polygons.Length; i++) { polygons[i].Material = activePolygon.Material; } } // Finally give the new brush the other set of polygons newBrush.SetPolygons(polygons, true); newBrush.Mode = csgMode; newBrush.ResetPivot(); // Use this brush as the basis for drawing the next brush csgModel.SetLastSelectedBrush(newBrush); Undo.RegisterCreatedObjectUndo(newObject, "Draw Brush"); }
public override void Invalidate(bool polygonsChanged) { base.Invalidate(polygonsChanged); //////////////////////////////////////////////////////////////////// // a little hack to detect the user manually resizing the bounds. // // we use this to automatically add steps for barnaby. // // it's probably good to build a more 'official' way to detect // // user scaling events in compound brushes sometime. // if (m_LastKnownExtents != localBounds.extents) // { // // undo any position movement. // transform.localPosition = m_LastKnownPosition; // // user is trying to scale up. // if (localBounds.extents.y > m_LastKnownExtents.y) // { // numSteps += 1; // m_LastKnownExtents = localBounds.extents; // Invalidate(true); // recusion! <3 // return; // } // // user is trying to scale down. // if (localBounds.extents.y < m_LastKnownExtents.y) // { // numSteps -= 1; // if (numSteps < 1) { numSteps = 1; // } m_LastKnownExtents = localBounds.extents; // Invalidate(true); // recusion! <3 // return; // } // } // //////////////////////////////////////////////////////////////////// // local variables List <Vector3> vertexPositions = new List <Vector3>(); Plane plane; Vector3 rotateStep = new Vector3(); Vector3 vertex = new Vector3(), newVertex = new Vector3(); float adjustment; int innerStart, outerStart, bottomInnerStart, bottomOuterStart; // begin rotateStep.z = angleOfCurve / numSteps; if (counterClockwise) { rotateStep.z *= -1; } // generate the inner curve points. innerStart = vertexPositions.Count; vertex.x = innerRadius; for (int x = 0; x < (numSteps + 1); x++) { if (x == 0) { adjustment = addToFirstStep; } else { adjustment = 0; } newVertex = Quaternion.Euler(rotateStep * x) * vertex; vertexPositions.Add(new Vector3(newVertex.x, vertex.z - adjustment, newVertex.y)); vertex.z += stepHeight; vertexPositions.Add(new Vector3(newVertex.x, vertex.z, newVertex.y)); } // generate the outer curve points. outerStart = vertexPositions.Count; vertex.x = innerRadius + stepWidth; vertex.z = 0; for (int x = 0; x < (numSteps + 1); x++) { if (x == 0) { adjustment = addToFirstStep; } else { adjustment = 0; } newVertex = Quaternion.Euler(rotateStep * x) * vertex; vertexPositions.Add(new Vector3(newVertex.x, vertex.z - adjustment, newVertex.y)); vertex.z += stepHeight; vertexPositions.Add(new Vector3(newVertex.x, vertex.z, newVertex.y)); } // generate the bottom inner curve points. bottomInnerStart = vertexPositions.Count; vertex.x = innerRadius; vertex.z = 0; for (int x = 0; x < (numSteps + 1); x++) { newVertex = Quaternion.Euler(rotateStep * x) * vertex; vertexPositions.Add(new Vector3(newVertex.x, vertex.z - addToFirstStep, newVertex.y)); } // generate the bottom outer curve points. bottomOuterStart = vertexPositions.Count; vertex.x = innerRadius + stepWidth; for (int x = 0; x < (numSteps + 1); x++) { newVertex = Quaternion.Euler(rotateStep * x) * vertex; vertexPositions.Add(new Vector3(newVertex.x, vertex.z - addToFirstStep, newVertex.y)); } // vertex indices to easily flip faces for the counter clockwise mode. int index0 = 0; int index1 = 1; int index2 = 2; int index3 = 3; // flip faces if counter clockwise mode is enabled. if (counterClockwise) { index0 = 2; index1 = 1; index2 = 0; index3 = 3; } // we calculate the bounds of the output csg. Bounds csgBounds = new Bounds(); // iterate through the brushes we received: int brushCount = BrushCount; for (int i = 0; i < brushCount; i++) { // copy our csg information to our child brushes. generatedBrushes[i].Mode = this.Mode; generatedBrushes[i].IsNoCSG = this.IsNoCSG; generatedBrushes[i].IsVisible = this.IsVisible; generatedBrushes[i].HasCollision = this.HasCollision; // retrieve the polygons from the current cube brush. Polygon[] polygons = generatedBrushes[i].GetPolygons(); // +-----------------------------------------------------+ // | Cube Polygons | // +--------+--------+--------+--------+--------+--------+ // | Poly:0 | Poly:1 | Poly:2 | Poly:3 | Poly:4 | Poly:5 | // +-----------------------------------------------------+ // | Back | Left | Right | Front | Bottom | Top | // +--------+--------+--------+--------+--------+--------+ // retrieve the vertices of the top polygon. Vertex[] vertices = polygons[5].Vertices; // step top. vertices[index0].Position = vertexPositions[outerStart + (i * 2) + 2]; vertices[index1].Position = vertexPositions[outerStart + (i * 2) + 1]; vertices[index2].Position = vertexPositions[innerStart + (i * 2) + 1]; vertices[index3].Position = vertexPositions[innerStart + (i * 2) + 2]; // update uv coordinates to prevent distortions using barnaby's genius utilities. vertices[index0].UV = GeometryHelper.GetUVForPosition(polygons[5], vertexPositions[outerStart + (i * 2) + 2]); vertices[index1].UV = GeometryHelper.GetUVForPosition(polygons[5], vertexPositions[outerStart + (i * 2) + 1]); vertices[index2].UV = GeometryHelper.GetUVForPosition(polygons[5], vertexPositions[innerStart + (i * 2) + 1]); vertices[index3].UV = GeometryHelper.GetUVForPosition(polygons[5], vertexPositions[innerStart + (i * 2) + 2]); // retrieve the vertices of the front polygon. vertices = polygons[3].Vertices; // step front. vertices[index0].Position = vertexPositions[outerStart + (i * 2) + 1]; vertices[index1].Position = vertexPositions[bottomOuterStart + i]; vertices[index2].Position = vertexPositions[bottomInnerStart + i]; vertices[index3].Position = vertexPositions[innerStart + (i * 2) + 1]; // calculate a normal using a virtual plane. plane = new Plane(vertices[index1].Position, vertices[index2].Position, vertices[index3].Position); vertices[index0].Normal = plane.normal; vertices[index1].Normal = plane.normal; vertices[index2].Normal = plane.normal; vertices[index3].Normal = plane.normal; // retrieve the vertices of the left polygon. vertices = polygons[1].Vertices; // inner curve. vertices[index0].Position = vertexPositions[bottomInnerStart + i + 1]; vertices[index1].Position = vertexPositions[innerStart + (i * 2) + 2]; vertices[index2].Position = vertexPositions[innerStart + (i * 2) + 1]; vertices[index3].Position = vertexPositions[bottomInnerStart + i]; // calculate a normal using a virtual plane. plane = new Plane(vertices[index1].Position, vertices[index2].Position, vertices[index3].Position); vertices[index0].Normal = plane.normal; vertices[index1].Normal = plane.normal; vertices[index2].Normal = plane.normal; vertices[index3].Normal = plane.normal; // retrieve the vertices of the right polygon. vertices = polygons[2].Vertices; // outer curve. vertices[index0].Position = vertexPositions[outerStart + (i * 2) + 2]; vertices[index1].Position = vertexPositions[bottomOuterStart + i + 1]; vertices[index2].Position = vertexPositions[bottomOuterStart + i]; vertices[index3].Position = vertexPositions[outerStart + (i * 2) + 1]; // calculate a normal using a virtual plane. plane = new Plane(vertices[index1].Position, vertices[index2].Position, vertices[index3].Position); vertices[index0].Normal = plane.normal; vertices[index1].Normal = plane.normal; vertices[index2].Normal = plane.normal; vertices[index3].Normal = plane.normal; // retrieve the vertices of the bottom polygon. vertices = polygons[4].Vertices; // bottom. vertices[index0].Position = vertexPositions[bottomOuterStart + i]; vertices[index1].Position = vertexPositions[bottomOuterStart + i + 1]; vertices[index2].Position = vertexPositions[bottomInnerStart + i + 1]; vertices[index3].Position = vertexPositions[bottomInnerStart + i]; // update uv coordinates to prevent distortions using barnaby's genius utilities. vertices[index0].UV = GeometryHelper.GetUVForPosition(polygons[4], vertexPositions[bottomOuterStart + i]); vertices[index1].UV = GeometryHelper.GetUVForPosition(polygons[4], vertexPositions[bottomOuterStart + i + 1]); vertices[index2].UV = GeometryHelper.GetUVForPosition(polygons[4], vertexPositions[bottomInnerStart + i + 1]); vertices[index3].UV = GeometryHelper.GetUVForPosition(polygons[4], vertexPositions[bottomInnerStart + i]); // retrieve the vertices of the back polygon. vertices = polygons[0].Vertices; // back panel. vertices[index0].Position = vertexPositions[bottomOuterStart + i + 1]; vertices[index1].Position = vertexPositions[outerStart + (i * 2) + 2]; vertices[index2].Position = vertexPositions[innerStart + (i * 2) + 2]; vertices[index3].Position = vertexPositions[bottomInnerStart + i + 1]; // calculate a normal using a virtual plane. plane = new Plane(vertices[index1].Position, vertices[index2].Position, vertices[index3].Position); vertices[index0].Normal = plane.normal; vertices[index1].Normal = plane.normal; vertices[index2].Normal = plane.normal; vertices[index3].Normal = plane.normal; generatedBrushes[i].Invalidate(true); csgBounds.Encapsulate(generatedBrushes[i].GetBounds()); } // apply the generated csg bounds. localBounds = csgBounds; m_LastKnownExtents = localBounds.extents; m_LastKnownPosition = transform.localPosition; }
public void TranslateSelectedVertices(Vector3 worldDelta) { foreach (PrimitiveBrush brush in targetBrushes) { bool anyAffected = false; Polygon[] polygons = brush.GetPolygons(); Vector3 localDelta = brush.transform.InverseTransformDirection(worldDelta); for (int i = 0; i < polygons.Length; i++) { Polygon polygon = polygons[i]; polygon.CalculatePlane(); Vector3 previousPlaneNormal = polygons[i].Plane.normal; int vertexCount = polygon.Vertices.Length; Vector3[] newPositions = new Vector3[vertexCount]; Vector2[] newUV = new Vector2[vertexCount]; for (int j = 0; j < vertexCount; j++) { newPositions[j] = polygon.Vertices[j].Position; newUV[j] = polygon.Vertices[j].UV; } bool polygonAffected = false; for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; if (selectedVertices.ContainsKey(vertex)) { Vector3 startPosition = startPositions[vertex]; Vector3 newPosition = vertex.Position + localDelta; Vector3 accumulatedDelta = newPosition - startPosition; if (CurrentSettings.PositionSnappingEnabled) { float snapDistance = CurrentSettings.PositionSnapDistance; // newPosition = targetBrush.transform.TransformPoint(newPosition); accumulatedDelta = MathHelper.RoundVector3(accumulatedDelta, snapDistance); // newPosition = targetBrush.transform.InverseTransformPoint(newPosition); } if (accumulatedDelta != Vector3.zero) { newPosition = startPosition + accumulatedDelta; newPositions[j] = newPosition; newUV[j] = GeometryHelper.GetUVForPosition(polygon, newPosition); polygonAffected = true; anyAffected = true; } } } // Apply all the changes to the polygon for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; vertex.Position = newPositions[j]; vertex.UV = newUV[j]; } if (polygonAffected) { // Polygon geometry has changed, inform the polygon that it needs to recalculate its cached plane polygons[i].CalculatePlane(); Vector3 newPlaneNormal = polygons[i].Plane.normal; // Find the rotation from the original polygon plane to the new polygon plane Quaternion normalRotation = Quaternion.FromToRotation(previousPlaneNormal, newPlaneNormal); // Update the affected normals so they are rotated by the rotational difference of the polygon from translation for (int j = 0; j < vertexCount; j++) { Vertex vertex = polygon.Vertices[j]; vertex.Normal = normalRotation * vertex.Normal; } } } if (anyAffected) // If any polygons have changed { // Mark the polygons and brush as having changed brush.Invalidate(true); // Assume that the brush no longer resembles it's base shape, this has false positives but that's not a big issue brush.BreakTypeRelation(); } } }