internal static bool PosHasVoxel(MyVoxelBase voxel, Vector3D testPos)
        {
            var planet = voxel as MyPlanet;
            var map    = voxel as MyVoxelMap;
            var hit    = new VoxelHit();

            if (planet != null)
            {
                var      from          = testPos;
                var      localPosition = (Vector3)(from - planet.PositionLeftBottomCorner);
                var      v             = localPosition / 1f;
                Vector3I voxelCoord;
                Vector3I.Floor(ref v, out voxelCoord);
                planet.Storage.ExecuteOperationFast(ref hit, MyStorageDataTypeFlags.Content, ref voxelCoord, ref voxelCoord, notifyRangeChanged: false);
            }
            else if (map != null)
            {
                var      from          = testPos;
                var      localPosition = (Vector3)(from - map.PositionLeftBottomCorner);
                var      v             = localPosition / 1f;
                Vector3I voxelCoord;
                Vector3I.Floor(ref v, out voxelCoord);
                map.Storage.ExecuteOperationFast(ref hit, MyStorageDataTypeFlags.Content, ref voxelCoord, ref voxelCoord, notifyRangeChanged: false);
            }

            return(hit.HasHit);
        }
        internal static bool CheckPointsOnLine(MyVoxelBase voxel, LineD testLine, int distBetweenPoints)
        {
            var planet      = voxel as MyPlanet;
            var map         = voxel as MyVoxelMap;
            var hit         = new VoxelHit();
            var checkPoints = (int)(testLine.Length / distBetweenPoints);

            for (int i = 0; i < checkPoints; i++)
            {
                var testPos = testLine.From + (testLine.Direction * (distBetweenPoints * i));
                //Log.Line($"i: {i} - lookAhead:{(distBetweenPoints * i)}");
                if (planet != null)
                {
                    var      from          = testPos;
                    var      localPosition = (Vector3)(from - planet.PositionLeftBottomCorner);
                    var      v             = localPosition / 1f;
                    Vector3I voxelCoord;
                    Vector3I.Floor(ref v, out voxelCoord);
                    planet.Storage.ExecuteOperationFast(ref hit, MyStorageDataTypeFlags.Content, ref voxelCoord, ref voxelCoord, notifyRangeChanged: false);
                    if (hit.HasHit)
                    {
                        return(true);
                    }
                }
                else if (map != null)
                {
                    var      from          = testPos;
                    var      localPosition = (Vector3)(from - map.PositionLeftBottomCorner);
                    var      v             = localPosition / 1f;
                    Vector3I voxelCoord;
                    Vector3I.Floor(ref v, out voxelCoord);
                    map.Storage.ExecuteOperationFast(ref hit, MyStorageDataTypeFlags.Content, ref voxelCoord, ref voxelCoord, notifyRangeChanged: false);
                    if (hit.HasHit)
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
        internal static Vector3D?ProcessVoxel(LineD trajectile, MyVoxelBase voxel, WeaponSystem system, List <Vector3I> testPoints)
        {
            var planet       = voxel as MyPlanet;
            var voxelMap     = voxel as MyVoxelMap;
            var ray          = new RayD(trajectile.From, trajectile.Direction);
            var voxelAABB    = voxel.PositionComp.WorldAABB;
            var rayVoxelDist = ray.Intersects(voxelAABB);

            if (rayVoxelDist.HasValue)
            {
                var voxelMaxLen = voxel.PositionComp.WorldVolume.Radius * 2;
                var start       = trajectile.From + (ray.Direction * rayVoxelDist.Value);
                var lenRemain   = trajectile.Length - rayVoxelDist.Value;
                var end         = voxelMaxLen > lenRemain ? start + (ray.Direction * lenRemain) : start + (ray.Direction * voxelMaxLen);
                var testLine    = new LineD(trajectile.From + (ray.Direction * rayVoxelDist.Value), end);
                var rotMatrix   = Quaternion.CreateFromRotationMatrix(voxel.WorldMatrix);
                var obb         = new MyOrientedBoundingBoxD(voxel.PositionComp.WorldAABB.Center, voxel.PositionComp.LocalAABB.HalfExtents, rotMatrix);
                if (obb.Intersects(ref testLine) != null)
                {
                    Log.Line("obb");
                    if (planet != null)
                    {
                        var startPos = trajectile.From - planet.PositionLeftBottomCorner;
                        var startInt = Vector3I.Round(startPos);
                        var endPos   = trajectile.To - planet.PositionLeftBottomCorner;
                        var endInt   = Vector3I.Round(endPos);

                        BresenhamLineDraw(startInt, endInt, testPoints);

                        for (int i = 0; i < testPoints.Count; ++i)
                        {
                            var voxelCoord = testPoints[i];
                            var voxelHit   = new VoxelHit();
                            planet.Storage.ExecuteOperationFast(ref voxelHit, MyStorageDataTypeFlags.Content, ref voxelCoord, ref voxelCoord, notifyRangeChanged: false);
                            if (voxelHit.HasHit)
                            {
                                return((Vector3D)voxelCoord + planet.PositionLeftBottomCorner);
                            }
                        }
                    }
                    else if (voxelMap != null)
                    {
                        var startPos = trajectile.From - voxelMap.PositionLeftBottomCorner;
                        var startInt = Vector3I.Round(startPos);
                        var endPos   = trajectile.To - voxelMap.PositionLeftBottomCorner;
                        var endInt   = Vector3I.Round(endPos);

                        BresenhamLineDraw(startInt, endInt, testPoints);

                        for (int i = 0; i < testPoints.Count; ++i)
                        {
                            var voxelCoord = testPoints[i];
                            var voxelHit   = new VoxelHit();
                            voxelMap.Storage.ExecuteOperationFast(ref voxelHit, MyStorageDataTypeFlags.Content, ref voxelCoord, ref voxelCoord, notifyRangeChanged: false);
                            if (voxelHit.HasHit)
                            {
                                return((Vector3D)voxelCoord + voxelMap.PositionLeftBottomCorner);
                            }
                        }
                    }
                }
            }

            return(null);
        }
        bool RaycastChunk(Ray ray, WorldChunk chunk, out VoxelHit hit)
        {
            //if (!chunk.Bounds.IntersectRay(ray)) {
            //    hit = new VoxelHit();
            //    return false;
            //}

            VoxelHit currentHit      = new VoxelHit();
            float    currentDistance = 0;
            bool     hasHit          = false;

            foreach (var v in chunk.Voxels)
            {
                if (v.Instance)
                {
                    var collider = v.Instance.GetComponent <BoxCollider>();

                    Debug.Assert(collider);

                    RaycastHit h;
                    if (collider.Raycast(ray, out h, chunk.Length))
                    {
                        if (!hasHit || h.distance < currentDistance)
                        {
                            hasHit          = true;
                            currentDistance = h.distance;
                            currentHit      = new VoxelHit {
                                Voxel = v, WorldNorma = h.normal, Normal = chunk.ChunkContainer.transform.InverseTransformDirection(h.normal)
                            };
                        }
                    }
                }
            }

            hit = currentHit;

            if (hasHit)
            {
                hit = currentHit;
                return(true);
            }
            else
            {
                var   chunkOrigin = chunk.ChunkContainer.transform.position;
                var   plane       = new Plane(new Vector3(0, 1, 0), -chunkOrigin.y + 0.5f * Settings.CunkScale);
                float d;
                if (plane.Raycast(ray, out d))
                {
                    var p = chunk.ChunkContainer.transform.InverseTransformPoint(ray.GetPoint(d));

                    var i = Mathf.FloorToInt(p.x + 0.5f);
                    var j = -1;
                    var k = Mathf.FloorToInt(p.z + 0.5f);

                    hit = new VoxelHit {
                        Voxel = new Voxel {
                            PrefabId = "", i = i, j = j, k = k
                        }, Normal = new Vector3(0, 1, 0)
                    };

                    return(true);
                }
            }

            return(false);
        }
예제 #5
0
    //const float kEps = float.Epsilon * 16;
    //const float kEps = float.Epsilon;
    //const float kEps = float.Epsilon;
    //const float kEps = 0;

    public bool RaycastVoxel(Vector3 origin, Vector3 direction, out VoxelHit hitInfo)
    {
        hitInfo = new VoxelHit();

        direction = Vector3.Normalize(direction);

        if (voxels == null)
        {
            throw new InvalidOperationException("Tried to raycast on an empty voxel set");
        }

        //Vector3 size = VecUtil.Mul(new Vector3(voxels.Size.x, voxels.Size.y, voxels.Size.z), transform.lossyScale);
        Vector3 size = new Vector3(voxels.Size.x, voxels.Size.y, voxels.Size.z);

        // TODO: Does this account for scale properly? Probably not.
        Ray ray = new Ray(
            transform.InverseTransformPoint(origin),
            transform.InverseTransformVector(direction)
            );

        bool inside = true;

        // Check each dimension to see if origin is inside the voxel set
        for (int i = 0; i < 3; ++i)
        {
            if (ray.origin[i] < 0 || ray.origin[i] > size[i])
            {
                inside = false;
            }
        }

        float dist = 0;

        if (!inside)
        {
            // Find a point on the surface to start at.
            float minT = float.PositiveInfinity;

            // Find first intersection
            for (int i = 0; i < 3; ++i)
            {
                if (ray.direction[i] == 0)
                {
                    continue;
                }

                for (int j = 0; j < 2; ++j)
                {
                    // TODO: Use true int size instead?
                    float t = (j * size[i] - ray.origin[i]) / ray.direction[i];

                    if (t < 0)
                    {
                        continue;
                    }

                    Vector3 probePoint = ray.origin + ray.direction * t;
                    bool    validHit   = true;

                    for (int k = 0; k < 3; ++k)
                    {
                        if (k == i)
                        {
                            // Current dimension *must* hit; don't check to avoid precision issues
                            continue;
                        }

                        if (probePoint[k] < 0 || probePoint[k] > size[k])
                        {
                            validHit = false;
                        }
                    }

                    if (validHit)
                    {
                        minT = Mathf.Min(t, minT);
                    }
                }
            }

            // TODO: Be more elegant about an invalid minT (no hit)
            //ray.origin += (minT + kEps) * ray.direction;
            //ray.origin += (minT + 0.00005f) * ray.direction;
            dist = minT + 0.00005f;
        }

        if (LayerMarch(ray.origin, ray.direction, out hitInfo.index, out hitInfo.neighborIndex, ref dist))
        {
            hitInfo.point = transform.TransformPoint(ray.GetPoint(dist));
            // TODO: Find a quicker way to do this; must account for non-uniform scale
            hitInfo.distance = (hitInfo.point - origin).magnitude;

            Vec3i finalIdx = ToIndex(transform.InverseTransformPoint(origin + direction * (hitInfo.distance + kEps)));
            if (finalIdx.x != hitInfo.index.x ||
                finalIdx.y != hitInfo.index.y ||
                finalIdx.z != hitInfo.index.z)
            {
                Debug.LogError("Final hit mismatch. Expected " + finalIdx + " but was " + hitInfo.index);
            }

            Vec3i delta = hitInfo.neighborIndex - hitInfo.index;
            hitInfo.normal = transform.TransformDirection(new Vector3(delta.x, delta.y, delta.z));
            return(true);
        }
        else
        {
            return(false);
        }
    }