public void Validate() { if (surfaceDefinition == null) { surfaceDefinition = new ChiselSurfaceDefinition(); } stepHeight = Mathf.Max(kMinStepHeight, stepHeight); innerDiameter = Mathf.Min(outerDiameter - kMinStairsDepth, innerDiameter); innerDiameter = Mathf.Max(kMinInnerDiameter, innerDiameter); outerDiameter = Mathf.Max(innerDiameter + kMinStairsDepth, outerDiameter); outerDiameter = Mathf.Max(kMinOuterDiameter, outerDiameter); height = Mathf.Max(stepHeight, Mathf.Abs(height)) * (height < 0 ? -1 : 1); treadHeight = Mathf.Max(0, treadHeight); nosingDepth = Mathf.Max(0, nosingDepth); nosingWidth = Mathf.Max(0, nosingWidth); riserDepth = Mathf.Max(kMinRiserDepth, riserDepth); rotation = Mathf.Max(kMinRotation, Mathf.Abs(rotation)) * (rotation < 0 ? -1 : 1); innerSegments = Mathf.Max(kMinSegments, innerSegments); outerSegments = Mathf.Max(kMinSegments, outerSegments); surfaceDefinition.EnsureSize(8); }
public override void CalcBounds() { bounds.Center = Vector3.zero; bounds.Size = Size; var minY = -Size.y / 2; var maxY = Size.y / 2; var minX = float.MaxValue; var maxX = float.MinValue; var minZ = float.MaxValue; var maxZ = float.MinValue; var points = new Vector3[] { new Vector3(Size.x / 2, 0, Size.z / 2), new Vector3(-Size.x / 2, 0, -Size.z / 2), new Vector3(-Size.x / 2, 0, Size.z / 2), new Vector3(Size.x / 2, 0, -Size.z / 2) }; for (int i = 0; i < points.Length; i++) { points[i] = Quaternion * points[i]; minX = Mathf.Min(minX, points[i].x); maxX = Mathf.Max(maxX, points[i].x); minZ = Mathf.Min(minZ, points[i].z); maxZ = Mathf.Max(maxZ, points[i].z); } bounds.Min = new Vector3(minX, minY, minZ); bounds.Max = new Vector3(maxX, maxY, maxZ); bounds.Center = Position; }
public static int AmountPawnWantsToPickUp(Pawn p, Thing t, HaulExplicitlyPosting posting) { return(Mathf.Min(new int[] { posting.RecordWithItem(t).RemainingToHaul(), p.carryTracker.AvailableStackSpace(t.def), t.stackCount })); }
public void Validate() { stepHeight = Mathf.Max(kMinStepHeight, stepHeight); innerDiameter = Mathf.Min(outerDiameter - kMinStairsDepth, innerDiameter); innerDiameter = Mathf.Max(kMinInnerDiameter, innerDiameter); outerDiameter = Mathf.Max(innerDiameter + kMinStairsDepth, outerDiameter); outerDiameter = Mathf.Max(kMinOuterDiameter, outerDiameter); height = Mathf.Max(stepHeight, Mathf.Abs(height)) * (height < 0 ? -1 : 1); treadHeight = Mathf.Max(0, treadHeight); nosingDepth = Mathf.Max(0, nosingDepth); nosingWidth = Mathf.Max(0, nosingWidth); riserDepth = Mathf.Max(kMinRiserDepth, riserDepth); rotation = Mathf.Max(kMinRotation, Mathf.Abs(rotation)) * (rotation < 0 ? -1 : 1); innerSegments = Mathf.Max(kMinSegments, innerSegments); outerSegments = Mathf.Max(kMinSegments, outerSegments); if (surfaceAssets == null || surfaceAssets.Length != 6) { var defaultRenderMaterial = CSGMaterialManager.DefaultWallMaterial; var defaultPhysicsMaterial = CSGMaterialManager.DefaultPhysicsMaterial; surfaceAssets = new CSGSurfaceAsset[6]; for (int i = 0; i < 6; i++) // Note: sides share same material { surfaceAssets[i] = CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial); } } if (surfaceDescriptions == null || surfaceDescriptions.Length != 6) { var surfaceFlags = CSGDefaults.SurfaceFlags; surfaceDescriptions = new SurfaceDescription[6]; for (int i = 0; i < 6; i++) { surfaceDescriptions[i] = new SurfaceDescription { surfaceFlags = surfaceFlags, UV0 = UVMatrix.centered, smoothingGroup = bottomSmoothingGroup }; } } else { for (int i = 0; i < 6; i++) { surfaceDescriptions[i].smoothingGroup = bottomSmoothingGroup; } } }
public static float Clamp(float x, float limit1, float limit2) { float max = Mathf.Max(limit1, limit2); float min = Mathf.Min(limit1, limit2); if (x < min) { return(min); } if (x > max) { return(max); } return(x); }
/** Clamps the velocity to the max speed and optionally the forwards direction. * \param velocity Desired velocity of the character. In world units per second. * \param maxSpeed Max speed of the character. In world units per second. * \param slowdownFactor Value between 0 and 1 which determines how much slower the character should move than normal. * Normally 1 but should go to 0 when the character approaches the end of the path. * \param slowWhenNotFacingTarget Prevent the velocity from being too far away from the forward direction of the character * and slow the character down if the desired velocity is not in the same direction as the forward vector. * \param forward Forward direction of the character. Used together with the \a slowWhenNotFacingTarget parameter. * * Note that all vectors are 2D vectors, not 3D vectors. * * \returns The clamped velocity in world units per second. */ public static Vector2 ClampVelocity(Vector2 velocity, float maxSpeed, float slowdownFactor, bool slowWhenNotFacingTarget, Vector2 forward) { // Max speed to use for this frame var currentMaxSpeed = maxSpeed * slowdownFactor; // Check if the agent should slow down in case it is not facing the direction it wants to move in if (slowWhenNotFacingTarget && (forward.x != 0 || forward.y != 0)) { float currentSpeed; var normalizedVelocity = VectorMath.Normalize(velocity.ToPFV2(), out currentSpeed); float dot = Vector2.Dot(normalizedVelocity.ToUnityV2(), forward); // Lower the speed when the character's forward direction is not pointing towards the desired velocity // 1 when velocity is in the same direction as forward // 0.2 when they point in the opposite directions float directionSpeedFactor = Mathf.Clamp(dot + 0.707f, 0.2f, 1.0f); currentMaxSpeed *= directionSpeedFactor; currentSpeed = Mathf.Min(currentSpeed, currentMaxSpeed); // Angle between the forwards direction of the character and our desired velocity float angle = Mathf.Acos(Mathf.Clamp(dot, -1, 1)); // Clamp the angle to 20 degrees // We cannot keep the velocity exactly in the forwards direction of the character // because we use the rotation to determine in which direction to rotate and if // the velocity would always be in the forwards direction of the character then // the character would never rotate. // Allow larger angles when near the end of the path to prevent oscillations. angle = Mathf.Min(angle, (20f + 180f * (1 - slowdownFactor * slowdownFactor)) * Mathf.Deg2Rad); float sin = Mathf.Sin(angle); float cos = Mathf.Cos(angle); // Determine if we should rotate clockwise or counter-clockwise to move towards the current velocity sin *= Mathf.Sign(normalizedVelocity.x * forward.y - normalizedVelocity.y * forward.x); // Rotate the #forward vector by #angle radians // The rotation is done using an inlined rotation matrix. // See https://en.wikipedia.org/wiki/Rotation_matrix return(new Vector2(forward.x * cos + forward.y * sin, forward.y * cos - forward.x * sin) * currentSpeed); } else { return(Vector2.ClampMagnitude(velocity, currentMaxSpeed)); } }
private static bool ProjectOverlapTest(Vector3 axis, Vector3[] srcPoints, Vector3[] dstPoints, out float overlap) { float srcMin = float.MaxValue; float dstMin = float.MaxValue; float srcMax = float.MinValue; float dstMax = float.MinValue; for (int i = 0; i < srcPoints.Length; i++) { var p = Vector3.Dot(axis, srcPoints[i]); if (p < srcMin) { srcMin = p; } if (p > srcMax) { srcMax = p; } } for (int i = 0; i < dstPoints.Length; i++) { var p = Vector3.Dot(axis, dstPoints[i]); if (p < dstMin) { dstMin = p; } if (p > dstMax) { dstMax = p; } } if (srcMax < dstMin || srcMin > dstMax) { overlap = 0; return(false); } overlap = Mathf.Min(srcMax, dstMax) - Mathf.Max(srcMin, dstMin); if ((srcMax > dstMax && srcMin < dstMin) || (srcMax < dstMax && srcMin > dstMin)) { var min = Mathf.Abs(srcMin - dstMin); var max = Mathf.Abs(srcMax - dstMax); overlap += Mathf.Min(min, max); } return(true); }
public static Frustum GetCameraSubFrustum(Camera camera, Rect rect) { var oldMatrix = UnityEditor.Handles.matrix; UnityEditor.Handles.matrix = Matrix4x4.identity; var min_x = Mathf.Min(rect.xMin, rect.xMax); var max_x = Mathf.Max(rect.xMin, rect.xMax); var min_y = Mathf.Min(rect.yMin, rect.yMax); var max_y = Mathf.Max(rect.yMin, rect.yMax); var o0 = new Vector2(min_x, min_y); var o1 = new Vector2(max_x, min_y); var o2 = new Vector2(max_x, max_y); var o3 = new Vector2(min_x, max_y); var r0 = HandleUtility.GUIPointToWorldRay(o0); var r1 = HandleUtility.GUIPointToWorldRay(o1); var r2 = HandleUtility.GUIPointToWorldRay(o2); var r3 = HandleUtility.GUIPointToWorldRay(o3); UnityEditor.Handles.matrix = oldMatrix; var n0 = r0.origin; var n1 = r1.origin; var n2 = r2.origin; var n3 = r3.origin; var far = camera.farClipPlane; var f0 = n0 + (r0.direction * far); var f1 = n1 + (r1.direction * far); var f2 = n2 + (r2.direction * far); var f3 = n3 + (r3.direction * far); var frustum = new Frustum(); frustum.Planes[0] = new Plane(n2, n1, f1); // right + frustum.Planes[1] = new Plane(f3, f0, n0); // left - frustum.Planes[2] = new Plane(n1, n0, f0); // top - frustum.Planes[3] = new Plane(n3, n2, f2); // bottom + frustum.Planes[4] = new Plane(n0, n1, n2); // near - frustum.Planes[5] = new Plane(f2, f1, f0); // far + return(frustum); }
/// <summary> /// Calculates a value from two given values based on the desired calculation method. /// </summary> /// <param name="lhs">The first value.</param> /// <param name="rhs">The second value.</param> /// <param name="calculation">How the final value should be calculated.</param> public static float Calculate(float lhs, float rhs, PhysicsMaterialCombine calculation) { switch (calculation) { case PhysicsMaterialCombine.Average: return((lhs + rhs) / 2f); case PhysicsMaterialCombine.Multiply: return(lhs * rhs); case PhysicsMaterialCombine.Maximum: return(Mathf.Max(lhs, rhs)); case PhysicsMaterialCombine.Minimum: return(Mathf.Min(lhs, rhs)); default: throw new System.NotImplementedException(); } }
public static bool Intersect(CubeXCollider src, CubeXCollider dst, out XContact?contact) { Vector3 normal; float penetration; if (!SATTest(src, dst, out normal, out penetration)) { contact = null; return(false); } var srcExtents = src.Size * 0.5f; var dstExtents = dst.Size * 0.5f; var srcMinY = src.Position.y - srcExtents.y; var srcMaxY = src.Position.y + srcExtents.y; var dstMinY = dst.Position.y - dstExtents.y; var dstMaxY = dst.Position.y + dstExtents.y; var overlapY = Mathf.Min(srcMaxY, dstMaxY) - Mathf.Max(srcMinY, dstMinY); if ((srcMaxY > dstMaxY && srcMinY < dstMinY) || (srcMaxY < dstMaxY && srcMinY > dstMinY)) { var min = Mathf.Abs(srcMinY - dstMinY); var max = Mathf.Abs(srcMaxY - dstMaxY); overlapY += Mathf.Min(min, max); } if (overlapY < penetration) { penetration = overlapY; normal = Vector3.up; } if (Vector3.Dot(normal, dst.Position - src.Position) < 0) { normal = -normal; } contact = new XContact(src, dst, normal, penetration); return(true); }
public static Toil PickUpThing(TargetIndex haulxItemInd, Toil nextToilIfBeingOpportunistic) { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; Job job = actor.CurJob; Thing target = job.GetTarget(haulxItemInd).Thing; if (Toils_Haul.ErrorCheckForCarry(actor, target)) { return; } Thing carriedItem = actor.carryTracker.CarriedThing; int targetInitialStackcount = target.stackCount; int countToPickUp = Mathf.Min( job.count - (carriedItem?.stackCount ?? 0), actor.carryTracker.AvailableStackSpace(target.def), targetInitialStackcount); if (countToPickUp <= 0) { throw new Exception("PickUpThing countToPickUp = " + countToPickUp); } //pick up int countPickedUp = actor.carryTracker.TryStartCarry(target, countToPickUp); if (countPickedUp < targetInitialStackcount) { actor.Map.reservationManager.Release(target, actor, job); } carriedItem = actor.carryTracker.CarriedThing; job.SetTarget(haulxItemInd, carriedItem); actor.records.Increment(RecordDefOf.ThingsHauled); //register the carried item (into the HaulExplicitly job) if (carriedItem.IsAHaulableSetToHaulable()) { carriedItem.ToggleHaulDesignation(); } var driver = (JobDriver_HaulExplicitly)actor.jobs.curDriver; driver.posting.TryAddItemSplinter(carriedItem); //pick up next available item in job? if (actor.CurJob.haulOpportunisticDuplicates) { Thing prospect = null; int best_dist = 999; foreach (Thing item in driver.record.items.Where( i => i.Spawned && WorkGiver_HaulExplicitly.CanGetThing(actor, i, false))) { IntVec3 offset = item.Position - actor.Position; int dist = Math.Abs(offset.x) + Math.Abs(offset.z); if (dist < best_dist && dist < 7) { prospect = item; best_dist = dist; } } if (prospect == null) { return; } int space_request = WorkGiver_HaulExplicitly .AmountPawnWantsToPickUp(actor, prospect, driver.posting); if (space_request == 0) { return; } var destInfo = DeliverableDestinations.For(prospect, actor, driver.posting); List <IntVec3> dests = destInfo.RequestSpaceForItemAmount( Math.Max(0, space_request - driver.dest_space_available)); int new_dest_space = destInfo.FreeSpaceInCells(dests); var count = Math.Min(space_request, driver.dest_space_available + new_dest_space); if (count < 1) { return; } //commit to it actor.Reserve(prospect, job); job.SetTarget(haulxItemInd, prospect); job.SetTarget(TargetIndex.C, prospect.Position); foreach (var dest in dests) { actor.Reserve(dest, job); job.targetQueueB.Add(dest); } job.count += count; driver.JumpToToil(nextToilIfBeingOpportunistic); } }; return(toil); }
public void OnEdit(IChiselHandles handles) { var normal = Vector3.up; var topDirection = Vector3.forward; var lowDirection = Vector3.forward; var originalOuterDiameter = this.outerDiameter; var originalInnerDiameter = this.innerDiameter; var originalStartAngle = this.startAngle; var originalStepHeight = this.stepHeight; var originalRotation = this.rotation; var originalHeight = this.height; var originalOrigin = this.origin; var cylinderTop = new BrushMeshFactory.ChiselCircleDefinition(1, originalOrigin.y + originalHeight); var cylinderLow = new BrushMeshFactory.ChiselCircleDefinition(1, originalOrigin.y); var originalTopPoint = normal * cylinderTop.height; var originalLowPoint = normal * cylinderLow.height; var originalMidPoint = (originalTopPoint + originalLowPoint) * 0.5f; var outerDiameter = originalOuterDiameter; var innerDiameter = originalInnerDiameter; var topPoint = originalTopPoint; var lowPoint = originalLowPoint; var midPoint = originalMidPoint; var startAngle = originalStartAngle; var rotation = originalRotation; { var currRotation = startAngle + rotation; handles.DoRotatableLineHandle(ref startAngle, lowPoint, outerDiameter * 0.5f, normal, lowDirection, Vector3.Cross(normal, lowDirection)); handles.DoRotatableLineHandle(ref currRotation, topPoint, outerDiameter * 0.5f, normal, topDirection, Vector3.Cross(normal, topDirection)); if (handles.modified) { rotation = currRotation - startAngle; } // TODO: properly show things as backfaced // TODO: temporarily show inner or outer diameter as disabled when resizing one or the other // TODO: FIXME: why aren't there any arrows? handles.DoDirectionHandle(ref topPoint, normal, snappingStep: originalStepHeight); topPoint.y = Mathf.Max(lowPoint.y + originalStepHeight, topPoint.y); handles.DoDirectionHandle(ref lowPoint, -normal, snappingStep: originalStepHeight); lowPoint.y = Mathf.Min(topPoint.y - originalStepHeight, lowPoint.y); float minOuterDiameter = innerDiameter + ChiselSpiralStairsDefinition.kMinStairsDepth; { var outerRadius = outerDiameter * 0.5f; handles.DoRadiusHandle(ref outerRadius, Vector3.up, topPoint, renderDisc: false); handles.DoRadiusHandle(ref outerRadius, Vector3.up, lowPoint, renderDisc: false); outerDiameter = Mathf.Max(minOuterDiameter, outerRadius * 2.0f); } float maxInnerDiameter = outerDiameter - ChiselSpiralStairsDefinition.kMinStairsDepth; { var innerRadius = innerDiameter * 0.5f; handles.DoRadiusHandle(ref innerRadius, Vector3.up, midPoint, renderDisc: false); innerDiameter = Mathf.Min(maxInnerDiameter, innerRadius * 2.0f); } // TODO: somehow put this into a separate renderer cylinderTop.diameterZ = cylinderTop.diameterX = cylinderLow.diameterZ = cylinderLow.diameterX = originalInnerDiameter; BrushMeshFactory.GetConicalFrustumVertices(cylinderLow, cylinderTop, 0, this.innerSegments, ref innerVertices); cylinderTop.diameterZ = cylinderTop.diameterX = cylinderLow.diameterZ = cylinderLow.diameterX = originalOuterDiameter; BrushMeshFactory.GetConicalFrustumVertices(cylinderLow, cylinderTop, 0, this.outerSegments, ref outerVertices); var originalColor = handles.color; var color = handles.color; var outlineColor = Color.black; outlineColor.a = color.a; handles.color = outlineColor; { var sides = this.outerSegments; for (int i = 0, j = sides - 1; i < sides; j = i, i++) { var t0 = outerVertices[i]; var t1 = outerVertices[j]; var b0 = outerVertices[i + sides]; var b1 = outerVertices[j + sides]; handles.DrawLine(t0, b0, thickness: 1.0f); handles.DrawLine(t0, t1, thickness: 1.0f); handles.DrawLine(b0, b1, thickness: 1.0f); } } { var sides = this.innerSegments; for (int i = 0, j = sides - 1; i < sides; j = i, i++) { var t0 = innerVertices[i]; var t1 = innerVertices[j]; var b0 = innerVertices[i + sides]; var b1 = innerVertices[j + sides]; handles.DrawLine(t0, b0, thickness: 1.0f); handles.DrawLine(t0, t1, thickness: 1.0f); handles.DrawLine(b0, b1, thickness: 1.0f); } } handles.color = originalColor; { var sides = this.outerSegments; for (int i = 0, j = sides - 1; i < sides; j = i, i++) { var t0 = outerVertices[i]; var t1 = outerVertices[j]; var b0 = outerVertices[i + sides]; var b1 = outerVertices[j + sides]; handles.DrawLine(t0, b0, thickness: 1.0f); handles.DrawLine(t0, t1, thickness: 1.0f); handles.DrawLine(b0, b1, thickness: 1.0f); } } { var sides = this.innerSegments; for (int i = 0, j = sides - 1; i < sides; j = i, i++) { var t0 = innerVertices[i]; var t1 = innerVertices[j]; var b0 = innerVertices[i + sides]; var b1 = innerVertices[j + sides]; handles.DrawLine(t0, b0, thickness: 1.0f); handles.DrawLine(t0, t1, thickness: 1.0f); handles.DrawLine(b0, b1, thickness: 1.0f); var m0 = (t0 + b0) * 0.5f; var m1 = (t1 + b1) * 0.5f; handles.DrawLine(m0, m1, thickness: 2.0f); } } } if (handles.modified) { this.outerDiameter = outerDiameter; this.innerDiameter = innerDiameter; this.startAngle = startAngle; this.rotation = rotation; if (topPoint != originalTopPoint) { this.height = topPoint.y - lowPoint.y; } if (lowPoint != originalLowPoint) { this.height = topPoint.y - lowPoint.y; var newOrigin = originalOrigin; newOrigin.y += lowPoint.y - originalLowPoint.y; this.origin = newOrigin; } } }
// // TODO: code below needs to be cleaned up & simplified // public void OnEdit(IChiselHandles handles) { var newDefinition = this; { var stepDepthOffset = this.StepDepthOffset; var stepHeight = this.stepHeight; var stepCount = this.StepCount; var bounds = this.bounds; var steps = handles.moveSnappingSteps; steps.y = stepHeight; if (handles.DoBoundsHandle(ref bounds, snappingSteps: steps)) { newDefinition.bounds = bounds; } var min = new Vector3(Mathf.Min(bounds.min.x, bounds.max.x), Mathf.Min(bounds.min.y, bounds.max.y), Mathf.Min(bounds.min.z, bounds.max.z)); var max = new Vector3(Mathf.Max(bounds.min.x, bounds.max.x), Mathf.Max(bounds.min.y, bounds.max.y), Mathf.Max(bounds.min.z, bounds.max.z)); var size = (max - min); var heightStart = bounds.max.y + (bounds.size.y < 0 ? size.y : 0); var edgeHeight = heightStart - stepHeight * stepCount; var pHeight0 = new Vector3(min.x, edgeHeight, max.z); var pHeight1 = new Vector3(max.x, edgeHeight, max.z); var depthStart = bounds.min.z - (bounds.size.z < 0 ? size.z : 0); var pDepth0 = new Vector3(min.x, max.y, depthStart + stepDepthOffset); var pDepth1 = new Vector3(max.x, max.y, depthStart + stepDepthOffset); if (handles.DoTurnHandle(ref bounds)) { newDefinition.bounds = bounds; } if (handles.DoEdgeHandle1D(out edgeHeight, Axis.Y, pHeight0, pHeight1, snappingStep: stepHeight)) { var totalStepHeight = Mathf.Clamp((heightStart - edgeHeight), size.y % stepHeight, size.y); const float kSmudgeValue = 0.0001f; var oldStepCount = newDefinition.StepCount; var newStepCount = Mathf.Max(1, Mathf.FloorToInt((Mathf.Abs(totalStepHeight) + kSmudgeValue) / stepHeight)); newDefinition.stepDepth = (oldStepCount * newDefinition.stepDepth) / newStepCount; newDefinition.plateauHeight = size.y - (stepHeight * newStepCount); } if (handles.DoEdgeHandle1D(out stepDepthOffset, Axis.Z, pDepth0, pDepth1, snappingStep: ChiselLinearStairsDefinition.kMinStepDepth)) { stepDepthOffset -= depthStart; stepDepthOffset = Mathf.Clamp(stepDepthOffset, 0, this.absDepth - ChiselLinearStairsDefinition.kMinStepDepth); newDefinition.stepDepth = ((this.absDepth - stepDepthOffset) / this.StepCount); } float heightOffset; var prevModified = handles.modified; { var direction = Vector3.Cross(Vector3.forward, pHeight0 - pDepth0).normalized; handles.DoEdgeHandle1DOffset(out var height0vec, Axis.Y, pHeight0, pDepth0, direction, snappingStep: stepHeight); handles.DoEdgeHandle1DOffset(out var height1vec, Axis.Y, pHeight1, pDepth1, direction, snappingStep: stepHeight); var height0 = Vector3.Dot(direction, height0vec); var height1 = Vector3.Dot(direction, height1vec); if (Mathf.Abs(height0) > Mathf.Abs(height1)) { heightOffset = height0; } else { heightOffset = height1; } } if (prevModified != handles.modified) { newDefinition.plateauHeight += heightOffset; } } if (handles.modified) { this = newDefinition; } }
public virtual bool Add(float amount) { timer = Mathf.Min(timer + amount, CurrentTimeValue); return(Finished); }
public static bool GenerateTorusAsset(CSGBrushMeshAsset brushMeshAsset, CSGTorusDefinition definition) { Vector3[] vertices = null; if (!GenerateTorusVertices(definition, ref vertices)) { brushMeshAsset.Clear(); return(false); } definition.Validate(); var surfaces = definition.surfaceAssets; var descriptions = definition.surfaceDescriptions; var tubeRadiusX = (definition.tubeWidth * 0.5f); var tubeRadiusY = (definition.tubeHeight * 0.5f); var torusRadius = (definition.outerDiameter * 0.5f) - tubeRadiusX; var horzSegments = definition.horizontalSegments; var vertSegments = definition.verticalSegments; var horzDegreePerSegment = (definition.totalAngle / horzSegments); var vertDegreePerSegment = (360.0f / vertSegments) * Mathf.Deg2Rad; var descriptionIndex = new int[2 + vertSegments]; descriptionIndex[0] = 0; descriptionIndex[1] = 1; var circleVertices = new Vector2[vertSegments]; var min = new Vector2(float.PositiveInfinity, float.PositiveInfinity); var max = new Vector2(float.NegativeInfinity, float.NegativeInfinity); var tubeAngleOffset = ((((vertSegments & 1) == 1) ? 0.0f : ((360.0f / vertSegments) * 0.5f)) + definition.tubeRotation) * Mathf.Deg2Rad; for (int v = 0; v < vertSegments; v++) { var vRad = tubeAngleOffset + (v * vertDegreePerSegment); circleVertices[v] = new Vector2((Mathf.Cos(vRad) * tubeRadiusX) - torusRadius, (Mathf.Sin(vRad) * tubeRadiusY)); min.x = Mathf.Min(min.x, circleVertices[v].x); min.y = Mathf.Min(min.y, circleVertices[v].y); max.x = Mathf.Max(max.x, circleVertices[v].x); max.y = Mathf.Max(max.y, circleVertices[v].y); descriptionIndex[v + 2] = 2; } if (definition.fitCircle) { var center = (max + min) * 0.5f; var size = (max - min) * 0.5f; size.x = tubeRadiusX / size.x; size.y = tubeRadiusY / size.y; for (int v = 0; v < vertSegments; v++) { circleVertices[v].x = (circleVertices[v].x - center.x) * size.x; circleVertices[v].y = (circleVertices[v].y - center.y) * size.y; circleVertices[v].x -= torusRadius; } } var subMeshes = new CSGBrushSubMesh[horzSegments]; var horzOffset = definition.startAngle; for (int h = 1, p = 0; h < horzSegments + 1; p = h, h++) { var hDegree0 = (p * horzDegreePerSegment) + horzOffset; var hDegree1 = (h * horzDegreePerSegment) + horzOffset; var rotation0 = Quaternion.AngleAxis(hDegree0, Vector3.up); var rotation1 = Quaternion.AngleAxis(hDegree1, Vector3.up); var subMeshVertices = new Vector3[vertSegments * 2]; for (int v = 0; v < vertSegments; v++) { subMeshVertices[v + vertSegments] = rotation0 * circleVertices[v]; subMeshVertices[v] = rotation1 * circleVertices[v]; } var subMesh = new CSGBrushSubMesh(); CreateExtrudedSubMesh(subMesh, vertSegments, descriptionIndex, descriptionIndex, 0, 1, subMeshVertices, surfaces, descriptions); if (!subMesh.Validate()) { brushMeshAsset.Clear(); return(false); } subMeshes[h - 1] = subMesh; } brushMeshAsset.SubMeshes = subMeshes; brushMeshAsset.CalculatePlanes(); brushMeshAsset.SetDirty(); return(true); }
public static bool GenerateTorusVertices(CSGTorusDefinition definition, ref Vector3[] vertices) { definition.Validate(); //var surfaces = definition.surfaceAssets; //var descriptions = definition.surfaceDescriptions; var tubeRadiusX = (definition.tubeWidth * 0.5f); var tubeRadiusY = (definition.tubeHeight * 0.5f); var torusRadius = (definition.outerDiameter * 0.5f) - tubeRadiusX; var horzSegments = definition.horizontalSegments; var vertSegments = definition.verticalSegments; var horzDegreePerSegment = (definition.totalAngle / horzSegments); var vertDegreePerSegment = (360.0f / vertSegments) * Mathf.Deg2Rad; var circleVertices = new Vector2[vertSegments]; var min = new Vector2(float.PositiveInfinity, float.PositiveInfinity); var max = new Vector2(float.NegativeInfinity, float.NegativeInfinity); var tubeAngleOffset = ((((vertSegments & 1) == 1) ? 0.0f : ((360.0f / vertSegments) * 0.5f)) + definition.tubeRotation) * Mathf.Deg2Rad; for (int v = 0; v < vertSegments; v++) { var vRad = tubeAngleOffset + (v * vertDegreePerSegment); circleVertices[v] = new Vector2((Mathf.Cos(vRad) * tubeRadiusX) - torusRadius, (Mathf.Sin(vRad) * tubeRadiusY)); min.x = Mathf.Min(min.x, circleVertices[v].x); min.y = Mathf.Min(min.y, circleVertices[v].y); max.x = Mathf.Max(max.x, circleVertices[v].x); max.y = Mathf.Max(max.y, circleVertices[v].y); } if (definition.fitCircle) { var center = (max + min) * 0.5f; var size = (max - min) * 0.5f; size.x = tubeRadiusX / size.x; size.y = tubeRadiusY / size.y; for (int v = 0; v < vertSegments; v++) { circleVertices[v].x = (circleVertices[v].x - center.x) * size.x; circleVertices[v].y = (circleVertices[v].y - center.y) * size.y; circleVertices[v].x -= torusRadius; } } if (definition.totalAngle != 360) { horzSegments++; } var horzOffset = definition.startAngle; var vertexCount = vertSegments * horzSegments; if (vertices == null || vertices.Length != vertexCount) { vertices = new Vector3[vertexCount]; } for (int h = 0, v = 0; h < horzSegments; h++) { var hDegree1 = (h * horzDegreePerSegment) + horzOffset; var rotation1 = Quaternion.AngleAxis(hDegree1, Vector3.up); for (int i = 0; i < vertSegments; i++, v++) { vertices[v] = rotation1 * circleVertices[i]; } } return(true); }