public void Validate() { if (surfaceDefinition == null) { surfaceDefinition = new ChiselSurfaceDefinition(); } if (surfaceDefinition.EnsureSize((int)SurfaceSides.TotalSides)) { var defaultRenderMaterial = ChiselMaterialManager.DefaultWallMaterial; var defaultPhysicsMaterial = ChiselMaterialManager.DefaultPhysicsMaterial; surfaceDefinition.surfaces[(int)SurfaceSides.Top].brushMaterial = ChiselBrushMaterial.CreateInstance(ChiselMaterialManager.DefaultFloorMaterial, defaultPhysicsMaterial); surfaceDefinition.surfaces[(int)SurfaceSides.Bottom].brushMaterial = ChiselBrushMaterial.CreateInstance(ChiselMaterialManager.DefaultFloorMaterial, defaultPhysicsMaterial); surfaceDefinition.surfaces[(int)SurfaceSides.Left].brushMaterial = ChiselBrushMaterial.CreateInstance(ChiselMaterialManager.DefaultWallMaterial, defaultPhysicsMaterial); surfaceDefinition.surfaces[(int)SurfaceSides.Right].brushMaterial = ChiselBrushMaterial.CreateInstance(ChiselMaterialManager.DefaultWallMaterial, defaultPhysicsMaterial); surfaceDefinition.surfaces[(int)SurfaceSides.Front].brushMaterial = ChiselBrushMaterial.CreateInstance(ChiselMaterialManager.DefaultWallMaterial, defaultPhysicsMaterial); surfaceDefinition.surfaces[(int)SurfaceSides.Back].brushMaterial = ChiselBrushMaterial.CreateInstance(ChiselMaterialManager.DefaultWallMaterial, defaultPhysicsMaterial); surfaceDefinition.surfaces[(int)SurfaceSides.Tread].brushMaterial = ChiselBrushMaterial.CreateInstance(ChiselMaterialManager.DefaultTreadMaterial, defaultPhysicsMaterial); surfaceDefinition.surfaces[(int)SurfaceSides.Step].brushMaterial = ChiselBrushMaterial.CreateInstance(ChiselMaterialManager.DefaultStepMaterial, defaultPhysicsMaterial); for (int i = 0; i < surfaceDefinition.surfaces.Length; i++) { if (surfaceDefinition.surfaces[i].brushMaterial == null) { surfaceDefinition.surfaces[i].brushMaterial = ChiselBrushMaterial.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial); } } } stepHeight = Mathf.Max(kMinStepHeight, stepHeight); stepDepth = Mathf.Clamp(stepDepth, kMinStepDepth, absDepth); treadHeight = Mathf.Max(0, treadHeight); nosingDepth = Mathf.Max(0, nosingDepth); nosingWidth = Mathf.Max(0, nosingWidth); width = Mathf.Max(kMinWidth, absWidth) * (width < 0 ? -1 : 1); depth = Mathf.Max(stepDepth, absDepth) * (depth < 0 ? -1 : 1); riserDepth = Mathf.Max(kMinRiserDepth, riserDepth); sideDepth = Mathf.Max(0, sideDepth); sideWidth = Mathf.Max(kMinSideWidth, sideWidth); sideHeight = Mathf.Max(0, sideHeight); var realHeight = Mathf.Max(stepHeight, absHeight); var maxPlateauHeight = realHeight - stepHeight; plateauHeight = Mathf.Clamp(plateauHeight, 0, maxPlateauHeight); var totalSteps = Mathf.Max(1, Mathf.FloorToInt((realHeight - plateauHeight + kStepSmudgeValue) / stepHeight)); var totalStepHeight = totalSteps * stepHeight; plateauHeight = Mathf.Max(0, realHeight - totalStepHeight); stepDepth = Mathf.Clamp(stepDepth, kMinStepDepth, absDepth / totalSteps); }
public void Validate() { tubeWidth = Mathf.Max(tubeWidth, kMinTubeDiameter); tubeHeight = Mathf.Max(tubeHeight, kMinTubeDiameter); outerDiameter = Mathf.Max(outerDiameter, tubeWidth * 2); horizontalSegments = Mathf.Max(horizontalSegments, 3); verticalSegments = Mathf.Max(verticalSegments, 3); totalAngle = Mathf.Clamp(totalAngle, 1, 360); // TODO: constants if (surfaceAssets == null || surfaceAssets.Length != 6) { var defaultRenderMaterial = CSGMaterialManager.DefaultWallMaterial; var defaultPhysicsMaterial = CSGMaterialManager.DefaultPhysicsMaterial; surfaceAssets = new CSGSurfaceAsset[6] { CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial) }; } if (surfaceDescriptions == null || surfaceDescriptions.Length != 6) { // TODO: make this independent on plane position somehow var surfaceFlags = CSGDefaults.SurfaceFlags; surfaceDescriptions = new SurfaceDescription[6] { new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 } }; } }
public Vector3 ClosestPoint(Vector3 point) { var closest = point - center; closest.x = Mathf.Clamp(closest.x, -extents.x, extents.x); closest.y = Mathf.Clamp(closest.y, -extents.y, extents.y); closest.z = Mathf.Clamp(closest.z, -extents.z, extents.z); closest += center; return(closest); }
public virtual void Reset(float lerpValue = 0f) { float time = 0f; float minTime1 = 0f, minTime2 = 0f; float maxTime1 = 0f, maxTime2 = 0f; switch (MyType) { case TimerType.CONST: CurrentTimeValue = Time1; break; case TimerType.LERP_TWO_CONSTANTS: CurrentTimeValue = Mathf.Lerp(Time1, Time2, lerpValue); break; case TimerType.RANDOM_TWO_CONSTANTS: CurrentTimeValue = Random.Range(Time1, Time2); break; case TimerType.LERP_RANDOM_FOUR_CONSTANTS: CurrentTimeValue = Random.Range(Mathf.Lerp(Time1, Time2, lerpValue), Mathf.Lerp(Time3, Time4, lerpValue)); break; case TimerType.LERP_CURVE: CurrentTimeValue = Curve1.Evaluate(Mathf.Lerp(CurveMaxTime(ref Curve1), CurveMinTime(ref Curve1), lerpValue)) * ValueMultiplier; break; case TimerType.RANDOM_CURVE: CurrentTimeValue = Curve1.Evaluate(RandomCurveTime(ref Curve1)) * ValueMultiplier; break; case TimerType.LERP_RANDOM_TWO_CURVES: minTime1 = CurveMinTime(ref Curve1); maxTime1 = CurveMaxTime(ref Curve2); minTime2 = CurveMinTime(ref Curve2); maxTime2 = CurveMaxTime(ref Curve2); time = Mathf.Clamp(Mathf.Lerp(minTime1, maxTime1, lerpValue), minTime2, maxTime2); CurrentTimeValue = Random.Range(Curve1.Evaluate(time), Curve2.Evaluate(time)) * ValueMultiplier; break; case TimerType.RANDOM_TWO_CURVES: time = RandomCurveTime(ref Curve1); minTime2 = CurveMinTime(ref Curve2); maxTime2 = CurveMaxTime(ref Curve2); time = Mathf.Clamp(time, minTime2, maxTime2); CurrentTimeValue = Random.Range(Curve1.Evaluate(time), Curve2.Evaluate(time)) * ValueMultiplier; break; default: CurrentTimeValue = Time1; break; } timer = 0f; }
public void Validate() { curveSegments = Mathf.Max(curveSegments, 2); revolveSegments = Mathf.Max(revolveSegments, 1); totalAngle = Mathf.Clamp(totalAngle, 1, 360); // TODO: constants if (surfaceAssets == null || surfaceAssets.Length != 6) { var defaultRenderMaterial = CSGMaterialManager.DefaultWallMaterial; var defaultPhysicsMaterial = CSGMaterialManager.DefaultPhysicsMaterial; surfaceAssets = new CSGSurfaceAsset[6] { CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial), CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial) }; } if (surfaceDescriptions == null || surfaceDescriptions.Length != 6) { // TODO: make this independent on plane position somehow var surfaceFlags = CSGDefaults.SurfaceFlags; surfaceDescriptions = new SurfaceDescription[6] { new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 }, new SurfaceDescription { UV0 = UVMatrix.centered, surfaceFlags = surfaceFlags, smoothingGroup = 0 } }; } }
public void Validate() { if (surfaceDefinition == null) { surfaceDefinition = new ChiselSurfaceDefinition(); } curveSegments = Mathf.Max(curveSegments, 2); revolveSegments = Mathf.Max(revolveSegments, 1); totalAngle = Mathf.Clamp(totalAngle, 1, 360); // TODO: constants surfaceDefinition.EnsureSize(6); }
/** 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)); } }
public void Validate() { if (surfaceDefinition == null) { surfaceDefinition = new ChiselSurfaceDefinition(); } tubeWidth = Mathf.Max(tubeWidth, kMinTubeDiameter); tubeHeight = Mathf.Max(tubeHeight, kMinTubeDiameter); outerDiameter = Mathf.Max(outerDiameter, tubeWidth * 2); horizontalSegments = Mathf.Max(horizontalSegments, 3); verticalSegments = Mathf.Max(verticalSegments, 3); totalAngle = Mathf.Clamp(totalAngle, 1, 360); // TODO: constants surfaceDefinition.EnsureSize(6); }
public Block GetBlock(int x, int y, int z) { if (!deactivated) { //if (IsInBounds(x, y, z)) { x = Mathf.Clamp(x, 0, ChunkSizeX); y = Mathf.Clamp(y, 0, ChunkSizeY); z = Mathf.Clamp(z, 0, ChunkSizeZ); int index = Get_Flat_Index(x, y, z); Block res = new Block(blocks_type[index], blocks_iso[index]); res.set = blocks_set[index]; return(res); } return(default(Block)); }
public void Validate() { if (surfaceAssets == null || surfaceDescriptions.Length != (int)SurfaceSides.TotalSides) { var defaultRenderMaterial = CSGMaterialManager.DefaultWallMaterial; var defaultPhysicsMaterial = CSGMaterialManager.DefaultPhysicsMaterial; surfaceAssets = new CSGSurfaceAsset[(int)SurfaceSides.TotalSides]; surfaceAssets[(int)SurfaceSides.Top] = CSGSurfaceAsset.CreateInstance(CSGMaterialManager.DefaultFloorMaterial, defaultPhysicsMaterial); surfaceAssets[(int)SurfaceSides.Bottom] = CSGSurfaceAsset.CreateInstance(CSGMaterialManager.DefaultFloorMaterial, defaultPhysicsMaterial); surfaceAssets[(int)SurfaceSides.Left] = CSGSurfaceAsset.CreateInstance(CSGMaterialManager.DefaultWallMaterial, defaultPhysicsMaterial); surfaceAssets[(int)SurfaceSides.Right] = CSGSurfaceAsset.CreateInstance(CSGMaterialManager.DefaultWallMaterial, defaultPhysicsMaterial); surfaceAssets[(int)SurfaceSides.Forward] = CSGSurfaceAsset.CreateInstance(CSGMaterialManager.DefaultWallMaterial, defaultPhysicsMaterial); surfaceAssets[(int)SurfaceSides.Back] = CSGSurfaceAsset.CreateInstance(CSGMaterialManager.DefaultWallMaterial, defaultPhysicsMaterial); surfaceAssets[(int)SurfaceSides.Tread] = CSGSurfaceAsset.CreateInstance(CSGMaterialManager.DefaultTreadMaterial, defaultPhysicsMaterial); surfaceAssets[(int)SurfaceSides.Step] = CSGSurfaceAsset.CreateInstance(CSGMaterialManager.DefaultStepMaterial, defaultPhysicsMaterial); for (int i = 0; i < surfaceAssets.Length; i++) { if (surfaceAssets[i] == null) { surfaceAssets[i] = CSGSurfaceAsset.CreateInstance(defaultRenderMaterial, defaultPhysicsMaterial); } } topSurface = surfaceAssets[(int)SurfaceSides.Top]; bottomSurface = surfaceAssets[(int)SurfaceSides.Bottom]; leftSurface = surfaceAssets[(int)SurfaceSides.Left]; rightSurface = surfaceAssets[(int)SurfaceSides.Right]; forwardSurface = surfaceAssets[(int)SurfaceSides.Forward]; backSurface = surfaceAssets[(int)SurfaceSides.Back]; treadSurface = surfaceAssets[(int)SurfaceSides.Tread]; stepSurface = surfaceAssets[(int)SurfaceSides.Step]; } 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 }; } } stepHeight = Mathf.Max(kMinStepHeight, stepHeight); stepDepth = Mathf.Clamp(stepDepth, kMinStepDepth, Mathf.Abs(depth)); treadHeight = Mathf.Max(0, treadHeight); nosingDepth = Mathf.Max(0, nosingDepth); nosingWidth = Mathf.Max(0, nosingWidth); width = Mathf.Max(kMinWidth, Mathf.Abs(width)) * (width < 0 ? -1 : 1); depth = Mathf.Max(stepDepth, Mathf.Abs(depth)) * (depth < 0 ? -1 : 1); riserDepth = Mathf.Max(kMinRiserDepth, riserDepth); sideDepth = Mathf.Max(0, sideDepth); sideWidth = Mathf.Max(kMinSideWidth, sideWidth); sideHeight = Mathf.Max(0, sideHeight); var absHeight = Mathf.Max(stepHeight, Mathf.Abs(height)); var maxPlateauHeight = absHeight - stepHeight; plateauHeight = Mathf.Clamp(plateauHeight, 0, maxPlateauHeight); var totalSteps = Mathf.Max(1, Mathf.FloorToInt((absHeight - plateauHeight) / stepHeight)); var totalStepHeight = totalSteps * stepHeight; plateauHeight = Mathf.Max(0, absHeight - totalStepHeight); stepDepth = Mathf.Clamp(stepDepth, kMinStepDepth, Mathf.Abs(depth) / totalSteps); }
/// <summary> /// Fill a texture with a signed distance field generated from the alpha channel of a source texture. /// </summary> /// <param name="source"> /// Source texture. Alpha values of 1 are considered inside, values of 0 are considered outside, and any other values are considered /// to be on the edge. Must be readable. /// </param> /// <param name="destination"> /// Destination texture. Must be the same size as the source texture. Must be readable. /// The texture change does not get applied automatically, you need to do that yourself. /// </param> /// <param name="maxInside"> /// Maximum pixel distance measured inside the edge, resulting in an alpha value of 1. /// If set to or below 0, everything inside will have an alpha value of 1. /// </param> /// <param name="maxOutside"> /// Maximum pixel distance measured outside the edge, resulting in an alpha value of 0. /// If set to or below 0, everything outside will have an alpha value of 0. /// </param> /// <param name="postProcessDistance"> /// Pixel distance from the edge within which pixels will be post-processed using the edge gradient. /// </param> /// <param name="rgbMode"> /// How to fill the destination texture's RGB channels. /// </param> public static void Generate( Image <Rgba32> source, Image <Rgba32> destination, float maxInside, float maxOutside, float postProcessDistance, RGBFillMode rgbMode) { if (source.Height != destination.Height || source.Width != destination.Width) { Console.Out.WriteLine("Source and destination textures must be the same size."); return; } width = source.Width; height = source.Height; pixels = new Pixel[width, height]; int x, y; float scale; Rgba32 c = rgbMode == RGBFillMode.White ? Color.White: Color.Black; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { pixels[x, y] = new Pixel(); } } if (maxInside > 0f) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { pixels[x, y].alpha = source.GetPixel(x, y).R / 255f; } } ComputeEdgeGradients(); GenerateDistanceTransform(); if (postProcessDistance > 0f) { PostProcess(postProcessDistance); } scale = 1f / maxInside; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { c.A = (byte)(255f * Math.Clamp(pixels[x, y].distance * scale, 0, 1)); destination.SetPixel(x, y, c); } } } if (maxOutside > 0f) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { pixels[x, y].alpha = 1f - source.GetPixel(x, y).R / 255f; } } ComputeEdgeGradients(); GenerateDistanceTransform(); if (postProcessDistance > 0f) { PostProcess(postProcessDistance); } scale = 1f / maxOutside; if (maxInside > 0f) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { c.A = (byte)(255f * (0.5f + (destination.GetPixel(x, y).A / 255f - Math.Clamp(pixels[x, y].distance * scale, 0, 1)) * 0.5f)); destination.SetPixel(x, y, c); } } } else { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { c.A = (byte)(255f * Math.Clamp(1f - pixels[x, y].distance * scale, 0, 1)); destination.SetPixel(x, y, c); } } } } if (rgbMode == RGBFillMode.Distance) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { c = destination.GetPixel(x, y); c.R = c.A; c.G = c.A; c.B = c.A; destination.SetPixel(x, y, c); } } } else if (rgbMode == RGBFillMode.Source) { for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { c = source.GetPixel(x, y); c.A = destination.GetPixel(x, y).A; destination.SetPixel(x, y, c); } } } pixels = null; }
public static bool Intersect(CubeXCollider src, CylinderXCollider dst, out XContact?contact) { var invP = Quaternion.Inverse(src.Quaternion) * (dst.Position - src.Position); Vector3 n = Vector3.zero; n.x = invP.x; n.z = invP.z; var extents = src.Size * 0.5f; var halfHa = extents.y; var topA = halfHa; var bottomA = -halfHa; var halfHb = dst.Height * 0.5f; var topB = invP.y + halfHb; var bottomB = invP.y - halfHb; var space = dst.Radius; var sqrSpace = space * space; // 相撞时,俯视图下的圆和矩形必然相交 var closest = n; closest.x = Mathf.Clamp(closest.x, -extents.x, extents.x); closest.z = Mathf.Clamp(closest.z, -extents.z, extents.z); if ((n - closest).sqrMagnitude > sqrSpace) { contact = null; return(false); } // 处理相交的情况 Vector3 normal; float penetration; float verticalP = float.PositiveInfinity; float horizontalP; var inside = false; if (n == closest) { inside = true; var disX = extents.x - Mathf.Abs(n.x); var disZ = extents.z - Mathf.Abs(n.z); //找到最近的一个面 if (disX < disZ) { // 沿X轴 if (n.x > 0) { closest.x = extents.x; } else { closest.x = -extents.x; } } else { // 沿Z轴 if (n.z > 0) { closest.z = extents.z; } else { closest.z = -extents.z; } } horizontalP = space + (n - closest).magnitude; } else { horizontalP = space - (n - closest).magnitude; } if (Mathf.Sign(topA - topB) != Mathf.Sign(bottomB - bottomA)) { // 斜向相撞 if (topB > topA) { verticalP = topA - bottomB; } else { verticalP = topB - bottomA; } } if (horizontalP < verticalP) { normal = (src.Quaternion * (n - closest)).normalized; if (inside) { normal = -normal; } penetration = horizontalP; } else { normal = topB > topA ? Vector3.up : Vector3.down; penetration = verticalP; } if (normal == Vector3.zero) { normal = Vector3.up; } contact = new XContact(src, dst, normal, penetration); return(true); }
public static bool Intersect(CubeXCollider src, SphereXCollider dst, out XContact?contact) { // 反向旋转sphere的位置,使得可以在cube的坐标系下进行碰撞判断 var extents = src.Size * 0.5f; var invQ = Quaternion.Inverse(src.Quaternion); var invP = invQ * (dst.Position - src.Position); // 以下所有操作都是在cube的坐标系下,随后的实际方向需要进行坐标系转换 var n = invP; var closest = n; closest.x = Mathf.Clamp(closest.x, -extents.x, extents.x); closest.y = Mathf.Clamp(closest.y, -extents.y, extents.y); closest.z = Mathf.Clamp(closest.z, -extents.z, extents.z); var inside = false; if (n == closest) { inside = true; var disX = extents.x - Mathf.Abs(n.x); var disY = extents.y - Mathf.Abs(n.y); var disZ = extents.z - Mathf.Abs(n.z); //找到最近的一个面 if (disX < disY && disX < disZ) { // 沿X轴 if (n.x > 0) { closest.x = extents.x; } else { closest.x = -extents.x; } } else if (disY < disX && disY < disZ) { // 沿Y轴 if (n.y > 0) { closest.y = extents.y; } else { closest.y = -extents.y; } } else { // 沿Z轴 if (n.z > 0) { closest.z = extents.z; } else { closest.z = -extents.z; } } } var dir = n - closest; var sqrDist = dir.sqrMagnitude; var space = dst.Radius; var sqrSpace = space * space; if (sqrDist < sqrSpace || inside) { var dist = Mathf.Sqrt(sqrDist); var normal = (src.Quaternion * dir).normalized; var penetration = space - dist; if (inside) { normal = -normal; penetration = space + dist; } if (normal == Vector3.zero) { normal = Vector3.up; } contact = new XContact(src, dst, normal, penetration); return(true); } contact = null; return(false); }
public static bool Intersect(CylinderXCollider src, SphereXCollider dst, out XContact?contact) { var n = dst.Position - src.Position; Vector3 closest = n; var extents = src.bounds.Extents; closest.x = Mathf.Clamp(closest.x, -extents.x, extents.x); closest.y = Mathf.Clamp(closest.y, -extents.y, extents.y); closest.z = Mathf.Clamp(closest.z, -extents.z, extents.z); var v = new Vector2(closest.x, closest.z); if (v.sqrMagnitude > src.Radius * src.Radius) { v = v.normalized * src.Radius; closest.x = v.x; closest.z = v.y; } bool inside = false; if (n == closest) { inside = true; // 往上下移动的最短距离 var dist1 = extents.y - Mathf.Abs(closest.y); // 往水平四周移动的最短距离 var dist2 = src.Radius - v.magnitude; if (dist1 < dist2) { closest.y = closest.y > 0 ? extents.y : -extents.y; } else { v = v.normalized * src.Radius; closest.x = v.x; closest.z = v.y; } } var dir = n - closest; var sqrDist = dir.sqrMagnitude; var space = dst.Radius; var sqrSpace = space * space; if (sqrDist < sqrSpace || inside) { var dist = Mathf.Sqrt(sqrDist); var normal = dir.normalized; var penetration = space - dist; if (inside) { normal = -normal; penetration = space + dist; } if (normal == Vector3.zero) { normal = Vector3.up; } contact = new XContact(src, dst, normal, penetration); return(true); } contact = null; return(false); }
static void ProcessSingleFile(string[] args, int outlineThreshold) { if (args.Length < 3) { Logger.WriteErrorLine( "Provide three arguments: [mode] [Input.png/jpg] [max colors] <output path replace from> <output path replace to>"); } var mode = args[0]; var startFileName = args[1] .Replace('/', Path.DirectorySeparatorChar) .Replace('\\', Path.DirectorySeparatorChar); int.TryParse(args[2], out var maxColor); maxColor = Math.Clamp(maxColor, 3, 100); if (args.Length >= 4) { outputPathReplaceFrom = args[3]; } if (args.Length >= 5) { outputPathReplaceTo = args[4]; } outputNewFileName = args.Length >= 6 ? args[5] : null; if (mode == "otb") { ExecuteOutlineToBlack(startFileName, outlineThreshold); } else if (mode == "fsnb") { var otbFileName = ExecuteOutlineToBlack(startFileName, outlineThreshold); ExecuteFillSmallNotBlack(otbFileName); } else if (mode == "q") { ExecuteOutlineToBlack(startFileName, outlineThreshold); ExecuteQuantize(startFileName, maxColor); } else if (mode == "fots") { var otbFileName = ExecuteOutlineToBlack(startFileName, outlineThreshold); var fsnbFileName = ExecuteFillSmallNotBlack(otbFileName); var qFileName = ExecuteQuantize(startFileName, maxColor); ExecuteFlattenedOutlineToSource(qFileName, fsnbFileName); } else if (mode == "di") { var otbFileName = ExecuteOutlineToBlack(startFileName, outlineThreshold); var fsnbFileName = ExecuteFillSmallNotBlack(otbFileName); var qFileName = ExecuteQuantize(startFileName, maxColor); var fotsFileName = ExecuteFlattenedOutlineToSource(qFileName, fsnbFileName); ExecuteDetermineIsland(fotsFileName, startFileName); } else if (mode == "dit") { var rasapFileName = ExecuteResizeAndSaveAsPng(startFileName, 1500); var otbFileName = ExecuteOutlineToBlack(rasapFileName, outlineThreshold); var fsnbFileName = ExecuteFillSmallNotBlack(otbFileName); var qFileName = ExecuteQuantize(rasapFileName, maxColor); var fotsFileName = ExecuteFlattenedOutlineToSource(qFileName, fsnbFileName); var bytesFileName = ExecuteDetermineIsland(fotsFileName, rasapFileName); // 색칠 테스트. 첫 데이터를 얻기 위한 것으로 오류 메시지는 경고로 무시해도 된다. var ditFileName = ExecuteDetermineIslandTest(fsnbFileName, bytesFileName, true, false); // DIT 파일이 최종 컬러링 완성 시의 이미지이다. 이걸로 최종적으로 데이터를 다시 뽑는다. bytesFileName = ExecuteDetermineIsland(ditFileName, rasapFileName); //두 번째 테스트. 여기서 오류가 나면 뭔가 이상한거다. ExecuteDetermineIslandTest(fsnbFileName, bytesFileName, false, true); var bbFileName = ExecuteBoxBlur(fsnbFileName, 1); ExecuteSdf(bbFileName); // 필요없는 파일은 삭제한다. // 디버그가 필요한 경우 삭제하지 않고 살펴보면 된다. // if (rasapFileName != startFileName) // { // File.Delete(rasapFileName); // } var artifactsDirName = Path.GetDirectoryName(ChangeToArtifactsPath(bbFileName)); if (string.IsNullOrEmpty(artifactsDirName)) { throw new ArgumentNullException(); } try { Directory.Delete(artifactsDirName, true); } catch (DirectoryNotFoundException) { } MoveOrOverwriteToArtifactsDirectory(bbFileName); MoveOrOverwriteToArtifactsDirectory(ditFileName); MoveOrOverwriteToArtifactsDirectory(fotsFileName); MoveOrOverwriteToArtifactsDirectory(fsnbFileName); MoveOrOverwriteToArtifactsDirectory(otbFileName); MoveOrOverwriteToArtifactsDirectory(qFileName); MoveOrOverwriteToArtifactsDirectory(rasapFileName); } else { Logger.WriteErrorLine($"Unknown mode provided: {mode}"); return; } Logger.WriteLine("Completed."); }
static void SetPixelClamped(Image <Rgba32> image, int x, int y, Rgba32 v) { image[Math.Clamp(x, 0, image.Width - 1), Math.Clamp(y, 0, image.Height - 1)] = v; }
static Rgba32 GetPixelClamped(Image <Rgba32> image, int x, int y) { return(image[Math.Clamp(x, 0, image.Width - 1), Math.Clamp(y, 0, image.Height - 1)]); }
static void ProcessSingleFile(string[] args, int outlineThreshold) { if (args.Length < 3) { Console.Out.WriteLine("Provide three arguments: [mode] [Input.png/jpg] [max colors] <output path replace from> <output path replace to>"); } var mode = args[0]; var startFileName = args[1] .Replace('/', Path.DirectorySeparatorChar) .Replace('\\', Path.DirectorySeparatorChar); int.TryParse(args[2], out var maxColor); maxColor = Math.Clamp(maxColor, 3, 100); if (args.Length >= 4) { outputPathReplaceFrom = args[3]; } if (args.Length >= 5) { outputPathReplaceTo = args[4]; } if (mode == "otb") { ExecuteOutlineToBlack(startFileName, outlineThreshold); } else if (mode == "fsnb") { var otbFileName = ExecuteOutlineToBlack(startFileName, outlineThreshold); ExecuteFillSmallNotBlack(otbFileName); } else if (mode == "q") { ExecuteOutlineToBlack(startFileName, outlineThreshold); ExecuteQuantize(startFileName, maxColor); } else if (mode == "fots") { var otbFileName = ExecuteOutlineToBlack(startFileName, outlineThreshold); var fsnbFileName = ExecuteFillSmallNotBlack(otbFileName); var qFileName = ExecuteQuantize(startFileName, maxColor); ExecuteFlattenedOutlineToSource(qFileName, fsnbFileName); } else if (mode == "di") { var otbFileName = ExecuteOutlineToBlack(startFileName, outlineThreshold); var fsnbFileName = ExecuteFillSmallNotBlack(otbFileName); var qFileName = ExecuteQuantize(startFileName, maxColor); var fotsFileName = ExecuteFlattenedOutlineToSource(qFileName, fsnbFileName); ExecuteDetermineIsland(fotsFileName, startFileName); } else if (mode == "dit") { var otbFileName = ExecuteOutlineToBlack(startFileName, outlineThreshold); var fsnbFileName = ExecuteFillSmallNotBlack(otbFileName); var qFileName = ExecuteQuantize(startFileName, maxColor); var fotsFileName = ExecuteFlattenedOutlineToSource(qFileName, fsnbFileName); var bytesFileName = ExecuteDetermineIsland(fotsFileName, startFileName); ExecuteDetermineIslandTest(fsnbFileName, bytesFileName); var bbFileName = ExecuteBoxBlur(fsnbFileName, 1); ExecuteSdf(bbFileName); } else { Console.Out.WriteLine($"Unknown mode provided: {mode}"); return; } Console.Out.WriteLine("Completed."); }
// // 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; } }
static Vector3[] vertices = null; // TODO: store this per instance? or just allocate every frame? public void OnEdit(IChiselHandles handles) { var baseColor = handles.color; var normal = Vector3.up; if (BrushMeshFactory.GenerateCapsuleVertices(ref this, ref vertices)) { handles.color = handles.GetStateColor(baseColor, false, false); DrawOutline(handles, this, vertices, lineMode: LineMode.ZTest); handles.color = handles.GetStateColor(baseColor, false, true); DrawOutline(handles, this, vertices, lineMode: LineMode.NoZTest); handles.color = baseColor; } var topPoint = normal * (this.offsetY + this.height); var bottomPoint = normal * (this.offsetY); var middlePoint = normal * (this.offsetY + (this.height * 0.5f)); var radius2D = new Vector2(this.diameterX, this.diameterZ) * 0.5f; var topHeight = this.topHeight; var bottomHeight = this.bottomHeight; var maxTopHeight = this.height - bottomHeight; var maxBottomHeight = this.height - topHeight; if (this.height < 0) { normal = -normal; } var prevModified = handles.modified; { handles.color = baseColor; // TODO: make it possible to (optionally) size differently in x & z var radius2Dx = radius2D.x; handles.DoRadiusHandle(ref radius2Dx, normal, middlePoint); radius2D.x = radius2Dx; { var isTopBackfaced = handles.IsSufaceBackFaced(topPoint, normal); var topLoopHasFocus = false; handles.backfaced = isTopBackfaced; for (int j = this.sides - 1, i = 0; i < this.sides; j = i, i++) { var from = vertices[j + this.topVertexOffset]; var to = vertices[i + this.topVertexOffset]; if (handles.DoEdgeHandle1DOffset(out var edgeOffset, UnitySceneExtensions.Axis.Y, from, to, renderLine: false)) { topHeight = Mathf.Clamp(topHeight - edgeOffset, 0, maxTopHeight); } topLoopHasFocus = topLoopHasFocus || handles.lastHandleHadFocus; } handles.color = baseColor; handles.DoDirectionHandle(ref topPoint, normal); var topHasFocus = handles.lastHandleHadFocus; handles.backfaced = false; topLoopHasFocus = topLoopHasFocus || (topHasFocus && !this.haveRoundedTop); var thickness = topLoopHasFocus ? kCapLineThicknessSelected : kCapLineThickness; handles.color = handles.GetStateColor(baseColor, topLoopHasFocus, true); handles.DrawLineLoop(vertices, this.topVertexOffset, this.sides, lineMode: LineMode.NoZTest, thickness: thickness); handles.color = handles.GetStateColor(baseColor, topLoopHasFocus, false); handles.DrawLineLoop(vertices, this.topVertexOffset, this.sides, lineMode: LineMode.ZTest, thickness: thickness); } { var isBottomBackfaced = handles.IsSufaceBackFaced(bottomPoint, -normal); var bottomLoopHasFocus = false; handles.backfaced = isBottomBackfaced; for (int j = this.sides - 1, i = 0; i < this.sides; j = i, i++) { var from = vertices[j + this.bottomVertexOffset]; var to = vertices[i + this.bottomVertexOffset]; if (handles.DoEdgeHandle1DOffset(out var edgeOffset, UnitySceneExtensions.Axis.Y, from, to, renderLine: false)) { bottomHeight = Mathf.Clamp(bottomHeight + edgeOffset, 0, maxBottomHeight); } bottomLoopHasFocus = bottomLoopHasFocus || handles.lastHandleHadFocus; } handles.color = baseColor; handles.DoDirectionHandle(ref bottomPoint, -normal); var bottomHasFocus = handles.lastHandleHadFocus; handles.backfaced = false; bottomLoopHasFocus = bottomLoopHasFocus || (bottomHasFocus && !this.haveRoundedBottom); var thickness = bottomLoopHasFocus ? kCapLineThicknessSelected : kCapLineThickness; handles.color = handles.GetStateColor(baseColor, bottomLoopHasFocus, true); handles.DrawLineLoop(vertices, this.bottomVertexOffset, this.sides, lineMode: LineMode.NoZTest, thickness: thickness); handles.color = handles.GetStateColor(baseColor, bottomLoopHasFocus, false); handles.DrawLineLoop(vertices, this.bottomVertexOffset, this.sides, lineMode: LineMode.ZTest, thickness: thickness); } } if (prevModified != handles.modified) { this.diameterX = radius2D.x * 2.0f; this.height = topPoint.y - bottomPoint.y; this.diameterZ = radius2D.x * 2.0f; this.offsetY = bottomPoint.y; this.topHeight = topHeight; this.bottomHeight = bottomHeight; // TODO: handle sizing down (needs to modify transformation?) } }