public static void AccessorSpaceToAccessorSpacePosition(this IWorldRAccessor self, IWorldRAccessor accessor, ref int x, ref int y, ref int z)
        {
            Vector3Int origin = self.WorldSpaceOrigin - accessor.WorldSpaceOrigin;

            x += origin.x;
            y += origin.y;
            z += origin.z;
        }
        protected bool ClipFace(Vector3Int pos, BlockData block, BlockFace face, IWorldRAccessor accessor)
        {
            switch (face)
            {
            case BlockFace.PositiveX: pos.x++; break;

            case BlockFace.PositiveY: pos.y++; break;

            case BlockFace.PositiveZ: pos.z++; break;

            case BlockFace.NegativeX: pos.x--; break;

            case BlockFace.NegativeY: pos.y--; break;

            case BlockFace.NegativeZ: pos.z--; break;

            default: throw new NotSupportedException("Unknown BlockFace.");
            }

            BlockData neighbor = accessor.GetBlock(pos.x, pos.y, pos.z);

            if (neighbor == null)
            {
                return(AggressiveBlockFaceClipping);
            }

            BlockMesh mesh = accessor.World.BlockDataTable.GetMesh(neighbor.Mesh.Value);
            Vector3   size = mesh.BoundingBox.Size;

            if (size.x < 1 || size.y < 1 || size.z < 1)
            {
                return(false);
            }

            switch (block.PhysicState)
            {
            case PhysicState.Fluid:
                return((block == neighbor) || neighbor.IsOpaqueBlock());

            case PhysicState.Solid:
                return(neighbor.IsOpaqueBlock());

            default:
                throw new NotSupportedException("Unknown BlockPhysicalState");
            }
        }
 public static void AccessorSpaceToWorldSpacePosition(this IWorldRAccessor accessor, ref int x, ref int y, ref int z)
 {
     AccessorSpaceToWorldSpacePosition(accessor.WorldSpaceOrigin, ref x, ref y, ref z);
 }
        public static Vector2 AmbientOcclusion(Vector3Int pos, BlockFace face, BlockFaceCorner corner, IWorldRAccessor accessor, bool fastMode)
        {
            if (fastMode)
            {
                float skyLight = MapLight01(accessor.GetSkyLight(pos.x, pos.y, pos.z));
                float ambient  = MapLight01(accessor.GetAmbientLight(pos.x, pos.y, pos.z));
                return(new Vector2(skyLight, ambient));
            }

            int     faceIndex   = (int)face;
            int     cornerIndex = (int)corner;
            Vector2 lights      = Vector2Int.zero;

            for (int i = 0; i < AmbientLightSampleCount; i++)
            {
                Vector3Int p = pos + AmbientLightSampleDirections[faceIndex, cornerIndex, i];
                lights.x += accessor.GetSkyLight(p.x, p.y, p.z);
                lights.y += accessor.GetAmbientLight(p.x, p.y, p.z);
            }

            return(MapLight01(lights / AmbientLightSampleCount));
        }
        public void AddBlock(Vector3Int pos, Vector3Int renderOffset, BlockData block, IWorldRAccessor accessor)
        {
            Quaternion rotation = accessor.GetBlockRotation(pos.x, pos.y, pos.z, Quaternion.identity);
            BlockMesh  mesh     = accessor.World.BlockDataTable.GetMesh(block.Mesh.Value);

            for (int i = 0; i < mesh.Faces.Length; i++)
            {
                BlockMesh.FaceData face    = mesh.Faces[i];
                BlockFace          faceDir = RotateFace(face.Face, rotation);

                if (EnableFaceClipping)
                {
                    // 没有撑满一格的方块所有的面都渲染
                    Vector3 size      = mesh.BoundingBox.Size;
                    bool    neverClip = face.NeverClip | size.x < 1 | size.y < 1 | size.z < 1;

                    if (!neverClip && ClipFace(pos, block, faceDir, accessor))
                    {
                        continue;
                    }
                }

                int?[] texIndices = block.Textures[i];

                // !!! must add indices first
                for (int j = 0; j < face.Indices.Length; j++)
                {
                    AddIndex(face.Indices[j], block.Material.Value);
                }

                for (int j = 0; j < face.Vertices.Length; j++)
                {
                    BlockVertexData vertex = face.Vertices[j];
                    vertex.Position = MathUtility.RotatePoint(vertex.Position, rotation, mesh.Pivot);

                    float   emission = block.GetEmissionValue();
                    Vector2 ambient  = LightingUtility.AmbientOcclusion(pos, faceDir, vertex.CornerInFace, accessor, !EnableAmbientOcclusion);

                    Vector3 posWS = WriteBlockWSPosToVertexData ? (pos + accessor.WorldSpaceOrigin) : Vector3.down;

                    AddVertex(new BlockMeshVertexData
                    {
                        PositionOS      = vertex.Position + pos + renderOffset,
                        UV              = vertex.UV,
                        TexIndices      = new Vector3Int(texIndices[0].Value, texIndices[1].Value, texIndices[2].Value),
                        Lights          = new Vector3(emission, ambient.x, ambient.y),
                        BlockPositionWS = posWS
                    });
                }
            }
        }