#pragma once #include "rbx/Boost.hpp" #include "Util/G3DCore.h" #include "Util/Vector3int32.h" #include "GfxCore/Resource.h" #include "voxel/Voxelizer.h" namespace RBX { class PartInstance; class Frustum; class Extents; class MegaClusterInstance; class ContactManager; namespace Voxel { class Grid; } } namespace RBX { namespace Graphics { using RBX::Voxel::DataModelPartCache; class VisualEngine; class SpatialHashedScene; struct LightShadowSlice; struct LightShadowMap; class LightObject; class Texture; const int kLightGridChunkSizeXZ = kVoxelChunkSizeXZ; const int kLightGridChunkSizeY = kVoxelChunkSizeY; const Vector3int32 kLightGridChunkSize = kVoxelChunkSize; struct LightGridChunkFringeY { unsigned char data[kLightGridChunkSizeXZ][kLightGridChunkSizeXZ]; }; struct LightGridChunkFringeXZ { unsigned char data[kLightGridChunkSizeY][kLightGridChunkSizeXZ]; }; struct LightGridChunk : Voxel::OccupancyChunk { enum DirtyStatus { Dirty_LightingLocalShadowed = 1 << 1, Dirty_LightingLocal = 1 << 2, Dirty_LightingSkylight = 1 << 3, Dirty_LightingGlobal = 1 << 4, Dirty_LightingUpload = 1 << 5, Dirty_Occupancy = 1 << 6, Dirty_HighPriority = 1 << 7, Dirty_OccupancyAndDependents = Dirty_Occupancy | Dirty_LightingGlobal | Dirty_LightingSkylight | Dirty_LightingLocalShadowed }; unsigned int distancePriority; unsigned int neverDirty; // 3D array order: [y][z][x] unsigned char lighting[kLightGridChunkSizeY][kLightGridChunkSizeXZ][kLightGridChunkSizeXZ][4]; unsigned char lightingSkylight[kLightGridChunkSizeY][kLightGridChunkSizeXZ][kLightGridChunkSizeXZ]; // Per-slice average of lighting data unsigned int lightingAverageGlobal[kLightGridChunkSizeY]; unsigned int lightingAverageSkylight[kLightGridChunkSizeY]; unsigned int lightingAverageWeight[kLightGridChunkSizeY]; // fringe data for inter-chunk luminance propagation LightGridChunkFringeXZ irradianceFringeX; LightGridChunkFringeY irradianceFringeY; LightGridChunkFringeXZ irradianceFringeZ; LightGridChunkFringeY irradianceFringeSkyY; LightGridChunkFringeXZ irradianceFringeSkyX0; LightGridChunkFringeXZ irradianceFringeSkyX1; LightGridChunkFringeXZ irradianceFringeSkyZ0; LightGridChunkFringeXZ irradianceFringeSkyZ1; }; class LightGrid: public Resource { public: enum TextureMode { Texture_None, Texture_2D, Texture_3D }; static LightGrid* create(VisualEngine* visualEngine, const Vector3int32& chunkCount, TextureMode textureMode); LightGrid(VisualEngine* visualEngine, const shared_ptr& texture, const shared_ptr& lookupTexture, const Vector3int32& chunkCount); ~LightGrid(); void occupancyUpdateChunkPrepare(Voxel::OccupancyChunk& chunk, MegaClusterInstance* terrain, ContactManager* contactManager, std::vector< DataModelPartCache >& partCache); void occupancyUpdateChunkPerform(const std::vector< DataModelPartCache >& partCache); void lightingUpdateChunkLocal(LightGridChunk& chunk, SpatialHashedScene* spatialHashedScene); void lightingUpdateChunkGlobal(LightGridChunk& chunk); void lightingUpdateChunkSkylight(LightGridChunk& chunk); void lightingUpdateChunkAverage(LightGridChunk& chunk); void lightingUploadChunk(LightGridChunk& chunk); void lightingUploadCommit(); void lightingClearAll(); void lightingUploadAll(); bool updateGridCenter(const Vector3& cameraTarget, bool skipChunkUpdate); void updateBorderColor(const Vector3& cameraTarget, const Frustum& cameraFrustum); void updateAgePriorityForChunks(const Vector3& cameraTarget); void setLightShadows(bool value); void setLightDirection(const Vector3& value); void setSkyAmbient(const Color3uint8& value); void invalidateAll(unsigned int status); void invalidateExtents(const Extents& extents, unsigned int status); void invalidatePoint(const Vector3& point, unsigned int status); Color4uint8 computeAverageColor(const Vector3& focusPoint); Vector3 getGridCornerOffset() const; Vector3 getWrapSafeOffset() const; Vector3 getGridSize() const; Color4uint8 getBorderColor() const; Vector3int32 getChunkCount() const { return chunkCount; } bool hasTexture() const { return !!texture; } const shared_ptr& getTexture() const { return texture; } const shared_ptr& getLookupTexture() const { return lookupTexture; } LightGridChunk* findDirtyChunk(); LightGridChunk* findFirstDirtyChunk(); LightGridChunk* findOldestChunk(); void setNonFixedPartsEnabled(bool value); bool getNonFixedPartsEnabled() const; virtual void onDeviceRestored(); private: LightGridChunk* getChunkByIndex(const Vector3int32& index); LightGridChunk* getChunkByLocalIndex(const Vector3int32& index); bool isChunkInsideGridLocal(const Vector3int32& index); Vector3int32 getChunkIndexForPoint(const Vector3& v); Vector3int32 getWrappedChunkIndex(const Vector3int32& index) const; void lightingUpdateDirectional(LightGridChunk& chunk, const Vector3& lightDirection); template void lightingUpdateDirectionalImpl(LightGridChunk& chunk, const Vector3int32& lightContrib); void lightingUpdateSkylight(LightGridChunk& chunk); void lightingUpdateSkylightRow(LightGridChunk& chunk, int y, int z, const unsigned char* powerCurveLUT); void lightingUpdateSkylightRowSIMD(LightGridChunk& chunk, int y, int z, const unsigned char* powerCurveLUT); void lightingUpdateAverageImpl(LightGridChunk& chunk); void lightingUpdateAverageImplSIMD(LightGridChunk& chunk); void lightingGetLights(std::vector& lights, const Extents& chunkExtents, SpatialHashedScene* spatialHashedScene); void lightingUpdateLightScratch(const LightGridChunk& chunk, const Extents& chunkExtents, LightObject* lobj); void lightingComputeShadowMask(const LightGridChunk& chunk, const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3& lightPosition, LightShadowMap& shadowMap); void lightingFixupShadowMaskBorder(const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell); template void lightingTransferShadowSliceToShadowMask(const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell, int shadowMapSize, const LightShadowSlice& shadowSlice0, const LightShadowSlice& shadowSlice1); template void lightingTransferShadowMaskToShadowSlice(const LightGridChunk& chunk, const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell, int shadowMapSize, LightShadowSlice& shadowSlice0, LightShadowSlice& shadowSlice1); void lightingComputeShadowMaskXYZ(const LightGridChunk& chunk, const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell, const Vector3& lightFraction); template void lightingComputeShadowMaskYZ(const LightGridChunk& chunk, const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell, const Vector3& lightFraction); template void lightingComputeShadowMaskZ(const LightGridChunk& chunk, const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell, const Vector3& lightFraction); template void lightingComputeShadowMask(const LightGridChunk& chunk, const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell, const Vector3& lightFraction); template void lightingComputeShadowMaskImplLUT(const LightGridChunk& chunk, const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell, const Vector3& lightFraction); template void lightingComputeShadowMaskImplSmooth(const LightGridChunk& chunk, const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell, const Vector3& lightFraction); template void lightingComputeShadowMaskImplSmoothSIMD(const LightGridChunk& chunk, const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3int32& lightCell, const Vector3& lightFraction); template void lightingUpdatePointLightScratch(const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3& lightPosition, float lightRadius, const Color3uint8& lightColor, float lightIntensity); template void lightingUpdatePointLightScratchSIMD(const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3& lightPosition, float lightRadius, const Color3uint8& lightColor, float lightIntensity); template void lightingUpdateSpotLightScratch(const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3& lightPosition, float lightRadius, const Vector3& lightDirection, float lightConeAngle, const Color3uint8& lightColor, float lightIntensity); template void lightingUpdateSpotLightScratchSIMD(const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3& lightPosition, float lightRadius, const Vector3& lightDirection, float lightConeAngle, const Color3uint8& lightColor, float lightIntensity); template void lightingUpdateSurfaceLightScratch(const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3& lightPosition, float lightRadius, const Vector3& lightDirection, float lightConeAngle, const Vector4& axisU, const Vector4& axisV, const Color3uint8& lightColor, float lightIntensity); template void lightingUpdateSurfaceLightScratchSIMD(const Vector3int32& extentsMin, const Vector3int32& extentsMax, const Vector3& lightPosition, float lightRadius, const Vector3& lightDirection, float lightConeAngle, const Vector4& axisU, const Vector4& axisV, const Color3uint8& lightColor, float lightIntensity); template void lightingBlurAxisYZScratch(); template void lightingBlurAxisYZScratchSIMD(); void lightingBlurAxisXScratchToChunk(LightGridChunk& chunk); void lightingBlurAxisXScratchToChunkSIMD(LightGridChunk& chunk); void lightingClearLocal(LightGridChunk& chunk); void lightingClearGlobal(LightGridChunk& chunk); void lightingComposit(const LightGridChunk& chunk, unsigned char* data, unsigned int rowPitch, unsigned int slicePitch); void lightingCompositImpl(const LightGridChunk& chunk, unsigned char* data, unsigned int rowPitch, unsigned int slicePitch, const Color3uint8& skyAmbient); void lightingCompositImplSIMD(const LightGridChunk& chunk, unsigned char* data, unsigned int rowPitch, unsigned int slicePitch, const Color3uint8& skyAmbient); void relocateGrid(const Vector3int32& newCorner, bool skipChunkUpdate); void stepCursor(Vector3int32& cursor); void precomputeShadowLUT(); Color3uint8 transformColor(const Color3uint8& color) const; Color4uint8 transformColor(const Color4uint8& color) const; // 3D array order: [y][z][x] std::vector chunks; Vector3int32 chunkCount; Vector3int32 cornerChunkIndex; VisualEngine* visualEngine; shared_ptr texture; shared_ptr lookupTexture; bool useSIMD; bool lightShadows; Vector3 lightDirection; Color3uint8 skyAmbient; Vector3int32 dirtyCursor; Vector3int32 dirtyCursorDirection; unsigned char lightBorderGlobal; unsigned char lightBorderSkylight; LightGridChunkFringeXZ dummyFringeXZ255; LightGridChunkFringeY dummyFringeY255; struct ShadowLUTEntry { unsigned char x, y, z; unsigned char add; }; enum { kShadowLUTSize = 16 }; ShadowLUTEntry shadowLUT[kShadowLUTSize][kShadowLUTSize][kShadowLUTSize]; unsigned char irradianceScratch[kLightGridChunkSizeY+2][kLightGridChunkSizeXZ+2][kLightGridChunkSizeXZ+2]; // Each value here uses 10 bits per channel, with 8 bits for the value and 2 bits as carry bits (that are always zero except for intermediate values) unsigned int lightingScratch[kLightGridChunkSizeY+2][kLightGridChunkSizeXZ+2][kLightGridChunkSizeXZ+6]; unsigned char shadowMask[kLightGridChunkSizeY+2][kLightGridChunkSizeXZ+2][kLightGridChunkSizeXZ+6]; unsigned char uploadScratch[kLightGridChunkSizeY][kLightGridChunkSizeXZ][kLightGridChunkSizeXZ][4]; Voxel::Voxelizer voxelizer; }; } }