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); }
//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); } }