public void EndCommit() { if (generatedBrushes == null) { return; } var bounds = BoundsUtilities.GetBounds(generatedBrushes); if (!bounds.IsEmpty()) { var center = bounds.Center - operationGameObject.transform.position; GeometryUtility.MoveControlMeshVertices(generatedBrushes, -center); SurfaceUtility.TranslateSurfacesInWorldSpace(generatedBrushes, -center); ControlMeshUtility.RebuildShapes(generatedBrushes); InternalCSGModelManager.Refresh(forceHierarchyUpdate: true); operationGameObject.transform.position += center; Undo.CollapseUndoOperations(undoGroupIndex); Cleanup(); if (generatedGameObjects != null && generatedGameObjects.Length > 0) { Selection.objects = generatedGameObjects; } Reset(); } if (shapeCommitted != null) { shapeCommitted(); } }
public void UpdateSmoothingGroups(HashSet <uint> usedSmoothingGroupIndices) { for (int i = 0; i < curveEdgeHandles.Length; i++) { curveEdgeHandles[i].Texgen.SmoothingGroup = 0; } for (int i = 0; i < curveEdgeHandles.Length; i++) { if (curveEdgeHandles[i].Texgen.SmoothingGroup != 0) { continue; } var smoothingGroup = SurfaceUtility.FindUnusedSmoothingGroupIndex(usedSmoothingGroupIndices); usedSmoothingGroupIndices.Add(smoothingGroup); curveEdgeHandles[i].Texgen.SmoothingGroup = smoothingGroup; if (i == 0 && curveTangentHandles[(i * 2) + 0].Constraint == HandleConstraints.Mirrored || curveTangentHandles[(i * 2) + 1].Constraint == HandleConstraints.Mirrored) { var last = curveEdgeHandles.Length - 1; curveEdgeHandles[last].Texgen.SmoothingGroup = smoothingGroup; } if (i < (curveEdgeHandles.Length - 1) && i < (curve.Points.Length - 1) && (curveTangentHandles[((i + 1) * 2) + 0].Constraint == HandleConstraints.Mirrored || curveTangentHandles[((i + 1) * 2) + 1].Constraint == HandleConstraints.Mirrored)) { curveEdgeHandles[i + 1].Texgen.SmoothingGroup = smoothingGroup; } } }
/* * public static bool ContinueTexGenFromSurfaceToSurface(CSGBrush srcBrush, int srcSurfaceIndex, CSGBrush dstBrush, int dstSurfaceIndex) * { * if (srcSurfaceIndex < 0 || srcSurfaceIndex >= srcBrush.Shape.Materials.Length || * srcBrush == null) * return false; * * var src_brush_cache = CSGModelManager.GetBrushCache(srcBrush); * if (src_brush_cache == null || * src_brush_cache.childData == null || * src_brush_cache.childData.modelTransform == null) * return false; * * var dst_brush_cache = CSGModelManager.GetBrushCache(dstBrush); * if (dst_brush_cache == null || * dst_brush_cache.childData == null || * dst_brush_cache.childData.modelTransform == null) * return false; * * var dstPlane = dstBrush.Shape.Surfaces[dstSurfaceIndex].Plane; * var srcPlane = srcBrush.Shape.Surfaces[srcSurfaceIndex].Plane; * * // convert planes into worldspace * dstPlane = GeometryUtility.InverseTransformPlane(dstBrush.transform.worldToLocalMatrix, dstPlane); * srcPlane = GeometryUtility.InverseTransformPlane(srcBrush.transform.worldToLocalMatrix, srcPlane); * * var dstNormal = dstPlane.normal; * var srcNormal = srcPlane.normal; * * var srcTexGenIndex = srcBrush.Shape.Surfaces[srcSurfaceIndex].TexGenIndex; * var dstTexGenIndex = dstBrush.Shape.Surfaces[dstSurfaceIndex].TexGenIndex; * * var scrShape = srcBrush.Shape; * * dstBrush.Shape.Materials[dstSurfaceIndex] = scrShape.Materials[srcSurfaceIndex]; * Vector3 srcPoint1, srcPoint2; * Vector3 dstPoint1, dstPoint2; * var edgeDirection = Vector3.Cross(dstNormal, srcNormal); * var det = edgeDirection.sqrMagnitude; * if (det < Constants.AlignmentTestEpsilon) * { * // Find 2 points on intersection of 2 planes * srcPoint1 = srcPlane.pointOnPlane; * srcPoint2 = GeometryUtility.ProjectPointOnPlane(srcPlane, srcPoint1 + MathConstants.oneVector3); * * dstPoint1 = GeometryUtility.ProjectPointOnPlane(dstPlane, srcPoint1); * dstPoint2 = GeometryUtility.ProjectPointOnPlane(dstPlane, srcPoint2); * } else * { * // Find 2 points on intersection of 2 planes * srcPoint1 = ((Vector3.Cross(edgeDirection, srcNormal) * -dstPlane.d) + * (Vector3.Cross(dstNormal, edgeDirection) * -srcPlane.d)) / det; * srcPoint2 = srcPoint1 + edgeDirection; * dstPoint1 = srcPoint1; * dstPoint2 = srcPoint2; * } * * Vector3 srcLocalPoint1 = srcBrush.transform.InverseTransformPoint(srcPoint1); * Vector3 srcLocalPoint2 = srcBrush.transform.InverseTransformPoint(srcPoint2); * * Vector3 dstLocalPoint1 = dstBrush.transform.InverseTransformPoint(dstPoint1); * Vector3 dstLocalPoint2 = dstBrush.transform.InverseTransformPoint(dstPoint2); * * var srcShape = srcBrush.Shape; * var srcTexGens = srcShape.TexGens; * var srcSurfaces = srcShape.Surfaces; * var dstShape = dstBrush.Shape; * var dstTexGens = dstShape.TexGens; * var dstSurfaces = dstShape.Surfaces; * * * // Reset destination shape to simplify calculations * dstTexGens[dstTexGenIndex].Scale = scrShape.TexGens[srcTexGenIndex].Scale; * dstTexGens[dstTexGenIndex].Translation = MathConstants.zeroVector2; * dstTexGens[dstTexGenIndex].RotationAngle = 0; * * if (!CSGModelManager.AlignTextureSpacesInLocalSpace(ref srcTexGens[srcTexGenIndex], ref srcSurfaces[srcSurfaceIndex], * srcLocalPoint1, srcLocalPoint2, * ref dstTexGens[dstTexGenIndex], ref dstSurfaces[dstSurfaceIndex], * dstLocalPoint1, dstLocalPoint2)) * return false; * return true; * } */ public static bool ContinueTexGenFromSurfaceToSurface(CSGBrush brush, int srcSurfaceIndex, int dstSurfaceIndex) { if (srcSurfaceIndex < 0 || srcSurfaceIndex >= brush.Shape.Materials.Length || !brush) { return(false); } var shape = brush.Shape; var texGens = shape.TexGens; var texGenFlags = shape.TexGenFlags; var surfaces = shape.Surfaces; var dstPlane = surfaces[dstSurfaceIndex].Plane; var srcPlane = surfaces[srcSurfaceIndex].Plane; // convert planes into worldspace dstPlane = InverseTransformPlane(brush.transform.worldToLocalMatrix, dstPlane); srcPlane = InverseTransformPlane(brush.transform.worldToLocalMatrix, srcPlane); var dstNormal = dstPlane.normal; var srcNormal = srcPlane.normal; var srcTexGenIndex = surfaces[srcSurfaceIndex].TexGenIndex; var dstTexGenIndex = surfaces[dstSurfaceIndex].TexGenIndex; shape.Materials[dstSurfaceIndex] = shape.Materials[srcSurfaceIndex]; Vector3 srcPoint1, srcPoint2; Vector3 dstPoint1, dstPoint2; var edgeDirection = Vector3.Cross(dstNormal, srcNormal); var det = edgeDirection.sqrMagnitude; if (det < MathConstants.AlignmentTestEpsilon) { // Find 2 points on intersection of 2 planes srcPoint1 = srcPlane.pointOnPlane; srcPoint2 = GeometryUtility.ProjectPointOnPlane(srcPlane, srcPoint1 + MathConstants.oneVector3); dstPoint1 = GeometryUtility.ProjectPointOnPlane(dstPlane, srcPoint1); dstPoint2 = GeometryUtility.ProjectPointOnPlane(dstPlane, srcPoint2); } else { // Find 2 points on intersection of 2 planes srcPoint1 = ((Vector3.Cross(edgeDirection, srcNormal) * -dstPlane.d) + (Vector3.Cross(dstNormal, edgeDirection) * -srcPlane.d)) / det; srcPoint2 = srcPoint1 + edgeDirection; dstPoint1 = srcPoint1; dstPoint2 = srcPoint2; } // Reset destination shape to simplify calculations texGens[dstTexGenIndex].Scale = shape.TexGens[srcTexGenIndex].Scale; texGens[dstTexGenIndex].Translation = MathConstants.zeroVector2; texGens[dstTexGenIndex].RotationAngle = 0; return(SurfaceUtility.AlignTextureSpaces(brush.transform, ref texGens[srcTexGenIndex], texGenFlags[srcTexGenIndex], ref surfaces[srcSurfaceIndex], srcPoint1, srcPoint2, false, brush.transform, ref texGens[dstTexGenIndex], texGenFlags[dstTexGenIndex], ref surfaces[dstSurfaceIndex], dstPoint1, dstPoint2, false)); }
private static void ApplyMaterial(Material material) { var activetool = EditModeManager.ActiveTool as EditModeSurface; if (activetool != null) { var selectedBrushSurfaces = activetool.GetSelectedSurfaces(); SurfaceUtility.SetMaterials(selectedBrushSurfaces, material); } }
static void OnGUIContentsMaterialImage(bool isSceneGUI, Material material, bool mixedValues, SelectedBrushSurface[] selectedBrushSurfaces) { GUILayout.BeginHorizontal(materialWidth, materialHeight); { //if (materialEditor == null || prevMaterial != material) { var editor = materialEditor as Editor; Editor.CreateCachedEditor(material, typeof(MaterialEditor), ref editor); materialEditor = editor as MaterialEditor; //prevMaterial = material; } if (materialEditor != null) { var rect = GUILayoutUtility.GetRect(materialSize, materialSize); EditorGUI.showMixedValue = mixedValues; materialEditor.OnPreviewGUI(rect, GUIStyle.none); EditorGUI.showMixedValue = false; } else { GUILayout.Box(new GUIContent(), CSG_GUIStyleUtility.emptyMaterialStyle, materialWidth, materialHeight); } } GUILayout.EndHorizontal(); var currentArea = GUILayoutUtility.GetLastRect(); var currentPoint = Event.current.mousePosition; if (currentArea.Contains(currentPoint)) { if (Event.current.type == EventType.DragUpdated && GetDragMaterial()) { DragAndDrop.visualMode = DragAndDropVisualMode.Generic; Event.current.Use(); } if (Event.current.type == EventType.DragPerform) { var new_material = GetDragMaterial(); if (new_material) { SurfaceUtility.SetMaterials(selectedBrushSurfaces, new_material); CSGSettings.DefaultMaterial = new_material; CSGSettings.Save(); GUI.changed = true; Event.current.Use(); } } } }
/// <summary>Converts a <see cref="RealtimeCSG.Legacy.Surface"/>/<see cref="RealtimeCSG.Legacy.TexGen"/>/<see cref="RealtimeCSG.Legacy.TexGenFlags"/> combination into a <see cref="RealtimeCSG.Foundation.SurfaceDescription"/>.</summary> /// <param name="surface">A legacy <see cref="RealtimeCSG.Legacy.Surface"/> that describes how the texture space is orientated relative to the brush.</param> /// <param name="texGen">A legacy <see cref="RealtimeCSG.Legacy.TexGen"/> that describes how the texture coordinates are calculated in the <see cref="RealtimeCSG.Foundation.SurfaceDescription"/>.</param> /// <param name="texGenFlags">A legacy <see cref="RealtimeCSG.Legacy.TexGenFlags"/> enum that describes if the <see cref="RealtimeCSG.Foundation.SurfaceDescription"/> texture generation will be in world-space or brush-space.</param> /// <returns>A new <see cref="RealtimeCSG.Foundation.SurfaceDescription"/></returns> public static SurfaceDescription CreateSurfaceDescription(Surface surface, TexGen texGen, TexGenFlags texGenFlags) { var localToTextureSpace = SurfaceUtility.GetLocalToTextureSpaceMatrix(texGen, surface); SurfaceDescription description; description.smoothingGroup = texGen.SmoothingGroup; description.surfaceFlags = ((texGenFlags & TexGenFlags.WorldSpaceTexture) == 0) ? SurfaceFlags.None : SurfaceFlags.TextureIsInWorldSpace; description.UV0.U = localToTextureSpace.GetRow(0); description.UV0.V = localToTextureSpace.GetRow(1); return(description); }
private bool GenerateStairs(CSGBrush[] stepBrushes, int totalSteps, float stepLength, float stepHeight, float stairsDepth, float stairsWidth, float stairsHeight, float extraDepth, float extraHeight) { bool success = true; for (int stepIndex = 0; stepIndex < totalSteps; stepIndex++) { var brush = stepBrushes[stepIndex]; if (!brush) { continue; } var curStepHeight = Mathf.Min(stairsHeight, (stepIndex == 0) ? (extraHeight + stepHeight) : stepHeight); var curStepY = (stepIndex == 0) ? (stepHeight * stepIndex) : (extraHeight + (stepHeight * stepIndex)); var extraLength = lengthDirection * (stepLength * stepIndex); var heightPos = heightDirection * curStepY; var widthSize = (widthDirection * stairsWidth); var lengthSize = (lengthDirection * stairsDepth) - extraLength; var heightSize = (heightDirection * curStepHeight); var size = widthSize + heightSize + lengthSize; var position = (totalSteps == 1) ? (heightPos + brushPosition) : heightPos; ControlMesh newControlMesh; Shape newShape; if (!BrushFactory.CreateCubeControlMesh(out newControlMesh, out newShape, Vector3.zero, size)) { success = false; if (brush.gameObject.activeSelf) { brush.gameObject.SetActive(false); } continue; } if (!brush.gameObject.activeSelf) { brush.gameObject.SetActive(true); } brush.Shape = newShape; brush.ControlMesh = newControlMesh; brush.transform.localPosition = position; SurfaceUtility.TranslateSurfacesInWorldSpace(brush, -position); } return(success); }
public static void TranslatePivot(CSGBrush[] brushes, Vector3 offset) { if (brushes == null || brushes.Length == 0 || offset.sqrMagnitude < MathConstants.ConsideredZero) { return; } for (int i = 0; i < brushes.Length; i++) { brushes[i].transform.position += offset; } GeometryUtility.MoveControlMeshVertices(brushes, -offset); SurfaceUtility.TranslateSurfacesInWorldSpace(brushes, -offset); ControlMeshUtility.RebuildShapes(brushes); }
public static void SetPivot(CSGBrush brush, Vector3 newCenter) { if (!brush) { return; } var transform = brush.transform; var realCenter = transform.position; var difference = newCenter - realCenter; if (difference.sqrMagnitude < MathConstants.ConsideredZero) { return; } transform.position += difference; GeometryUtility.MoveControlMeshVertices(brush, -difference); SurfaceUtility.TranslateSurfacesInWorldSpace(brush, -difference); ControlMeshUtility.RebuildShape(brush); }
public static void OnSurfaceFlagButtons(SurfaceFlagState state, SelectedBrushSurface[] selectedBrushSurfaces, bool isSceneGUI = false) { var leftStyle = isSceneGUI ? EditorStyles.miniButtonLeft : GUI.skin.button; //var middleStyle = isSceneGUI ? EditorStyles.miniButtonMid : GUI.skin.button; var rightStyle = isSceneGUI ? EditorStyles.miniButtonRight : GUI.skin.button; GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (!isSceneGUI) { GUILayout.Label(ContentShadows, EditModeSurfaceGUI.largeLabelWidth); } else { GUILayout.Label(ContentShadows, EditorStyles.miniLabel, EditModeSurfaceGUI.smallLabelWidth); } EditorGUI.BeginChangeCheck(); { // TODO: implement support EditorGUI.showMixedValue = !state.noReceiveShadows.HasValue; state.noReceiveShadows = !GUILayout.Toggle(!(state.noReceiveShadows ?? (state.noRender ?? true)), ContentReceiveShadowsSurfaces, leftStyle); TooltipUtility.SetToolTip(ToolTipReceiveShadowsSurfaces); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoReceiveShadows, state.noReceiveShadows.Value); } EditorGUI.BeginChangeCheck(); { // TODO: implement support EditorGUI.showMixedValue = !state.noCastShadows.HasValue; state.noCastShadows = !GUILayout.Toggle(!(state.noCastShadows ?? true), ContentCastShadowsSurfaces, rightStyle); TooltipUtility.SetToolTip(ToolTipCastShadowsSurfaces); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoCastShadows, state.noCastShadows.Value); } } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = !state.noRender.HasValue; state.noRender = !GUILayout.Toggle(!(state.noRender ?? true), ContentVisibleSurfaces, leftStyle); TooltipUtility.SetToolTip(ToolTipVisibleSurfaces); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoRender, state.noRender.Value); } EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = !state.noCollision.HasValue; state.noCollision = !GUILayout.Toggle(!(state.noCollision ?? true), ContentCollisionSurfaces, rightStyle); TooltipUtility.SetToolTip(ToolTipCollisionSurfaces); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoCollision, state.noCollision.Value); } } GUILayout.EndHorizontal(); EditorGUI.showMixedValue = false; }
public static void OnSurfaceFlagButtons(Rect rect, SurfaceFlagState state, SelectedBrushSurface[] selectedBrushSurfaces) { var leftStyle = EditorStyles.miniButtonLeft; var rightStyle = EditorStyles.miniButtonRight; var tempRect = rect; { tempRect.Set(rect.x + 4, rect.y + 1, 45, 16); GUI.Label(tempRect, ContentShadows, EditorStyles.miniLabel); EditorGUI.BeginChangeCheck(); { var mixed = !state.noReceiveShadows.HasValue; var enabled = !(state.noReceiveShadows ?? (state.noRender ?? true)); EditorGUI.showMixedValue = mixed; tempRect.Set(rect.x + 53, rect.y + 1, 90 - 4, 15); state.noReceiveShadows = !GUI.Toggle(tempRect, enabled, ContentReceiveShadowsSurfaces, leftStyle); TooltipUtility.SetToolTip(ToolTipReceiveShadowsSurfaces, tempRect); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoReceiveShadows, state.noReceiveShadows.Value); } EditorGUI.BeginChangeCheck(); { var mixed = !state.noCastShadows.HasValue; var enabled = !(state.noCastShadows ?? true); EditorGUI.showMixedValue = mixed; tempRect.Set(rect.x + 143 - 4, rect.y + 1, 74 - 4, 15); state.noCastShadows = !GUI.Toggle(tempRect, enabled, ContentCastShadowsSurfaces, rightStyle); TooltipUtility.SetToolTip(ToolTipCastShadowsSurfaces, tempRect); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoCastShadows, state.noCastShadows.Value); } } { EditorGUI.BeginChangeCheck(); { var mixed = !state.noRender.HasValue; var enabled = !(state.noRender ?? true); EditorGUI.showMixedValue = mixed; tempRect.Set(rect.x + 4, rect.y + 18, 94, 15); state.noRender = !GUI.Toggle(tempRect, enabled, ContentVisibleSurfaces, leftStyle); TooltipUtility.SetToolTip(ToolTipVisibleSurfaces, tempRect); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoRender, state.noRender.Value); } EditorGUI.BeginChangeCheck(); { var mixed = !state.noCollision.HasValue; var enabled = !(state.noCollision ?? true); EditorGUI.showMixedValue = mixed; tempRect.Set(rect.x + 98, rect.y + 18, 112, 15); state.noCollision = !GUI.Toggle(tempRect, enabled, ContentCollisionSurfaces, rightStyle); TooltipUtility.SetToolTip(ToolTipCollisionSurfaces, tempRect); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoCollision, state.noCollision.Value); } } EditorGUI.showMixedValue = false; }
public static Transform[] CloneTargets(SetTransformation setTransform = null) { if (instance.filteredSelection.NodeTargets.Length == 0) { return(new Transform[0]); } var groupId = Undo.GetCurrentGroup(); //Undo.IncrementCurrentGroup(); var newTargets = new GameObject[instance.filteredSelection.NodeTargets.Length]; var newTransforms = new Transform[instance.filteredSelection.NodeTargets.Length]; for (int i = 0; i < instance.filteredSelection.NodeTargets.Length; i++) { var originalGameObject = instance.filteredSelection.NodeTargets[i].gameObject; var originalTransform = originalGameObject.GetComponent <Transform>(); newTargets[i] = CSGPrefabUtility.Instantiate(originalGameObject); var newTransform = newTargets[i].GetComponent <Transform>(); if (originalTransform.parent != null) { newTransform.SetParent(originalTransform.parent, false); newTransform.SetSiblingIndex(originalTransform.GetSiblingIndex() + 1); newTransform.name = GameObjectUtility.GetUniqueNameForSibling(originalTransform.parent, originalTransform.name); } if (setTransform == null) { newTransform.localScale = originalTransform.localScale; newTransform.localPosition = originalTransform.localPosition; newTransform.localRotation = originalTransform.localRotation; } else { setTransform(newTransform, originalTransform); } var childBrushes = newTargets[i].GetComponentsInChildren <CSGBrush>(); Dictionary <uint, uint> uniqueSmoothingGroups = new Dictionary <uint, uint>(); foreach (var childBrush in childBrushes) { for (int g = 0; g < childBrush.Shape.TexGens.Length; g++) { var smoothingGroup = childBrush.Shape.TexGens[g].SmoothingGroup; if (smoothingGroup == 0) { continue; } uint newSmoothingGroup; if (!uniqueSmoothingGroups.TryGetValue(smoothingGroup, out newSmoothingGroup)) { newSmoothingGroup = SurfaceUtility.FindUnusedSmoothingGroupIndex(); uniqueSmoothingGroups[smoothingGroup] = newSmoothingGroup; } childBrush.Shape.TexGens[g].SmoothingGroup = newSmoothingGroup; } } newTransforms[i] = newTransform; Undo.RegisterCreatedObjectUndo(newTargets[i], "Created clone of " + originalGameObject.name); } Selection.objects = newTargets; Undo.CollapseUndoOperations(groupId); return(newTransforms); }
protected bool UpdateExtrudedShape(bool registerUndo = true) { if (polygons == null || polygons.Length == 0) { return(false); } bool failures = false; bool modifiedHierarchy = false; if (HaveExtrusion) { UpdateBrushOperation(); if (generatedGameObjects != null && generatedGameObjects.Length > 0) { for (int i = generatedGameObjects.Length - 1; i >= 0; i--) { if (generatedGameObjects[i]) { continue; } ArrayUtility.RemoveAt(ref generatedGameObjects, i); } } if (generatedGameObjects == null || generatedGameObjects.Length == 0) { Cancel(); return(false); } if (generatedGameObjects != null && generatedGameObjects.Length > 0) { if (registerUndo) { Undo.RecordObjects(generatedGameObjects, "Extruded shape"); } int brushIndex = 0; for (int slice = 0; slice < extrusionPoints.Length - 1; slice++) { for (int p = 0; p < polygons.Length; p++) { var brush = generatedBrushes[brushIndex]; brushIndex++; if (!brush || !brush.gameObject) { continue; } var direction = haveForcedDirection ? forcedDirection : buildPlane.normal; var distance = new CSGPlane(direction, extrusionPoints[slice].Position).Distance(extrusionPoints[slice + 1].Position); if (float.IsInfinity(distance) || float.IsNaN(distance)) { distance = 1.0f; } var poly2dToWorldMatrix = brush.transform.worldToLocalMatrix * Matrix4x4.TRS(extrusionPoints[slice].Position, Quaternion.FromToRotation(MathConstants.upVector3, buildPlane.normal), Vector3.one); // * parentModel.transform.localToWorldMatrix; ControlMesh newControlMesh; Shape newShape; if (!CreateControlMeshForBrushIndex(parentModel, brush, polygons[p], poly2dToWorldMatrix, distance, out newControlMesh, out newShape)) { failures = true; if (brush.gameObject.activeSelf) { modifiedHierarchy = true; brush.gameObject.SetActive(false); } continue; } if (!brush.gameObject.activeSelf) { modifiedHierarchy = true; brush.gameObject.SetActive(true); } brush.ControlMesh.SetDirty(); if (registerUndo) { EditorUtility.SetDirty(brush); } } } } } else { if (generatedGameObjects != null) { if (registerUndo) { Undo.RecordObjects(generatedGameObjects, "Extruded brush"); } InternalCSGModelManager.skipCheckForChanges = false; int brushIndex = 0; for (int slice = 0; slice < extrusionPoints.Length - 1; slice++) { for (int p = 0; p < polygons.Length; p++) { if (p >= generatedBrushes.Length) { continue; } var brush = generatedBrushes[brushIndex]; brushIndex++; brush.ControlMesh.SetDirty(); if (registerUndo) { EditorUtility.SetDirty(brush); } } } HideGenerateBrushes(); } } try { InternalCSGModelManager.skipCheckForChanges = true; if (registerUndo) { EditorUtility.SetDirty(this); } //CSGModelManager.External.SetDirty(parentModel.modelNodeID); InternalCSGModelManager.CheckForChanges(forceHierarchyUpdate: modifiedHierarchy); } finally { InternalCSGModelManager.skipCheckForChanges = false; } if (shapeEdges != null && smearTextures) { CSGBrush lastBrush = null; int lastSurfaceIndex = -1; for (int slice = 0; slice < extrusionPoints.Length - 1; slice++) { for (int se = 0; se < shapeEdges.Length; se++) { var brushIndex = shapeEdges[se].PolygonIndex + (slice * shapeEdges.Length); var surfaceIndex = shapeEdges[se].EdgeIndex; if (brushIndex < 0 || brushIndex >= generatedBrushes.Length || surfaceIndex == -1) { continue; } var brush = generatedBrushes[brushIndex]; if (brush && brush.brushNodeID != CSGNode.InvalidNodeID) { if (lastBrush && lastBrush.brushNodeID != CSGNode.InvalidNodeID) { SurfaceUtility.CopyLastMaterial(brush, surfaceIndex, false, lastBrush, lastSurfaceIndex, false, registerUndo = false); } else { brush.Shape.TexGens[surfaceIndex].Translation = Vector3.zero; brush.Shape.TexGens[surfaceIndex].Scale = Vector2.one; brush.Shape.TexGens[surfaceIndex].RotationAngle = 0; } lastBrush = brush; lastSurfaceIndex = surfaceIndex; } } } } InternalCSGModelManager.RefreshMeshes(); return(!failures); }
public static void OnSurfaceFlagButtons(SelectedBrushSurface[] selectedBrushSurfaces, bool isSceneGUI = false) { var leftStyle = isSceneGUI ? EditorStyles.miniButtonLeft : GUI.skin.button; //var middleStyle = isSceneGUI ? EditorStyles.miniButtonMid : GUI.skin.button; var rightStyle = isSceneGUI ? EditorStyles.miniButtonRight : GUI.skin.button; bool?noRender = false; bool?noCollision = false; bool?noCastShadows = false; bool?noReceiveShadows = false; if (selectedBrushSurfaces.Length > 0) { for (var i = 0; i < selectedBrushSurfaces.Length; i++) { var brush = selectedBrushSurfaces[i].brush; var surfaceIndex = selectedBrushSurfaces[i].surfaceIndex; if (surfaceIndex >= brush.Shape.Surfaces.Length) { Debug.LogWarning("surface_index >= brush.Shape.Surfaces.Length"); continue; } var texGenIndex = brush.Shape.Surfaces[surfaceIndex].TexGenIndex; if (texGenIndex >= brush.Shape.TexGens.Length) { Debug.LogWarning("texGen_index >= brush.Shape.TexGens.Length"); continue; } var texGenFlags = brush.Shape.TexGenFlags[texGenIndex]; var surfaceNoRender = ((texGenFlags & TexGenFlags.NoRender) == TexGenFlags.NoRender); var surfaceNoCollision = ((texGenFlags & TexGenFlags.NoCollision) == TexGenFlags.NoCollision); var surfaceNoCastShadows = ((texGenFlags & TexGenFlags.NoCastShadows) == TexGenFlags.NoCastShadows); var surfaceNoReceiveShadows = ((texGenFlags & TexGenFlags.NoReceiveShadows) == TexGenFlags.NoReceiveShadows); if (i == 0) { noRender = surfaceNoRender; noCollision = surfaceNoCollision; noCastShadows = surfaceNoCastShadows; noReceiveShadows = surfaceNoReceiveShadows; } else { if (noRender.HasValue && noRender.Value != surfaceNoRender) { noRender = surfaceNoRender; } if (noCollision.HasValue && noCollision.Value != surfaceNoCollision) { noCollision = surfaceNoCollision; } if (noCastShadows.HasValue && noCastShadows.Value != surfaceNoCastShadows) { noCastShadows = surfaceNoCastShadows; } if (noReceiveShadows.HasValue && noReceiveShadows.Value != surfaceNoReceiveShadows) { noReceiveShadows = surfaceNoReceiveShadows; } } } } GUILayout.BeginHorizontal(GUIStyleUtility.ContentEmpty); { if (!isSceneGUI) { GUILayout.Label(ContentShadows, SurfaceToolGUI.largeLabelWidth); } else { GUILayout.Label(ContentShadows, EditorStyles.miniLabel, SurfaceToolGUI.smallLabelWidth); } EditorGUI.BeginChangeCheck(); { // TODO: implement support EditorGUI.showMixedValue = !noReceiveShadows.HasValue; noReceiveShadows = !GUILayout.Toggle(!(noReceiveShadows ?? (noRender ?? true)), ContentReceiveShadowsSurfaces, leftStyle); TooltipUtility.SetToolTip(ToolTipReceiveShadowsSurfaces); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoReceiveShadows, noReceiveShadows.Value); } EditorGUI.EndDisabledGroup(); EditorGUI.BeginChangeCheck(); { // TODO: implement support EditorGUI.showMixedValue = !noCastShadows.HasValue; noCastShadows = !GUILayout.Toggle(!(noCastShadows ?? true), ContentCastShadowsSurfaces, rightStyle); TooltipUtility.SetToolTip(ToolTipCastShadowsSurfaces); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoCastShadows, noCastShadows.Value); } } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(GUIStyleUtility.ContentEmpty); { EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = !noRender.HasValue; noRender = !GUILayout.Toggle(!(noRender ?? true), ContentVisibleSurfaces, leftStyle); TooltipUtility.SetToolTip(ToolTipVisibleSurfaces); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoRender, noRender.Value); } EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = !noCollision.HasValue; noCollision = !GUILayout.Toggle(!(noCollision ?? true), ContentCollisionSurfaces, rightStyle); TooltipUtility.SetToolTip(ToolTipCollisionSurfaces); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetSurfaceTexGenFlags(selectedBrushSurfaces, TexGenFlags.NoCollision, noCollision.Value); } } GUILayout.EndHorizontal(); EditorGUI.showMixedValue = false; }
/* * static void OnGUIContentsMaterialInspector(Material material, bool mixedValues) * { * //if (materialEditor == null || prevMaterial != material) * { * var editor = materialEditor as Editor; * Editor.CreateCachedEditor(material, typeof(MaterialEditor), ref editor); * materialEditor = editor as MaterialEditor; * } * * if (materialEditor != null) * { * EditorGUI.showMixedValue = mixedValues; * try * { * materialEditor.DrawHeader(); * if (materialEditor.PropertiesGUI()) * { * materialEditor.PropertiesChanged(); * } * } * catch * {} * EditorGUI.showMixedValue = false; * } * } */ private static void OnGUIContents(bool isSceneGUI, EditModeSurface tool) { EditModeCommonGUI.StartToolGUI(); var selectedBrushSurfaces = (tool == null) ? new SelectedBrushSurface[0] : tool.GetSelectedSurfaces(); var enabled = selectedBrushSurfaces.Length > 0; EditorGUI.BeginDisabledGroup(!enabled); { Material material = null; var currentTexGen = new TexGen(); var haveTexgen = false; var multipleColors = !enabled; var multipleTranslationX = !enabled; var multipleTranslationY = !enabled; var multipleScaleX = !enabled; var multipleScaleY = !enabled; var multipleRotationAngle = !enabled; var multipleMaterials = !enabled; bool?textureLocked = null; bool foundHelperMaterial = false; RenderSurfaceType?firstRenderSurfaceType = null; Material firstMaterial = null; if (selectedBrushSurfaces.Length > 0) { for (var i = 0; i < selectedBrushSurfaces.Length; i++) { var brush = selectedBrushSurfaces[i].brush; if (!brush) { continue; } var surfaceIndex = selectedBrushSurfaces[i].surfaceIndex; if (surfaceIndex >= brush.Shape.Surfaces.Length) { Debug.LogWarning("surface_index >= brush.Shape.Surfaces.Length"); continue; } var texGenIndex = brush.Shape.Surfaces[surfaceIndex].TexGenIndex; if (texGenIndex >= brush.Shape.TexGens.Length) { Debug.LogWarning("texGen_index >= brush.Shape.TexGens.Length"); continue; } var brushCache = InternalCSGModelManager.GetBrushCache(brush); var model = (brushCache != null) ? brushCache.childData.Model : null; Material foundMaterial; var texGenFlags = brush.Shape.TexGenFlags[texGenIndex]; if (model && (!model.IsRenderable || model.ShadowsOnly)) { foundHelperMaterial = true; if (!firstRenderSurfaceType.HasValue) { firstRenderSurfaceType = ModelTraits.GetModelSurfaceType(model); } foundMaterial = null; } else if ((texGenFlags & TexGenFlags.NoRender) == TexGenFlags.NoRender) { foundHelperMaterial = true; if (!firstRenderSurfaceType.HasValue) { if ((texGenFlags & TexGenFlags.NoCastShadows) != TexGenFlags.NoCastShadows) { firstRenderSurfaceType = RenderSurfaceType.ShadowOnly; } else if ((texGenFlags & TexGenFlags.NoCollision) != TexGenFlags.NoCollision) { firstRenderSurfaceType = RenderSurfaceType.Collider; } else { firstRenderSurfaceType = RenderSurfaceType.Hidden; } } foundMaterial = null; } else { var surfaceMaterial = brush.Shape.TexGens[texGenIndex].RenderMaterial; if (!foundHelperMaterial) { var surfaceType = MaterialUtility.GetMaterialSurfaceType(surfaceMaterial); if (!firstRenderSurfaceType.HasValue) { firstRenderSurfaceType = surfaceType; } foundHelperMaterial = surfaceType != RenderSurfaceType.Normal; } foundMaterial = surfaceMaterial; } if ((texGenFlags & TexGenFlags.WorldSpaceTexture) == TexGenFlags.WorldSpaceTexture) { if (i == 0) { textureLocked = false; } else if (textureLocked.HasValue && textureLocked.Value) { textureLocked = null; } } else { if (i == 0) { textureLocked = true; } else if (textureLocked.HasValue && !textureLocked.Value) { textureLocked = null; } } if (foundMaterial != material) { if (!material) { firstMaterial = foundMaterial; material = foundMaterial; } else { multipleMaterials = true; } } if (!haveTexgen) { currentTexGen = brush.Shape.TexGens[texGenIndex]; haveTexgen = true; } else { if (!multipleColors) { var color = brush.Shape.TexGens[texGenIndex].Color; multipleColors = currentTexGen.Color.a != color.a || currentTexGen.Color.b != color.b || currentTexGen.Color.g != color.g || currentTexGen.Color.r != color.r; } if (!multipleScaleX || !multipleScaleY) { var scale = brush.Shape.TexGens[texGenIndex].Scale; multipleScaleX = multipleScaleX || currentTexGen.Scale.x != scale.x; multipleScaleY = multipleScaleY || currentTexGen.Scale.y != scale.y; } if (!multipleTranslationX || !multipleTranslationY) { var translation = brush.Shape.TexGens[texGenIndex].Translation; multipleTranslationX = multipleTranslationX || currentTexGen.Translation.x != translation.x; multipleTranslationY = multipleTranslationY || currentTexGen.Translation.y != translation.y; } if (!multipleRotationAngle) { var rotationAngle = brush.Shape.TexGens[texGenIndex].RotationAngle; multipleRotationAngle = currentTexGen.RotationAngle != rotationAngle; } } } if (foundHelperMaterial && !firstMaterial) { if (firstRenderSurfaceType.HasValue) { firstMaterial = MaterialUtility.GetSurfaceMaterial(firstRenderSurfaceType.Value); } else { firstMaterial = MaterialUtility.HiddenMaterial; } } } GUILayout.BeginVertical(isSceneGUI ? materialDoubleWidth : CSG_GUIStyleUtility.ContentEmpty); { GUILayout.BeginVertical(isSceneGUI ? GUI.skin.box : GUIStyle.none); { /* * Color new_color; * EditorGUI.BeginChangeCheck(); * { * EditorGUI.showMixedValue = multipleColors; * // why doesn't the colorfield return a modified color? * try * { * new_color = EditorGUILayout.ColorField(GUIContent.none, currentTexGen.Color); * } * catch * { * new_color = currentTexGen.Color; * } * } * if (EditorGUI.EndChangeCheck() || currentTexGen.Color != new_color) * { * SurfaceUtility.SetColors(selectedBrushSurfaces, new_color); * } */ if (isSceneGUI) { GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { EditorGUI.BeginDisabledGroup(material == null); { GUILayout.BeginVertical(CSG_GUIStyleUtility.ContentEmpty); { GUILayout.Space(1); /* * Color new_color; * EditorGUI.BeginChangeCheck(); * { * EditorGUI.showMixedValue = multipleColors; * // why doesn't the colorfield return a modified color? * try * { * new_color = EditorGUILayout.ColorField(GUIContent.none, currentTexGen.Color); * } * catch * { * new_color = currentTexGen.Color; * } * } * if (EditorGUI.EndChangeCheck() || currentTexGen.Color != new_color) * { * SurfaceUtility.SetColors(selectedBrushSurfaces, new_color); * } * * GUILayout.Space(1); */ Material newMaterial; EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = multipleMaterials; newMaterial = EditorGUILayout.ObjectField(material, typeof(Material), true) as Material; EditorGUI.showMixedValue = false; } if (EditorGUI.EndChangeCheck()) { if (newMaterial) { SurfaceUtility.SetMaterials(selectedBrushSurfaces, newMaterial); CSGSettings.DefaultMaterial = newMaterial; CSGSettings.Save(); } } } GUILayout.EndVertical(); GUILayout.Space(1); } EditorGUI.EndDisabledGroup(); } GUILayout.EndHorizontal(); GUILayout.Space(4); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { GUILayout.Space(2); OnGUIContentsMaterialImage(isSceneGUI, firstMaterial, multipleMaterials, selectedBrushSurfaces); GUILayout.BeginHorizontal(materialWidth); { GUILayout.FlexibleSpace(); GUILayout.BeginVertical(materialHeight); { OnGUIContentsJustify(isSceneGUI, selectedBrushSurfaces); GUILayout.FlexibleSpace(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); GUILayout.FlexibleSpace(); } GUILayout.EndHorizontal(); } } GUILayout.EndVertical(); if (!isSceneGUI) { EditorGUILayout.Space(); } if (currentTexGen.Scale.x == 0.0f) { currentTexGen.Scale.x = 1.0f; } if (currentTexGen.Scale.y == 0.0f) { currentTexGen.Scale.y = 1.0f; } const float scale_round = 10000.0f; currentTexGen.Scale.x = Mathf.RoundToInt(currentTexGen.Scale.x * scale_round) / scale_round; currentTexGen.Scale.y = Mathf.RoundToInt(currentTexGen.Scale.y * scale_round) / scale_round; currentTexGen.Translation.x = Mathf.RoundToInt(currentTexGen.Translation.x * scale_round) / scale_round; currentTexGen.Translation.y = Mathf.RoundToInt(currentTexGen.Translation.y * scale_round) / scale_round; currentTexGen.RotationAngle = Mathf.RoundToInt(currentTexGen.RotationAngle * scale_round) / scale_round; var leftStyle = isSceneGUI ? EditorStyles.miniButtonLeft : GUI.skin.button; var middleStyle = isSceneGUI ? EditorStyles.miniButtonMid : GUI.skin.button; var rightStyle = isSceneGUI ? EditorStyles.miniButtonRight : GUI.skin.button; GUILayout.BeginVertical(isSceneGUI ? GUI.skin.box : GUIStyle.none); { EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = !textureLocked.HasValue; textureLocked = EditorGUILayout.ToggleLeft(ContentLockTexture, textureLocked.HasValue ? textureLocked.Value : false); TooltipUtility.SetToolTip(ToolTipLockTexture); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetTextureLock(selectedBrushSurfaces, textureLocked.Value); } } GUILayout.EndVertical(); GUILayout.BeginVertical(isSceneGUI ? GUI.skin.box : GUIStyle.none); { GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (isSceneGUI) { EditorGUILayout.LabelField(ContentUVScale, EditorStyles.miniLabel, labelWidth); } else { EditorGUILayout.LabelField(ContentUVScale, largeLabelWidth); } TooltipUtility.SetToolTip(ToolTipScaleUV); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (!isSceneGUI) { EditorGUILayout.LabelField(ContentUSymbol, unitWidth); } EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = multipleScaleX; currentTexGen.Scale.x = EditorGUILayout.FloatField(currentTexGen.Scale.x, minFloatFieldWidth); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetScaleX(selectedBrushSurfaces, currentTexGen.Scale.x); } if (!isSceneGUI) { EditorGUILayout.LabelField(ContentVSymbol, unitWidth); } EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = multipleScaleY; currentTexGen.Scale.y = EditorGUILayout.FloatField(currentTexGen.Scale.y, minFloatFieldWidth); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetScaleY(selectedBrushSurfaces, currentTexGen.Scale.y); } } GUILayout.EndHorizontal(); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (isSceneGUI) { EditorGUILayout.LabelField(ContentOffset, EditorStyles.miniLabel, labelWidth); } else { EditorGUILayout.LabelField(ContentOffset, largeLabelWidth); } TooltipUtility.SetToolTip(ToolTipOffsetUV); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (!isSceneGUI) { EditorGUILayout.LabelField(ContentUSymbol, unitWidth); } EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = multipleTranslationX; currentTexGen.Translation.x = EditorGUILayout.FloatField(currentTexGen.Translation.x, minFloatFieldWidth); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetTranslationX(selectedBrushSurfaces, currentTexGen.Translation.x); } if (!isSceneGUI) { EditorGUILayout.LabelField(ContentVSymbol, unitWidth); } EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = multipleTranslationY; currentTexGen.Translation.y = EditorGUILayout.FloatField(currentTexGen.Translation.y, minFloatFieldWidth); } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetTranslationY(selectedBrushSurfaces, currentTexGen.Translation.y); } } GUILayout.EndHorizontal(); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (isSceneGUI) { EditorGUILayout.LabelField(ContentRotate, EditorStyles.miniLabel, labelWidth); } else { EditorGUILayout.LabelField(ContentRotate, largeLabelWidth); } TooltipUtility.SetToolTip(ToolTipRotation); if (!isSceneGUI) { GUILayout.BeginVertical(CSG_GUIStyleUtility.ContentEmpty); } GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = multipleRotationAngle; currentTexGen.RotationAngle = EditorGUILayout.FloatField(currentTexGen.RotationAngle, minFloatFieldWidth); if (!isSceneGUI) { EditorGUILayout.LabelField(ContentAngleSymbol, unitWidth); } } if (EditorGUI.EndChangeCheck()) { SurfaceUtility.SetRotationAngle(selectedBrushSurfaces, currentTexGen.RotationAngle); } } GUILayout.EndHorizontal(); var buttonWidth = isSceneGUI ? new GUILayoutOption[] { angleButtonWidth } : new GUILayoutOption[0]; GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (GUILayout.Button(ContentRotate90Negative, leftStyle, buttonWidth)) { SurfaceUtility.AddRotationAngle(selectedBrushSurfaces, -90.0f); } TooltipUtility.SetToolTip(ToolTipRotate90Negative); if (GUILayout.Button(ContentRotate90Positive, rightStyle, buttonWidth)) { SurfaceUtility.AddRotationAngle(selectedBrushSurfaces, +90.0f); } TooltipUtility.SetToolTip(ToolTipRotate90Positive); } GUILayout.EndHorizontal(); if (!isSceneGUI) { GUILayout.EndVertical(); } } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (!isSceneGUI) { EditorGUILayout.Space(); } GUILayout.BeginVertical(isSceneGUI ? GUI.skin.box : GUIStyle.none); { GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (!isSceneGUI) { GUILayout.Label(ContentFit, largeLabelWidth); } else { GUILayout.Label(ContentFit, EditorStyles.miniLabel, smallLabelWidth); } if (GUILayout.Button(ContentFitX, leftStyle)) { SurfaceUtility.FitSurfaceX(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipFitX); if (GUILayout.Button(ContentFitXY, middleStyle)) { SurfaceUtility.FitSurface(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipFitXY); if (GUILayout.Button(ContentFitY, rightStyle)) { SurfaceUtility.FitSurfaceY(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipFitY); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (!isSceneGUI) { GUILayout.Label(ContentReset, largeLabelWidth); } else { GUILayout.Label(ContentReset, EditorStyles.miniLabel, smallLabelWidth); } if (GUILayout.Button(ContentResetX, leftStyle)) { SurfaceUtility.ResetSurfaceX(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipResetX); if (GUILayout.Button(ContentResetXY, middleStyle)) { SurfaceUtility.ResetSurface(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipResetXY); if (GUILayout.Button(ContentResetY, rightStyle)) { SurfaceUtility.ResetSurfaceY(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipResetY); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (!isSceneGUI) { GUILayout.Label(ContentFlip, largeLabelWidth); } else { GUILayout.Label(ContentFlip, EditorStyles.miniLabel, smallLabelWidth); } if (GUILayout.Button(ContentFlipX, leftStyle)) { SurfaceUtility.FlipX(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipFlipX); if (GUILayout.Button(ContentFlipXY, middleStyle)) { SurfaceUtility.FlipXY(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipFlipXY); if (GUILayout.Button(ContentFlipY, rightStyle)) { SurfaceUtility.FlipY(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipFlipY); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (!isSceneGUI) { GUILayout.Label(ContentScale, largeLabelWidth); } else { GUILayout.Label(ContentScale, EditorStyles.miniLabel, smallLabelWidth); } if (GUILayout.Button(ContentDoubleScale, leftStyle)) { SurfaceUtility.MultiplyScale(selectedBrushSurfaces, 2.0f); } TooltipUtility.SetToolTip(ToolTipDoubleScale); if (GUILayout.Button(ContentHalfScale, rightStyle)) { SurfaceUtility.MultiplyScale(selectedBrushSurfaces, 0.5f); } TooltipUtility.SetToolTip(ToolTipHalfScale); } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (!isSceneGUI) { EditorGUILayout.Space(); } if (!isSceneGUI) { OnGUIContentsJustify(isSceneGUI, selectedBrushSurfaces); } if (!isSceneGUI) { EditorGUILayout.Space(); } GUILayout.BeginVertical(isSceneGUI ? GUI.skin.box : GUIStyle.none); { EditModeCommonGUI.OnSurfaceFlagButtons(selectedBrushSurfaces, isSceneGUI); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { EditorGUI.BeginDisabledGroup(!SurfaceUtility.CanSmooth(selectedBrushSurfaces)); { if (GUILayout.Button(ContentSmoothSurfaces, leftStyle)) { SurfaceUtility.Smooth(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipSmoothSurfaces); } EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(!SurfaceUtility.CanUnSmooth(selectedBrushSurfaces)); { if (GUILayout.Button(ContentUnSmoothSurfaces, rightStyle)) { SurfaceUtility.UnSmooth(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipUnSmoothSurfaces); } EditorGUI.EndDisabledGroup(); } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (!isSceneGUI) { EditorGUILayout.Space(); Material new_material; GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { EditorGUILayout.LabelField(ContentMaterial, largeLabelWidth); GUILayout.BeginVertical(CSG_GUIStyleUtility.ContentEmpty); { EditorGUI.BeginChangeCheck(); { EditorGUI.showMixedValue = multipleMaterials; new_material = EditorGUILayout.ObjectField(material, typeof(Material), true) as Material; EditorGUI.showMixedValue = false; } if (EditorGUI.EndChangeCheck()) { if (!new_material) { new_material = MaterialUtility.MissingMaterial; } SurfaceUtility.SetMaterials(selectedBrushSurfaces, new_material); } } GUILayout.Space(2); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { GUILayout.Space(5); OnGUIContentsMaterialImage(isSceneGUI, firstMaterial, multipleMaterials, selectedBrushSurfaces); } GUILayout.EndHorizontal(); GUILayout.EndVertical(); } GUILayout.EndHorizontal(); // Unity won't let us do this //GUILayout.BeginVertical(GUIStyleUtility.ContentEmpty); //OnGUIContentsMaterialInspector(first_material, multiple_materials); //GUILayout.EndVertical(); } } GUILayout.EndVertical(); } EditorGUI.EndDisabledGroup(); EditorGUI.showMixedValue = false; }
/// <summary>Generate a <see cref="RealtimeCSG.Legacy.ControlMesh"/>/<see cref="RealtimeCSG.Legacy.Shape"/> pair from the given planes (and optional other values)</summary> /// <remarks><note>Keep in mind that the planes encapsulate the geometry we're generating, so it can only be <i>convex</i>.</note></remarks> /// <param name="controlMesh">The generated <see cref="RealtimeCSG.Legacy.ControlMesh"/></param> /// <param name="shape">The generated <see cref="RealtimeCSG.Legacy.Shape"/></param> /// <param name="planes">The geometric planes of all the surfaces that define this convex shape</param> /// <param name="tangents">The tangents for each plane (optional)</param> /// <param name="binormals">The binormals for each plane (optional)</param> /// <param name="materials">The materials for each plane (optional)</param> /// <param name="textureMatrices">The texture matrices for each plane (optional)</param> /// <param name="textureMatrixSpace">The texture matrix space for each plane (optional)</param> /// <param name="smoothingGroups">The smoothing groups for each plane (optional)</param> /// <param name="texGenFlags">The <see cref="RealtimeCSG.Legacy.TexGenFlags"/> for each plane (optional)</param> /// <returns>*true* on success, *false* on failure</returns> public static bool CreateControlMeshFromPlanes(out ControlMesh controlMesh, out Shape shape, UnityEngine.Plane[] planes, UnityEngine.Vector3[] tangents = null, UnityEngine.Vector3[] binormals = null, UnityEngine.Material[] materials = null, UnityEngine.Matrix4x4[] textureMatrices = null, TextureMatrixSpace textureMatrixSpace = TextureMatrixSpace.WorldSpace, uint[] smoothingGroups = null, TexGenFlags[] texGenFlags = null) { controlMesh = null; shape = null; if (planes == null) { Debug.LogError("The planes array is not allowed to be null"); return(false); } if (planes.Length < 4) { Debug.LogError("The planes array must have at least 4 planes"); return(false); } if (materials == null) { materials = new Material[planes.Length]; for (int i = 0; i < materials.Length; i++) { materials[i] = CSGSettings.DefaultMaterial; } } if (planes.Length != materials.Length || (textureMatrices != null && planes.Length != textureMatrices.Length) || (tangents != null && tangents.Length != textureMatrices.Length) || (binormals != null && binormals.Length != textureMatrices.Length) || (smoothingGroups != null && smoothingGroups.Length != materials.Length)) { Debug.LogError("All non null arrays need to be of equal length"); return(false); } shape = new Shape(); shape.TexGenFlags = new TexGenFlags[planes.Length]; shape.Surfaces = new Surface[planes.Length]; shape.TexGens = new TexGen[planes.Length]; for (int i = 0; i < planes.Length; i++) { shape.Surfaces[i].Plane = new CSGPlane(planes[i].normal, -planes[i].distance); Vector3 tangent, binormal; if (tangents != null && binormals != null) { tangent = tangents[i]; binormal = binormals[i]; } else { GeometryUtility.CalculateTangents(planes[i].normal, out tangent, out binormal); } shape.Surfaces[i].Tangent = -tangent; shape.Surfaces[i].BiNormal = -binormal; shape.Surfaces[i].TexGenIndex = i; shape.TexGens[i] = new TexGen(materials[i]); if (smoothingGroups != null) { shape.TexGens[i].SmoothingGroup = smoothingGroups[i]; } if (texGenFlags != null) { shape.TexGenFlags[i] = texGenFlags[i]; } else { shape.TexGenFlags[i] = RealtimeCSG.CSGSettings.DefaultTexGenFlags; } } controlMesh = ControlMeshUtility.CreateFromShape(shape, MathConstants.DistanceEpsilon); if (controlMesh == null) { return(false); } if (!ControlMeshUtility.Validate(controlMesh, shape)) { //Debug.LogError("Generated mesh is not valid"); return(false); } if (textureMatrices != null) { int n = 0; for (var i = 0; i < planes.Length; i++) { if (shape.Surfaces[n].TexGenIndex != i) { continue; } shape.Surfaces[n].TexGenIndex = n; SurfaceUtility.AlignTextureSpaces(textureMatrices[i], textureMatrixSpace == TextureMatrixSpace.PlaneSpace, ref shape.TexGens[n], ref shape.TexGenFlags[n], ref shape.Surfaces[n]); n++; } } return(true); }
private bool GenerateStairs(CSGBrush[] stepBrushes, int totalSteps, float stepLength, float stepHeight, float stepDepth, float stairsDepth, float stairsWidth, float stairsHeight, float extraDepth, float extraHeight, StairsBottom stairsBottom) { //var currentModel = parentModel ? parentModel : SelectionUtility.LastUsedModel; //var modelRotation = Quaternion.Inverse(currentModel.transform.rotation); stairsDepth = Math.Max(0, stairsDepth); bool success = true; for (int stepIndex = 0; stepIndex < totalSteps; stepIndex++) { var brush = stepBrushes[stepIndex]; if (!brush) { continue; } float curStepDepth; float curStepHeight; float curStepY; Vector3 extraLength; Vector3 lengthPos; switch (stairsBottom) { default: case StairsBottom.Filled: { curStepHeight = Mathf.Min(stairsHeight, (stepIndex == 0) ? (extraHeight + stepHeight) : stepHeight); curStepY = (stepIndex == 0) ? (stepHeight * stepIndex) : (extraHeight + (stepHeight * stepIndex)); extraLength = lengthDirection * (stepLength * stepIndex); curStepDepth = stairsDepth; lengthPos = Vector3.zero; break; } case StairsBottom.Steps: { curStepHeight = stepHeight; curStepY = extraHeight + (stepHeight * stepIndex); extraLength = Vector3.zero; curStepDepth = (stepIndex == totalSteps - 1) ? (stepDepth + extraDepth) : stepDepth; lengthPos = (stepIndex == totalSteps - 1) ? Vector3.zero : (lengthDirection * Mathf.Max(0, ((totalSteps - (stepIndex + 1)) * stepDepth) + extraDepth)); break; } } var heightPos = heightDirection * curStepY; var widthSize = (widthDirection * stairsWidth); var lengthSize = (lengthDirection * curStepDepth) - extraLength; var heightSize = (heightDirection * curStepHeight); var size = widthSize + heightSize + lengthSize; var position = (totalSteps == 1) ? (heightPos + lengthPos + brushPosition) : (heightPos + lengthPos); ControlMesh newControlMesh; Shape newShape; if (!BrushFactory.CreateCubeControlMesh(out newControlMesh, out newShape, Vector3.zero, size)) { success = false; if (brush.gameObject.activeSelf) { brush.gameObject.SetActive(false); } continue; } if (!brush.gameObject.activeSelf) { brush.gameObject.SetActive(true); } brush.Shape = newShape; brush.ControlMesh = newControlMesh; if (totalSteps != 1) { brush.transform.localPosition = position; } //brush.transform.localRotation = Quaternion.identity; SurfaceUtility.TranslateSurfacesInWorldSpace(brush, -position); } return(success); }
public static void OnSurfaceFlagButtons(SelectedBrushSurface[] selectedBrushSurfaces, bool isSceneGUI = false) { var leftStyle = isSceneGUI ? EditorStyles.miniButtonLeft : GUI.skin.button; var middleStyle = isSceneGUI ? EditorStyles.miniButtonMid : GUI.skin.button; var rightStyle = isSceneGUI ? EditorStyles.miniButtonRight : GUI.skin.button; var canDiscard = false; var canMakeShadowOnly = false; var canMakeVisible = false; if (selectedBrushSurfaces.Length > 0) { for (var i = 0; i < selectedBrushSurfaces.Length; i++) { var brush = selectedBrushSurfaces[i].brush; var surfaceIndex = selectedBrushSurfaces[i].surfaceIndex; if (surfaceIndex >= brush.Shape.Surfaces.Length) { Debug.Log("surface_index >= brush.Shape.Surfaces.Length"); continue; } var texGenIndex = brush.Shape.Surfaces[surfaceIndex].TexGenIndex; if (texGenIndex >= brush.Shape.TexGens.Length) { Debug.Log("texGen_index >= brush.Shape.TexGens.Length"); continue; } var texGenFlags = brush.Shape.TexGenFlags[texGenIndex]; if ((texGenFlags & TexGenFlags.Discarded) == TexGenFlags.Discarded) { canMakeVisible = true; canMakeShadowOnly = true; } else if ((texGenFlags & TexGenFlags.ShadowOnly) == TexGenFlags.ShadowOnly) { canDiscard = true; canMakeVisible = true; } else { canDiscard = true; canMakeShadowOnly = true; } } } GUILayout.BeginHorizontal(GUIStyleUtility.ContentEmpty); { EditorGUI.BeginDisabledGroup(!canDiscard); { if (GUILayout.Button(ContentDiscardSurfaces, leftStyle)) { SurfaceUtility.DiscardSurfaces(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipDiscardSurfaces); } EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(!canMakeShadowOnly); { if (GUILayout.Button(ContentShadowOnlySurfaces, middleStyle)) { SurfaceUtility.MakeSurfacesShadowOnly(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipShadowOnlySurfaces); } EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup(!canMakeVisible); { if (GUILayout.Button(ContentVisibleSurfaces, rightStyle)) { SurfaceUtility.MakeSurfacesVisible(selectedBrushSurfaces); } TooltipUtility.SetToolTip(ToolTipVisibleSurfaces); } EditorGUI.EndDisabledGroup(); } GUILayout.EndHorizontal(); }
/* * public static bool ContinueTexGenFromSurfaceToSurface(CSGBrush srcBrush, int srcSurfaceIndex, CSGBrush dstBrush, int dstSurfaceIndex) * { * if (srcSurfaceIndex < 0 || srcSurfaceIndex >= srcBrush.Shape.Materials.Length || * srcBrush == null) * return false; * * var src_brush_cache = CSGModelManager.GetBrushCache(srcBrush); * if (src_brush_cache == null || * src_brush_cache.childData == null || * src_brush_cache.childData.modelTransform == null) * return false; * * var dst_brush_cache = CSGModelManager.GetBrushCache(dstBrush); * if (dst_brush_cache == null || * dst_brush_cache.childData == null || * dst_brush_cache.childData.modelTransform == null) * return false; * * var dstPlane = dstBrush.Shape.Surfaces[dstSurfaceIndex].Plane; * var srcPlane = srcBrush.Shape.Surfaces[srcSurfaceIndex].Plane; * * // convert planes into worldspace * dstPlane = GeometryUtility.InverseTransformPlane(dstBrush.transform.worldToLocalMatrix, dstPlane); * srcPlane = GeometryUtility.InverseTransformPlane(srcBrush.transform.worldToLocalMatrix, srcPlane); * * var dstNormal = dstPlane.normal; * var srcNormal = srcPlane.normal; * * var srcTexGenIndex = srcBrush.Shape.Surfaces[srcSurfaceIndex].TexGenIndex; * var dstTexGenIndex = dstBrush.Shape.Surfaces[dstSurfaceIndex].TexGenIndex; * * var scrShape = srcBrush.Shape; * * dstBrush.Shape.Materials[dstSurfaceIndex] = scrShape.Materials[srcSurfaceIndex]; * Vector3 srcPoint1, srcPoint2; * Vector3 dstPoint1, dstPoint2; * var edgeDirection = Vector3.Cross(dstNormal, srcNormal); * var det = edgeDirection.sqrMagnitude; * if (det < Constants.AlignmentTestEpsilon) * { * // Find 2 points on intersection of 2 planes * srcPoint1 = srcPlane.pointOnPlane; * srcPoint2 = GeometryUtility.ProjectPointOnPlane(srcPlane, srcPoint1 + MathConstants.oneVector3); * * dstPoint1 = GeometryUtility.ProjectPointOnPlane(dstPlane, srcPoint1); * dstPoint2 = GeometryUtility.ProjectPointOnPlane(dstPlane, srcPoint2); * } else * { * // Find 2 points on intersection of 2 planes * srcPoint1 = ((Vector3.Cross(edgeDirection, srcNormal) * -dstPlane.d) + * (Vector3.Cross(dstNormal, edgeDirection) * -srcPlane.d)) / det; * srcPoint2 = srcPoint1 + edgeDirection; * dstPoint1 = srcPoint1; * dstPoint2 = srcPoint2; * } * * Vector3 srcLocalPoint1 = srcBrush.transform.InverseTransformPoint(srcPoint1); * Vector3 srcLocalPoint2 = srcBrush.transform.InverseTransformPoint(srcPoint2); * * Vector3 dstLocalPoint1 = dstBrush.transform.InverseTransformPoint(dstPoint1); * Vector3 dstLocalPoint2 = dstBrush.transform.InverseTransformPoint(dstPoint2); * * var srcShape = srcBrush.Shape; * var srcTexGens = srcShape.TexGens; * var srcSurfaces = srcShape.Surfaces; * var dstShape = dstBrush.Shape; * var dstTexGens = dstShape.TexGens; * var dstSurfaces = dstShape.Surfaces; * * * // Reset destination shape to simplify calculations * dstTexGens[dstTexGenIndex].Scale = scrShape.TexGens[srcTexGenIndex].Scale; * dstTexGens[dstTexGenIndex].Translation = MathConstants.zeroVector2; * dstTexGens[dstTexGenIndex].RotationAngle = 0; * * if (!CSGModelManager.AlignTextureSpacesInLocalSpace(ref srcTexGens[srcTexGenIndex], ref srcSurfaces[srcSurfaceIndex], * srcLocalPoint1, srcLocalPoint2, * ref dstTexGens[dstTexGenIndex], ref dstSurfaces[dstSurfaceIndex], * dstLocalPoint1, dstLocalPoint2)) * return false; * return true; * } */ public static bool ContinueTexGenFromSurfaceToSurface(CSGBrush brush, int srcSurfaceIndex, int dstSurfaceIndex) { if (srcSurfaceIndex < 0 || srcSurfaceIndex >= brush.Shape.TexGens.Length || !brush) { return(false); } var shape = brush.Shape; var texGens = shape.TexGens; var texGenFlags = shape.TexGenFlags; var surfaces = shape.Surfaces; var srcTexGenIndex = surfaces[srcSurfaceIndex].TexGenIndex; var dstTexGenIndex = surfaces[dstSurfaceIndex].TexGenIndex; // var src_is_world_space = (texGenFlags[srcTexGenIndex] & TexGenFlags.WorldSpaceTexture) != TexGenFlags.None; // var dst_is_world_space = (texGenFlags[dstTexGenIndex] & TexGenFlags.WorldSpaceTexture) != TexGenFlags.None; // if (src_is_world_space) SurfaceUtility.SetTextureLock(brush, srcSurfaceIndex, true); // if (dst_is_world_space) SurfaceUtility.SetTextureLock(brush, dstSurfaceIndex, true); var dstLocalPlane = surfaces[dstSurfaceIndex].Plane; var srcLocalPlane = surfaces[srcSurfaceIndex].Plane; CSGModel parentModel; CSGOperation parentOp; InternalCSGModelManager.FindParentOperationAndModel(brush.transform, out parentOp, out parentModel); var localFromWorld = brush.transform.worldToLocalMatrix; var worldFromModel = parentModel.transform.localToWorldMatrix; var modelFromWorld = parentModel.transform.worldToLocalMatrix; var localFromModel = localFromWorld * worldFromModel; //var localToWorldMatrix = brush.transform.localToWorldMatrix; // convert planes into worldspace var dstWorldPlane = InverseTransformPlane(localFromWorld, dstLocalPlane); var srcWorldPlane = InverseTransformPlane(localFromWorld, srcLocalPlane); var dstWorldNormal = dstWorldPlane.normal; var srcWorldNormal = srcWorldPlane.normal; shape.TexGens[dstSurfaceIndex].RenderMaterial = shape.TexGens[srcSurfaceIndex].RenderMaterial; Vector3 srcWorldPoint1, srcWorldPoint2; Vector3 dstWorldPoint1, dstWorldPoint2; var edgeDirection = Vector3.Cross(dstWorldNormal, srcWorldNormal); var det = edgeDirection.sqrMagnitude; if (det < MathConstants.AlignmentTestEpsilon) { // Find 2 points on intersection of 2 planes srcWorldPoint1 = srcWorldPlane.pointOnPlane; srcWorldPoint2 = GeometryUtility.ProjectPointOnPlane(srcWorldPlane, srcWorldPoint1 + MathConstants.oneVector3); dstWorldPoint1 = GeometryUtility.ProjectPointOnPlane(dstWorldPlane, srcWorldPoint1); dstWorldPoint2 = GeometryUtility.ProjectPointOnPlane(dstWorldPlane, srcWorldPoint2); } else { // Find 2 points on intersection of 2 planes srcWorldPoint1 = ((Vector3.Cross(edgeDirection, srcWorldNormal) * -dstWorldPlane.d) + (Vector3.Cross(dstWorldNormal, edgeDirection) * -srcWorldPlane.d)) / det; srcWorldPoint2 = srcWorldPoint1 + edgeDirection; dstWorldPoint1 = srcWorldPoint1; dstWorldPoint2 = srcWorldPoint2; } var srcModelPoint1 = modelFromWorld.MultiplyPoint(srcWorldPoint1); var srcModelPoint2 = modelFromWorld.MultiplyPoint(srcWorldPoint2); var dstModelPoint1 = modelFromWorld.MultiplyPoint(dstWorldPoint1); var dstModelPoint2 = modelFromWorld.MultiplyPoint(dstWorldPoint2); var result = SurfaceUtility.AlignTextureSpaces(localFromModel, texGens[srcTexGenIndex], texGenFlags[srcTexGenIndex], ref surfaces[srcSurfaceIndex], srcModelPoint1, srcModelPoint2, localFromModel, ref texGens[dstTexGenIndex], texGenFlags[dstTexGenIndex], ref surfaces[dstSurfaceIndex], dstModelPoint1, dstModelPoint2, false, Vector3.one); // if (src_is_world_space) SurfaceUtility.SetTextureLock(brush, srcSurfaceIndex, false); // if (dst_is_world_space) SurfaceUtility.SetTextureLock(brush, dstSurfaceIndex, false); return(result); }
private bool GenerateSphere(float radius, int splits, CSGModel parentModel, CSGBrush brush, out ControlMesh controlMesh, out Shape shape) { if (prevSplits != splits || prevIsHemisphere != IsHemiSphere || splitControlMesh == null || splitShape == null) { splitControlMesh = null; splitShape = null; BrushFactory.CreateCubeControlMesh(out splitControlMesh, out splitShape, Vector3.one); var axi = new Vector3[] { MathConstants.upVector3, MathConstants.leftVector3, MathConstants.forwardVector3 }; List<int> intersectedEdges = new List<int>(); float step = 1.0f / (float)(splits + 1); float offset; for (int i = 0; i < axi.Length; i++) { var normal = axi[i]; offset = 0.5f - step; while (offset > 0.0f) { ControlMeshUtility.CutMesh(splitControlMesh, splitShape, new CSGPlane(-normal, -offset), ref intersectedEdges); if (i != 0 || !IsHemiSphere) { ControlMeshUtility.CutMesh(splitControlMesh, splitShape, new CSGPlane(normal, -offset), ref intersectedEdges); } offset -= step; } if (i != 0 || !IsHemiSphere) { if ((splits & 1) == 1) ControlMeshUtility.CutMesh(splitControlMesh, splitShape, new CSGPlane(normal, 0), ref intersectedEdges); } } if (IsHemiSphere) { var cuttingPlane = new CSGPlane(MathConstants.upVector3, 0); intersectedEdges.Clear(); if (ControlMeshUtility.CutMesh(splitControlMesh, splitShape, cuttingPlane, ref intersectedEdges)) { var edge_loop = ControlMeshUtility.FindEdgeLoop(splitControlMesh, ref intersectedEdges); if (edge_loop != null) { if (ControlMeshUtility.SplitEdgeLoop(splitControlMesh, splitShape, edge_loop)) { Shape foundShape; ControlMesh foundControlMesh; ControlMeshUtility.FindAndDetachSeparatePiece(splitControlMesh, splitShape, cuttingPlane, out foundControlMesh, out foundShape); } } } } // Spherize the cube for (int i = 0; i < splitControlMesh.Vertices.Length; i++) { Vector3 v = splitControlMesh.Vertices[i] * 2.0f; float x2 = v.x * v.x; float y2 = v.y * v.y; float z2 = v.z * v.z; Vector3 s; s.x = v.x * Mathf.Sqrt(1f - (y2 * 0.5f) - (z2 * 0.5f) + ((y2 * z2) / 3.0f)); s.y = v.y * Mathf.Sqrt(1f - (z2 * 0.5f) - (x2 * 0.5f) + ((z2 * x2) / 3.0f)); s.z = v.z * Mathf.Sqrt(1f - (x2 * 0.5f) - (y2 * 0.5f) + ((x2 * y2) / 3.0f)); splitControlMesh.Vertices[i] = s;//(splitControlMesh.Vertices[i] * 0.75f) + (splitControlMesh.Vertices[i].normalized * 0.25f); } if (!ControlMeshUtility.Triangulate(null, splitControlMesh, splitShape)) { Debug.LogWarning("!ControlMeshUtility.IsConvex"); controlMesh = null; shape = null; return false; } ControlMeshUtility.FixTexGens(splitControlMesh, splitShape); if (!ControlMeshUtility.IsConvex(splitControlMesh, splitShape)) { Debug.LogWarning("!ControlMeshUtility.IsConvex"); controlMesh = null; shape = null; return false; } ControlMeshUtility.UpdateTangents(splitControlMesh, splitShape); prevSplits = splits; prevIsHemisphere = IsHemiSphere; } if (splitControlMesh == null || splitShape == null || !splitControlMesh.Valid) { Debug.LogWarning("splitControlMesh == null || splitShape == null || !splitControlMesh.IsValid"); controlMesh = null; shape = null; return false; } controlMesh = splitControlMesh.Clone(); shape = splitShape.Clone(); /* float angle_offset = GeometryUtility.SignedAngle(gridTangent, delta / sphereRadius, buildPlane.normal); angle_offset -= 90; angle_offset += sphereOffset; angle_offset *= Mathf.Deg2Rad; Vector3 p1 = MathConstants.zeroVector3; for (int i = 0; i < realSplits; i++) { var angle = ((i * Mathf.PI * 2.0f) / (float)realSplits) + angle_offset; p1.x = (Mathf.Sin(angle) * sphereRadius); p1.z = (Mathf.Cos(angle) * sphereRadius); } */ for (int i = 0; i < controlMesh.Vertices.Length; i++) { var vertex = controlMesh.Vertices[i]; vertex *= radius; controlMesh.Vertices[i] = vertex; } for (int i = 0; i < shape.Surfaces.Length; i++) { var plane = shape.Surfaces[i].Plane; plane.d *= radius; shape.Surfaces[i].Plane = plane; } bool smoothShading = SphereSmoothShading; if (!sphereSmoothingGroup.HasValue && smoothShading) { sphereSmoothingGroup = SurfaceUtility.FindUnusedSmoothingGroupIndex(); } for (int i = 0; i < shape.TexGenFlags.Length; i++) { shape.TexGens[i].SmoothingGroup = smoothShading ? sphereSmoothingGroup.Value : 0; } var defaultTexGen = new TexGen(); defaultTexGen.Scale = MathConstants.oneVector3; //defaultTexGen.Color = Color.white; var fakeSurface = new Surface(); fakeSurface.TexGenIndex = 0; var defaultMaterial = CSGSettings.DefaultMaterial; for (var s = 0; s < shape.Surfaces.Length; s++) { var texGenIndex = shape.Surfaces[s].TexGenIndex; var axis = GeometryUtility.SnapToClosestAxis(shape.Surfaces[s].Plane.normal); var rotation = Quaternion.FromToRotation(axis, MathConstants.backVector3); var matrix = Matrix4x4.TRS(MathConstants.zeroVector3, rotation, MathConstants.oneVector3); SurfaceUtility.AlignTextureSpaces(matrix, false, ref shape.TexGens[texGenIndex], ref shape.TexGenFlags[texGenIndex], ref shape.Surfaces[s]); shape.TexGens[texGenIndex].RenderMaterial = defaultMaterial; } return true; }
public static bool GenerateControlMeshFromVertices(ShapePolygon shape2DPolygon, Matrix4x4 localToWorld, Vector3 direction, float height, Material capMaterial, TexGen capTexgen, bool?smooth, bool singleSurfaceEnds, //Plane buildPlane, out ControlMesh controlMesh, out Shape shape) { if (shape2DPolygon == null) { controlMesh = null; shape = null; return(false); } var vertices = shape2DPolygon.Vertices; if (vertices.Length < 3) { controlMesh = null; shape = null; return(false); } if (height == 0.0f) { controlMesh = null; shape = null; return(false); } Vector3 from; Vector3 to; if (height > 0) { @from = direction * height; // buildPlane.normal * height; to = MathConstants.zeroVector3; } else { @from = MathConstants.zeroVector3; to = direction * height; //buildPlane.normal * height; } var count = vertices.Length; var doubleCount = (count * 2); var extraPoints = 0; var extraEdges = 0; var endsPolygons = 2; var startEdgeOffset = doubleCount; if (!singleSurfaceEnds) { extraPoints = 2; extraEdges = (4 * count); endsPolygons = doubleCount; startEdgeOffset += extraEdges; } var dstPoints = new Vector3 [doubleCount + extraPoints]; var dstEdges = new HalfEdge[(count * 6) + extraEdges]; var dstPolygons = new Polygon [count + endsPolygons]; var center1 = MathConstants.zeroVector3; var center2 = MathConstants.zeroVector3; for (int i = 0; i < count; i++) { var point1 = vertices[i]; var point2 = vertices[(count + i - 1) % count]; point1 += @from; point2 += to; // swap y/z to solve texgen issues dstPoints[i].x = point1.x; dstPoints[i].y = point1.y; dstPoints[i].z = point1.z; center1 += dstPoints[i]; dstEdges [i].VertexIndex = (short)i; dstEdges [i].HardEdge = true; // swap y/z to solve texgen issues dstPoints[i + count].x = point2.x; dstPoints[i + count].y = point2.y; dstPoints[i + count].z = point2.z; center2 += dstPoints[i + count]; dstEdges [i + count].VertexIndex = (short)(i + count); dstEdges [i + count].HardEdge = true; } if (!singleSurfaceEnds) { dstPoints[doubleCount] = center1 / count; dstPoints[doubleCount + 1] = center2 / count; int edge_offset = doubleCount; short polygon_index = (short)count; // 'top' for (int i = 0, j = count - 1; i < count; j = i, i++) { var jm = (j) % count; var im = (i) % count; var edgeOut0 = edge_offset + (jm * 2) + 1; var edgeIn0 = edge_offset + (im * 2) + 0; var edgeOut1 = edge_offset + (im * 2) + 1; dstEdges[edgeIn0].VertexIndex = (short)(doubleCount); dstEdges[edgeIn0].HardEdge = true; dstEdges[edgeIn0].TwinIndex = edgeOut1; dstEdges[edgeOut1].VertexIndex = (short)im; dstEdges[edgeOut1].HardEdge = true; dstEdges[edgeOut1].TwinIndex = edgeIn0; dstEdges[im].PolygonIndex = polygon_index; dstEdges[edgeIn0].PolygonIndex = polygon_index; dstEdges[edgeOut0].PolygonIndex = polygon_index; dstPolygons[polygon_index] = new Polygon(new int[] { im, edgeIn0, edgeOut0 }, polygon_index); polygon_index++; } edge_offset = doubleCount * 2; // 'bottom' for (int i = 0, j = count - 1; j >= 0; i = j, j--) { var jm = (count + count - j) % count; var im = (count + count - i) % count; var edgeOut0 = edge_offset + (jm * 2) + 1; var edgeIn0 = edge_offset + (im * 2) + 0; var edgeOut1 = edge_offset + (im * 2) + 1; dstEdges[edgeIn0].VertexIndex = (short)(doubleCount + 1); dstEdges[edgeIn0].HardEdge = true; dstEdges[edgeIn0].TwinIndex = edgeOut1; dstEdges[edgeOut1].VertexIndex = (short)(im + count); dstEdges[edgeOut1].HardEdge = true; dstEdges[edgeOut1].TwinIndex = edgeIn0; dstEdges[im + count].PolygonIndex = polygon_index; dstEdges[edgeIn0].PolygonIndex = polygon_index; dstEdges[edgeOut0].PolygonIndex = polygon_index; dstPolygons[polygon_index] = new Polygon(new int[] { im + count, edgeIn0, edgeOut0 }, polygon_index); polygon_index++; } } else { var polygon0Edges = new int[count]; var polygon1Edges = new int[count]; for (var i = 0; i < count; i++) { dstEdges [i].PolygonIndex = (short)(count + 0); dstEdges [i + count].PolygonIndex = (short)(count + 1); polygon0Edges[i] = i; polygon1Edges[count - (i + 1)] = i + count; } dstPolygons[count + 0] = new Polygon(polygon0Edges, count + 0); dstPolygons[count + 1] = new Polygon(polygon1Edges, count + 1); } for (int v0 = count - 1, v1 = 0; v1 < count; v0 = v1, v1++) { var polygonIndex = (short)(v1); var nextOffset = startEdgeOffset + (((v1 + 1) % count) * 4); var currOffset = startEdgeOffset + (((v1)) * 4); var prevOffset = startEdgeOffset + (((v1 + count - 1) % count) * 4); var nextTwin = nextOffset + 1; var prevTwin = prevOffset + 3; dstEdges[v1].TwinIndex = currOffset + 0; dstEdges[v1 + count].TwinIndex = currOffset + 2; dstEdges[currOffset + 0].PolygonIndex = polygonIndex; dstEdges[currOffset + 1].PolygonIndex = polygonIndex; dstEdges[currOffset + 2].PolygonIndex = polygonIndex; dstEdges[currOffset + 3].PolygonIndex = polygonIndex; dstEdges[currOffset + 0].TwinIndex = (v1); dstEdges[currOffset + 1].TwinIndex = prevTwin; dstEdges[currOffset + 2].TwinIndex = (v1 + count); dstEdges[currOffset + 3].TwinIndex = nextTwin; dstEdges[currOffset + 0].VertexIndex = (short)(v0); dstEdges[currOffset + 1].VertexIndex = (short)(v1 + count); dstEdges[currOffset + 2].VertexIndex = (short)(((v1 + 1) % count) + count); dstEdges[currOffset + 3].VertexIndex = (short)(v1); dstEdges[currOffset + 0].HardEdge = true; dstEdges[currOffset + 1].HardEdge = true; dstEdges[currOffset + 2].HardEdge = true; dstEdges[currOffset + 3].HardEdge = true; dstPolygons[polygonIndex] = new Polygon(new [] { currOffset + 0, currOffset + 1, currOffset + 2, currOffset + 3 }, polygonIndex); } for (int i = 0; i < dstPoints.Length; i++) { dstPoints[i] = localToWorld.MultiplyPoint(dstPoints[i]); } controlMesh = new ControlMesh { Vertices = dstPoints, Edges = dstEdges, Polygons = dstPolygons }; controlMesh.SetDirty(); shape = new Shape { Materials = new Material[dstPolygons.Length], Surfaces = new Surface[dstPolygons.Length], TexGenFlags = new TexGenFlags[dstPolygons.Length], TexGens = new TexGen[dstPolygons.Length] }; var smoothinggroup = (smooth.HasValue && smooth.Value) ? SurfaceUtility.FindUnusedSmoothingGroupIndex() : 0; var containedMaterialCount = 0; if (shape2DPolygon.EdgeMaterials != null && shape2DPolygon.EdgeTexgens != null /* && * shape2DPolygon.edgeTexgenFlags != null*/) { containedMaterialCount = Mathf.Min(shape2DPolygon.EdgeMaterials.Length, shape2DPolygon.EdgeTexgens.Length /*, * shape2DPolygon.edgeTexgenFlags.Length*/); } if (!capMaterial) { capMaterial = CSGSettings.DefaultMaterial; capTexgen = new TexGen(-1); } for (var i = 0; i < dstPolygons.Length; i++) { if (i < containedMaterialCount) { //shape.TexGenFlags[i] = shape2DPolygon.edgeTexgenFlags[i]; shape.Materials [i] = shape2DPolygon.EdgeMaterials[i]; shape.TexGens [i] = shape2DPolygon.EdgeTexgens[i]; shape.Surfaces [i].TexGenIndex = i; shape.TexGens[i].MaterialIndex = -1; } else { shape.Materials[i] = capMaterial; shape.TexGens[i] = capTexgen; //shape.TexGenFlags[i] = TexGenFlags.None; shape.Surfaces[i].TexGenIndex = i; shape.TexGens[i].MaterialIndex = -1; } if (smooth.HasValue) { if (i < count) { shape.TexGens[i].SmoothingGroup = smoothinggroup; } else { shape.TexGens[i].SmoothingGroup = 0; } } } for (var s = 0; s < dstPolygons.Length; s++) { var normal = shape.Surfaces[s].Plane.normal; shape.Surfaces[s].Plane = GeometryUtility.CalcPolygonPlane(controlMesh, (short)s); Vector3 tangent, binormal; GeometryUtility.CalculateTangents(normal, out tangent, out binormal); //var tangent = Vector3.Cross(GeometryUtility.CalculateTangent(normal), normal).normalized; //var binormal = Vector3.Cross(normal, tangent); shape.Surfaces[s].Tangent = tangent; shape.Surfaces[s].BiNormal = binormal; shape.Surfaces[s].TexGenIndex = s; } controlMesh.IsValid = ControlMeshUtility.Validate(controlMesh, shape); if (controlMesh.IsValid) { return(true); } controlMesh = null; shape = null; return(false); }
static void OnGUIContentsJustify(bool isSceneGUI, SelectedBrushSurface[] selectedBrushSurfaces) { GUILayout.BeginVertical(CSG_GUIStyleUtility.ContentEmpty); { if (!isSceneGUI) { GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); EditorGUILayout.LabelField(ContentJustifyLabel, largeLabelWidth); } else { GUILayout.Label(ContentJustifyLabel); } GUILayout.BeginVertical(CSG_GUIStyleUtility.ContentEmpty); { GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (GUILayout.Button(ContentJustifyUpLeft, justifyButtonLayout)) { SurfaceUtility.JustifyLayout(selectedBrushSurfaces, -1, -1); } TooltipUtility.SetToolTip(ToolTipJustifyUpLeft); if (GUILayout.Button(ContentJustifyUp, justifyButtonLayout)) { SurfaceUtility.JustifyLayoutY(selectedBrushSurfaces, -1); } TooltipUtility.SetToolTip(ToolTipJustifyUp); if (GUILayout.Button(ContentJustifyUpRight, justifyButtonLayout)) { SurfaceUtility.JustifyLayout(selectedBrushSurfaces, 1, -1); } TooltipUtility.SetToolTip(ToolTipJustifyUpRight); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (GUILayout.Button(ContentJustifyLeft, justifyButtonLayout)) { SurfaceUtility.JustifyLayoutX(selectedBrushSurfaces, -1); } TooltipUtility.SetToolTip(ToolTipJustifyLeft); if (GUILayout.Button(ContentJustifyCenter, justifyButtonLayout)) { SurfaceUtility.JustifyLayout(selectedBrushSurfaces, 0, 0); } TooltipUtility.SetToolTip(ToolTipJustifyCenter); if (GUILayout.Button(ContentJustifyRight, justifyButtonLayout)) { SurfaceUtility.JustifyLayoutX(selectedBrushSurfaces, 1); } TooltipUtility.SetToolTip(ToolTipJustifyRight); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(CSG_GUIStyleUtility.ContentEmpty); { if (GUILayout.Button(ContentJustifyDownLeft, justifyButtonLayout)) { SurfaceUtility.JustifyLayout(selectedBrushSurfaces, -1, 1); } TooltipUtility.SetToolTip(ToolTipJustifyDownLeft); if (GUILayout.Button(ContentJustifyDown, justifyButtonLayout)) { SurfaceUtility.JustifyLayoutY(selectedBrushSurfaces, 1); } TooltipUtility.SetToolTip(ToolTipJustifyDown); if (GUILayout.Button(ContentJustifyDownRight, justifyButtonLayout)) { SurfaceUtility.JustifyLayout(selectedBrushSurfaces, 1, 1); } TooltipUtility.SetToolTip(ToolTipJustifyDownRight); } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); if (!isSceneGUI) { GUILayout.EndHorizontal(); } } GUILayout.EndVertical(); }
public override void Invalidate(bool 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; // } // //////////////////////////////////////////////////////////////////// Bounds csgBounds = new Bounds(); // nothing to do except copy csg information to our child brushes. if (!isDirty) { for (int i = 0; i < BrushCount; i++) { generatedBrushes[i].Mode = this.Mode; generatedBrushes[i].IsNoCSG = this.IsNoCSG; generatedBrushes[i].IsVisible = this.IsVisible; generatedBrushes[i].HasCollision = this.HasCollision; generatedBrushes[i].Invalidate(true); csgBounds.Encapsulate(generatedBrushes[i].GetBounds()); } // apply the generated csg bounds. localBounds = csgBounds; m_LastKnownExtents = localBounds.extents; m_LastKnownPosition = transform.localPosition; return; } base.Invalidate(polygonsChanged); isDirty = false; // build the polygons from the project. if (m_LastBuiltPolygons == null) { m_LastBuiltPolygons = BuildConvexPolygons(); } // iterate through the brushes we received: int brushCount = BrushCount; // force nocsg when creating a flat polygon sheet as sabrecsg doesn't support it. if (extrudeMode == ExtrudeMode.CreatePolygon) { this.IsNoCSG = true; } 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; // local variables. Quaternion rot; Polygon[] outputPolygons; switch (extrudeMode) { // generate a flat 2d polygon. case ExtrudeMode.CreatePolygon: GenerateNormals(m_LastBuiltPolygons[i]); GenerateUvCoordinates(m_LastBuiltPolygons[i], false); Polygon poly1 = m_LastBuiltPolygons[i].DeepCopy(); poly1.Flip(); generatedBrushes[i].SetPolygons(new Polygon[] { poly1 }); break; // generate 3d cube-ish shapes that revolve around the pivot. case ExtrudeMode.RevolveShape: int labpIndex = i % m_LastBuiltPolygons.Count; Polygon poly2 = m_LastBuiltPolygons[labpIndex].DeepCopy(); poly2.Flip(); GenerateUvCoordinates(poly2, false); foreach (Vertex v in poly2.Vertices) { float step = 360.0f / project.revolve360; v.Position = RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, (project.revolveDirection ? 0 : 180) + ((i / m_LastBuiltPolygons.Count) * step), 0.0f)); } Polygon nextPoly = m_LastBuiltPolygons[labpIndex].DeepCopy(); nextPoly.Flip(); foreach (Vertex v in nextPoly.Vertices) { float step = 360.0f / project.revolve360; v.Position = RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, (project.revolveDirection ? 0 : 180) + (((i / m_LastBuiltPolygons.Count) * step) + step), 0.0f)); } GenerateNormals(poly2); List <Polygon> polygons = new List <Polygon>() { poly2 }; List <Vertex> backPolyVertices = new List <Vertex>(); Edge[] myEdges = poly2.GetEdges(); Edge[] nextEdges = nextPoly.GetEdges(); for (int j = 0; j < myEdges.Length; j++) { Edge myEdge = myEdges[j]; Edge nextEdge = nextEdges[j]; Polygon newPoly = new Polygon(new Vertex[] { new Vertex(myEdge.Vertex1.Position, Vector3.zero, Vector2.zero), new Vertex(nextEdge.Vertex1.Position, Vector3.zero, Vector2.zero), new Vertex(nextEdge.Vertex2.Position, Vector3.zero, Vector2.zero), new Vertex(myEdge.Vertex2.Position, Vector3.zero, Vector2.zero), }, null, false, false); backPolyVertices.Add(nextEdge.Vertex1); GenerateNormals(newPoly); if (newPoly.Plane.normal == Vector3.zero) { continue; // discard single line, can happen in the center of the shape. } GenerateUvCoordinates(newPoly, false); polygons.Add(newPoly); } Polygon backPoly = new Polygon(backPolyVertices.ToArray(), null, false, false); backPoly.Flip(); GenerateNormals(backPoly); GenerateUvCoordinates(backPoly, false); polygons.Add(backPoly); generatedBrushes[i].SetPolygons(polygons.ToArray()); break; // generate a 3d cube-ish shape. case ExtrudeMode.ExtrudeShape: GenerateNormals(m_LastBuiltPolygons[i]); SurfaceUtility.ExtrudePolygon(m_LastBuiltPolygons[i], project.extrudeDepth, out outputPolygons, out rot); foreach (Polygon poly in outputPolygons) { GenerateUvCoordinates(poly, false); } generatedBrushes[i].SetPolygons(outputPolygons); break; // generate a 3d cone-ish shape. case ExtrudeMode.ExtrudePoint: GenerateNormals(m_LastBuiltPolygons[i]); ExtrudePolygonToPoint(m_LastBuiltPolygons[i], project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot); foreach (Polygon poly in outputPolygons) { GenerateUvCoordinates(poly, false); } generatedBrushes[i].SetPolygons(outputPolygons); break; // generate a 3d trapezoid-ish shape. case ExtrudeMode.ExtrudeBevel: GenerateNormals(m_LastBuiltPolygons[i]); ExtrudePolygonBevel(m_LastBuiltPolygons[i], project.extrudeDepth, project.extrudeClipDepth / project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot); foreach (Polygon poly in outputPolygons) { GenerateUvCoordinates(poly, false); } generatedBrushes[i].SetPolygons(outputPolygons); break; } 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 override void Invalidate(bool 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; // } // //////////////////////////////////////////////////////////////////// Bounds csgBounds = new Bounds(); // force nocsg when creating a flat polygon sheet as sabrecsg doesn't support it. if (extrudeMode == ExtrudeMode.CreatePolygon) { this.IsNoCSG = true; } // force nocsg when revolving with a sloped spiral as there are non-planar polygons. if (extrudeMode == ExtrudeMode.RevolveShape && project.revolveSpiralSloped && project.globalPivot.position.y != 0) { this.IsNoCSG = true; } // nothing to do except copy csg information to our child brushes. if (!isDirty) { for (int i = 0; i < BrushCount; i++) { generatedBrushes[i].Mode = this.Mode; generatedBrushes[i].IsNoCSG = this.IsNoCSG; generatedBrushes[i].IsVisible = this.IsVisible; generatedBrushes[i].HasCollision = this.HasCollision; generatedBrushes[i].Invalidate(true); csgBounds.Encapsulate(generatedBrushes[i].GetBounds()); } // apply the generated csg bounds. localBounds = csgBounds; m_LastKnownExtents = localBounds.extents; m_LastKnownPosition = transform.localPosition; return; } base.Invalidate(polygonsChanged); isDirty = false; // build the polygons from the project. if (m_LastBuiltPolygons == null) { m_LastBuiltPolygons = BuildConvexPolygons(); } // 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; // local variables. Quaternion rot; Polygon[] outputPolygons; switch (extrudeMode) { // generate a flat 2d polygon. case ExtrudeMode.CreatePolygon: GenerateNormals(m_LastBuiltPolygons[i]); GenerateUvCoordinates(m_LastBuiltPolygons[i], false); Polygon poly1 = m_LastBuiltPolygons[i].DeepCopy(); poly1.Flip(); generatedBrushes[i].SetPolygons(new Polygon[] { poly1 }); break; // generate 3d cube-ish shapes that revolve around the pivot and spirals up or down. case ExtrudeMode.RevolveShape: float spiralHeight = ((((project.globalPivot.position.y * project.extrudeScale.y) / 8.0f) * (i / m_LastBuiltPolygons.Count)) / project.revolve360) * (project.revolve360 / project.revolveSteps); float spiralStep = ((((project.globalPivot.position.y * project.extrudeScale.y) / 8.0f)) / project.revolve360) * (project.revolve360 / project.revolveSteps); int labpIndex = i % m_LastBuiltPolygons.Count; Polygon poly2 = m_LastBuiltPolygons[labpIndex].DeepCopy(); poly2.Flip(); GenerateUvCoordinates(poly2, false); foreach (Vertex v in poly2.Vertices) { float step = 360.0f / project.revolve360; v.Position = new Vector3(0, -spiralHeight, 0) + RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, ((i / m_LastBuiltPolygons.Count) * step), 0.0f)); } GenerateNormals(poly2); Polygon nextPoly = m_LastBuiltPolygons[labpIndex].DeepCopy(); nextPoly.Flip(); foreach (Vertex v in nextPoly.Vertices) { float step = 360.0f / project.revolve360; v.Position = new Vector3(0, -spiralHeight - (project.revolveSpiralSloped ? spiralStep : 0), 0) + RotatePointAroundPivot(v.Position, new Vector3(((project.revolveDistance / 8.0f) * project.extrudeScale.x) + ((project.revolveRadius * project.extrudeScale.x) / 8.0f), 0.0f, 0.0f), new Vector3(0.0f, (((i / m_LastBuiltPolygons.Count) * step) + step), 0.0f)); } List <Polygon> polygons = new List <Polygon>() { poly2 }; List <Vertex> backPolyVertices = new List <Vertex>(); Edge[] myEdges = poly2.GetEdges(); Edge[] nextEdges = nextPoly.GetEdges(); for (int j = 0; j < myEdges.Length; j++) { Edge myEdge = myEdges[j]; Edge nextEdge = nextEdges[j]; Polygon newPoly = new Polygon(new Vertex[] { new Vertex(myEdge.Vertex1.Position, Vector3.zero, Vector2.zero), new Vertex(nextEdge.Vertex1.Position, Vector3.zero, Vector2.zero), new Vertex(nextEdge.Vertex2.Position, Vector3.zero, Vector2.zero), new Vertex(myEdge.Vertex2.Position, Vector3.zero, Vector2.zero), }, null, false, false); backPolyVertices.Add(nextEdge.Vertex1); GenerateNormals(newPoly); if (newPoly.Plane.normal == Vector3.zero) { continue; // discard single line, can happen in the center of the shape. } GenerateUvCoordinates(newPoly, false); polygons.Add(newPoly); } Polygon backPoly = new Polygon(backPolyVertices.ToArray(), null, false, false); backPoly.Flip(); GenerateNormals(backPoly); GenerateUvCoordinates(backPoly, false); polygons.Add(backPoly); generatedBrushes[i].SetPolygons(polygons.ToArray()); break; // generate a 3d cube-ish shape. case ExtrudeMode.ExtrudeShape: GenerateNormals(m_LastBuiltPolygons[i]); SurfaceUtility.ExtrudePolygon(m_LastBuiltPolygons[i], project.extrudeDepth, out outputPolygons, out rot); foreach (Polygon poly in outputPolygons) { GenerateUvCoordinates(poly, false); } generatedBrushes[i].SetPolygons(outputPolygons); break; // generate a 3d cone-ish shape. case ExtrudeMode.ExtrudePoint: GenerateNormals(m_LastBuiltPolygons[i]); ExtrudePolygonToPoint(m_LastBuiltPolygons[i], project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot); foreach (Polygon poly in outputPolygons) { GenerateUvCoordinates(poly, false); } generatedBrushes[i].SetPolygons(outputPolygons); break; // generate a 3d trapezoid-ish shape. case ExtrudeMode.ExtrudeBevel: GenerateNormals(m_LastBuiltPolygons[i]); ExtrudePolygonBevel(m_LastBuiltPolygons[i], project.extrudeDepth, project.extrudeClipDepth / project.extrudeDepth, new Vector2((project.globalPivot.position.x * project.extrudeScale.x) / 8.0f, -(project.globalPivot.position.y * project.extrudeScale.y) / 8.0f), out outputPolygons, out rot); foreach (Polygon poly in outputPolygons) { GenerateUvCoordinates(poly, false); } generatedBrushes[i].SetPolygons(outputPolygons); break; } // we invalidate every brush after hidden surface removal. } // we exclude hidden faces automatically. // this step will automatically optimize NoCSG output the same way additive brushes would have. // it also excludes a couple faces that CSG doesn't exclude due to floating point precision errors. // the latter is especially noticable with complex revolved shapes. // compare each brush to another brush: for (int i = 0; i < brushCount; i++) { for (int j = 0; j < brushCount; j++) { // can't check for hidden faces on the same brush. if (i == j) { continue; } // compare each polygon on brush i to each polygon on brush j: foreach (Polygon pa in generatedBrushes[i].GetPolygons()) { foreach (Polygon pb in generatedBrushes[j].GetPolygons()) { // check they both have this polygon: bool identical = true; foreach (Vertex va in pa.Vertices) { if (!pb.Vertices.Any(vb => vb.Position == va.Position)) { identical = false; break; } } // identical polygons on both brushes means it can be excluded: if (identical) { pa.UserExcludeFromFinal = true; pb.UserExcludeFromFinal = true; } } } } // invalidate every brush. generatedBrushes[i].Invalidate(true); csgBounds.Encapsulate(generatedBrushes[i].GetBounds()); } // apply the generated csg bounds. localBounds = csgBounds; m_LastKnownExtents = localBounds.extents; m_LastKnownPosition = transform.localPosition; // update the generated name in the hierarchy. UpdateGeneratedHierarchyName(); }