Beispiel #1
0
        /// <summary>
        /// Returns the signed distance to the field as a whole.
        /// </summary>
        public float Map(Vector3 p)
        {
            float minDist = 10000000f;

            for (int i = 0; i < m_sdfData.Count; i++)
            {
                SDFGPUData data = m_sdfData[i];

                if (data.IsOperation)
                {
                    p = ElongateSpace(p, data.Data, data.Transform);
                }
                else
                {
                    if (data.CombineType == 0)
                    {
                        minDist = SmoothUnion(minDist, SDF(p, data), data.Smoothing);
                    }
                    else if (data.CombineType == 1)
                    {
                        minDist = SmoothSubtract(SDF(p, data), minDist, data.Smoothing);
                    }
                    else
                    {
                        minDist = SmoothIntersect(SDF(p, data), minDist, data.Smoothing);
                    }
                }
            }

            return(minDist);
        }
Beispiel #2
0
        /// <summary>
        /// Get the signed distance to the object represented by the given data object.
        /// </summary>
        private float SDF(Vector3 p, SDFGPUData data)
        {
            if (data.IsMesh)
            {
                Vector3 vec = GetDirectionToMesh(p, data, out float distSign, out Vector3 transformedP);

                return(vec.magnitude * distSign * data.Flip);
            }
            else
            {
                p = data.Transform.MultiplyPoint(p);

                switch ((SDFPrimitiveType)(data.Type - 1))
                {
                case SDFPrimitiveType.Sphere:
                    return(MapSphere(p, data.Data.x) * data.Flip);

                case SDFPrimitiveType.Torus:
                    return(MapTorus(p, data.Data) * data.Flip);

                case SDFPrimitiveType.Cuboid:
                    return(MapRoundedBox(p, data.Data, data.Data.w) * data.Flip);

                case SDFPrimitiveType.Cylinder:
                    return(MapCylinder(p, data.Data.x, data.Data.y) * data.Flip);

                default:
                    return(MapBoxFrame(p, data.Data, data.Data.w) * data.Flip);
                }
            }
        }
Beispiel #3
0
        private static Vector3 CellCoordinateToVertex(int x, int y, int z, SDFGPUData data)
        {
            float   gridSize  = data.Size - 1f;
            Vector3 minBounds = data.MinBounds;
            Vector3 maxBounds = data.MaxBounds;
            float   xPos      = Mathf.Lerp(minBounds.x, maxBounds.x, x / gridSize);
            float   yPos      = Mathf.Lerp(minBounds.y, maxBounds.y, y / gridSize);
            float   zPos      = Mathf.Lerp(minBounds.z, maxBounds.z, z / gridSize);

            return(new Vector3(xPos, yPos, zPos));
        }
Beispiel #4
0
        // clamp the input point to an axis aligned bounding cube of the given bounds
        // optionally can provide an offset which pushes the bounds in or out.
        // this is used to get the position on the bounding cube nearest the given point as
        // part of the sdf to mesh calculation. the additional push param is used to ensure we have enough
        // samples around our point that we can get a gradient
        private static Vector3 GetClosestPointToVolume(Vector3 p, SDFGPUData data, float boundsOffset = 0f)
        {
            Vector3 minBounds = data.MinBounds;
            Vector3 maxBounds = data.MaxBounds;

            return(new Vector3(
                       Mathf.Clamp(p.x, minBounds.x + boundsOffset, maxBounds.x - boundsOffset),
                       Mathf.Clamp(p.y, minBounds.y + boundsOffset, maxBounds.y - boundsOffset),
                       Mathf.Clamp(p.z, minBounds.z + boundsOffset, maxBounds.z - boundsOffset)
                       ));
        }
Beispiel #5
0
        private Vector3 ComputeMeshGradient(Vector3 p, SDFGPUData data, float epsilon, float boundsOffset = 0f)
        {
            // sample the map 4 times to calculate the gradient at that point, then normalize it
            Vector2 e = new Vector2(epsilon, -epsilon);

            return((
                       XYY(e) * SampleAssetInterpolated(p + XYY(e), data, boundsOffset) +
                       YYX(e) * SampleAssetInterpolated(p + YYX(e), data, boundsOffset) +
                       YXY(e) * SampleAssetInterpolated(p + YXY(e), data, boundsOffset) +
                       XXX(e) * SampleAssetInterpolated(p + XXX(e), data, boundsOffset)).normalized);
        }
Beispiel #6
0
        // these functions are all specifically to do with SDFMesh objects only

        // given a point, return the coords of the cell it's in, and the fractional component for interpolation
        private static void GetNearestCoordinates(Vector3 p, SDFGPUData data, out Vector3 coords, out Vector3 fracs, float boundsOffset = 0f)
        {
            p = ClampAndNormalizeToVolume(p, data, boundsOffset);
            int cellsPerSide = data.Size - 1;

            // sometimes i'm not good at coming up with names :U
            Vector3 floored = Floor(p * cellsPerSide);

            coords = Min(floored, cellsPerSide - 1);

            fracs = Frac(p * cellsPerSide);
        }
Beispiel #7
0
        // ensure the given point is inside the volume, and then smush into the the [0, 1] range
        private static Vector3 ClampAndNormalizeToVolume(Vector3 p, SDFGPUData data, float boundsOffset = 0f)
        {
            // clamp so we're inside the volume
            p = GetClosestPointToVolume(p, data, boundsOffset);

            Vector3 minBounds = data.MinBounds;
            Vector3 maxBounds = data.MaxBounds;

            return(new Vector3(
                       Mathf.InverseLerp(minBounds.x + boundsOffset, maxBounds.x - boundsOffset, p.x),
                       Mathf.InverseLerp(minBounds.y + boundsOffset, maxBounds.y - boundsOffset, p.y),
                       Mathf.InverseLerp(minBounds.z + boundsOffset, maxBounds.z - boundsOffset, p.z)
                       ));
        }
Beispiel #8
0
        private float SampleAssetInterpolated(Vector3 p, SDFGPUData data, float boundsOffset = 0f)
        {
            GetNearestCoordinates(p, data, out Vector3 coords, out Vector3 fracs, boundsOffset);

            int x = (int)coords.x;
            int y = (int)coords.y;
            int z = (int)coords.z;

            float sampleA = GetMeshSignedDistance(x, y, z, data);
            float sampleB = GetMeshSignedDistance(x + 1, y, z, data);
            float sampleC = GetMeshSignedDistance(x, y + 1, z, data);
            float sampleD = GetMeshSignedDistance(x + 1, y + 1, z, data);
            float sampleE = GetMeshSignedDistance(x, y, z + 1, data);
            float sampleF = GetMeshSignedDistance(x + 1, y, z + 1, data);
            float sampleG = GetMeshSignedDistance(x, y + 1, z + 1, data);
            float sampleH = GetMeshSignedDistance(x + 1, y + 1, z + 1, data);

            return(Utils.TrilinearInterpolate(fracs, sampleA, sampleB, sampleC, sampleD, sampleE, sampleF, sampleG, sampleH));
        }
Beispiel #9
0
        // returns the vector pointing to the surface of the mesh representation, as well as the sign
        // (negative for inside, positive for outside)
        // this can be used to recreate a signed distance field
        private Vector3 GetDirectionToMesh(Vector3 p, SDFGPUData data, out float distSign, out Vector3 transformedP)
        {
            transformedP = data.Transform.MultiplyPoint(p);

            const float epsilon        = 0.75f;
            const float pushIntoBounds = 0.04f;

            // get the distance either at p, or at the point on the bounds nearest p
            float sample = SampleAssetInterpolated(transformedP, data);

            Vector3 closestPoint = GetClosestPointToVolume(transformedP, data, pushIntoBounds);

            Vector3 vecInBounds = (-(ComputeMeshGradient(closestPoint, data, epsilon, pushIntoBounds)).normalized * sample);
            Vector3 vecToBounds = (closestPoint - transformedP);
            Vector3 finalVec    = vecToBounds + vecInBounds;

            distSign = Mathf.Sign(sample);

            return(finalVec);
        }
Beispiel #10
0
        private static int CellCoordinateToIndex(int x, int y, int z, SDFGPUData data)
        {
            int size = data.Size;

            return(data.SampleStartIndex + (x + y * size + z * size * size));
        }
Beispiel #11
0
 private float SDF_Colour(Vector3 p, SDFGPUData data, SDFMaterialGPU material, out Vector4 colour)
 {
     colour = material.Colour;
     return(SDF(p, data));
 }
Beispiel #12
0
        private float GetMeshSignedDistance(int x, int y, int z, SDFGPUData data)
        {
            int index = CellCoordinateToIndex(x, y, z, data);

            return(m_sdfMeshSamples[index]);
        }