123
This commit is contained in:
852
Editor/LightmapCompiler/IndoorLightPatches.h
Normal file
852
Editor/LightmapCompiler/IndoorLightPatches.h
Normal file
@@ -0,0 +1,852 @@
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Crytek CryENGINE source code
|
||||
// History:
|
||||
// - Created by Marco Corbetta
|
||||
// - Changed by Tim Schroeder
|
||||
// - Partial rewrite for editor integration
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
#pragma once
|
||||
|
||||
#ifndef __INDOOR_LIGHT_PATCHES_H__
|
||||
#define __INDOOR_LIGHT_PATCHES_H__
|
||||
|
||||
//#define REDUCE_DOT3LIGHTMAPS_TO_CLASSIC // for debugging
|
||||
//#define DISPLAY_MORE_INFO
|
||||
|
||||
//typedef float real;
|
||||
typedef double real;//typedef controlling the accuracy
|
||||
|
||||
#define HDR_EXP_BASE (1.04)
|
||||
#define HDR_EXP_OFFSET (64.0)
|
||||
#define HDR_LOG(a, b) ( log(b) / log(a) )
|
||||
|
||||
#include <float.h>
|
||||
#include "LMCompCommon.h"
|
||||
#include "LMCompStructures.h"
|
||||
#include "IEntityRenderstate.h"
|
||||
#include "LMLightCollection.h"
|
||||
#include "..\Objects\BrushObject.h"
|
||||
#include "I3dEngine.h"
|
||||
#include <direct.h>
|
||||
|
||||
static const float scfMaxGridSize = 2.f;
|
||||
|
||||
#define MIN_LIGHTMAP_SIZE 4
|
||||
|
||||
//flags for CRadPoly
|
||||
#define NOLIGHTMAP_FLAG 1
|
||||
#define MERGE_FLAG 2
|
||||
#define SHARED_FLAG 4
|
||||
#define MERGE_SOURCE_FLAG 8
|
||||
#define DECAL_FLAG 64
|
||||
#define DO_NOT_COMPRESS_FLAG 128 //flag for patches
|
||||
|
||||
|
||||
#define WRONG_NORMALS_FLAG 16
|
||||
#define NOT_NORMALIZED_NORMALS_FLAG 32
|
||||
#define ONLY_SUNLIGHT 256 //flag for mesh
|
||||
#define DOUBLE_SIDED_MAT 512 //flag for mesh
|
||||
#define REBUILD_USED 1024 //flag for mesh
|
||||
#define CAST_LIGHTMAP 2048 //flag for mesh
|
||||
#define RECEIVES_SUNLIGHT 4096 //flag for mesh
|
||||
#define HASH_CHANGED 8192 //flag for mesh
|
||||
#define RECEIVES_LIGHTMAP (8192<<1) //flag for mesh
|
||||
|
||||
//forces the patches to align on 4 pixel boundaries
|
||||
#define MAKE_BLOCK_ALIGN
|
||||
|
||||
struct SUV
|
||||
{
|
||||
float u,v; //texture coordinates
|
||||
};
|
||||
|
||||
inline const AABB MakeSafeAABB(const Vec3& rMin, const Vec3& rMax)
|
||||
{
|
||||
static const float scfMargin = 0.1f;//margin to add
|
||||
Vec3 vMin(rMin); Vec3 vMax(rMax);
|
||||
if(vMin.x == vMax.x) vMax.x += scfMargin;
|
||||
if(vMin.y == vMax.y) vMax.y += scfMargin;
|
||||
if(vMin.z == vMax.z) vMax.z += scfMargin;
|
||||
return AABB(vMin, vMax);
|
||||
}
|
||||
|
||||
//used for warning gathering
|
||||
typedef enum
|
||||
{
|
||||
EWARNING_EXPORT_FAILED = 0, //!< export of lightmaps has failed
|
||||
EWARNING_LIGHT_EXPORT_FAILED, //!< export of lightsources has failed
|
||||
EWARNING_DOUBLE_SIDED, //!< double sided material
|
||||
EWARNING_TOO_MANY_OCCL_LIGHTS, //!< more than 4 active occlusion map light sources at the same time on glm
|
||||
EWARNING_NO_FIT, //!< glm does not fit into a single lightmap
|
||||
EWARNING_HUGE_PATCH, //!< has patch(es) which are larger than halve a lightmap wide or high
|
||||
EWARNING_WRONG_NORMALS, //!< glm has wrong normals
|
||||
EWARNING_DENORM_NORMALS, //!< glm has denormalized normals
|
||||
EWARNING_LIGHT_RADIUS, //!< light has a too little radius
|
||||
EWARNING_LIGHT_INTENSITY, //!< light has a too little intensity
|
||||
EWARNING_LIGHT_FRUSTUM //!< spotlight has invalid frustum
|
||||
}EWARNING_TYPE;
|
||||
|
||||
static const unsigned int scuiWarningTextAllocation = 300;//number of chars allocated on stack for warning string
|
||||
|
||||
static inline const bool IsNormalized(const float cfSqLen)
|
||||
{
|
||||
static const float scfThreshold = 0.1f;
|
||||
if(fabs(cfSqLen - 1.f) < scfThreshold)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//supports flexible subsampling patterns, but for simplicity just use 9x or nothing for now
|
||||
class CAASettings
|
||||
{
|
||||
protected:
|
||||
unsigned int m_uiScale;
|
||||
float m_fInvScale;
|
||||
public:
|
||||
bool m_bEnabled;
|
||||
CAASettings():m_bEnabled(false),m_uiScale(1),m_fInvScale(1.0f){}
|
||||
void SetScale(const unsigned int cuiScale)
|
||||
{
|
||||
assert(cuiScale != 0);
|
||||
m_uiScale = cuiScale;
|
||||
m_fInvScale = 1.0f / (float)cuiScale;
|
||||
}
|
||||
const float GetInvScale()const{return m_fInvScale;}
|
||||
const unsigned int GetScale()const{return m_uiScale;}
|
||||
const float RetrieveRealSamplePos(const real cfOrig)
|
||||
{
|
||||
switch(m_uiScale)
|
||||
{
|
||||
case 1:
|
||||
return cfOrig;
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
const real cfNumber = (real)((int)(cfOrig * 0.5f));
|
||||
return (cfNumber - (real)1.0f/(real)3.0 + (real)2.0/(real)3.0 * (cfOrig - cfNumber * (real)2.0));//map onto -1/3, 1/3, 2/3, 4/3,...
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
return ((real)1.0f/(real)3.0 * cfOrig - (real)1.0f/(real)3.0);//map onto -1/3, 0/3, 1/3, 2/3, 3/3, 4/3,...
|
||||
break;
|
||||
default:
|
||||
return m_fInvScale * cfOrig;
|
||||
}
|
||||
}
|
||||
//returns the middle index, or tells whether this is the one or not
|
||||
const bool IsMiddle(const unsigned int cuiX, const unsigned int cuiY)
|
||||
{
|
||||
switch(m_uiScale)
|
||||
{
|
||||
case 1:
|
||||
return true;
|
||||
case 2:
|
||||
return (cuiX == 1 && cuiY == 1);
|
||||
case 3:
|
||||
return (cuiX == 1 && cuiY == 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class CLightPatch;
|
||||
class CRadPoly;
|
||||
class CRadVertex;
|
||||
class CRadMesh;
|
||||
struct IStatObj;
|
||||
class CLightScene;
|
||||
|
||||
typedef std::vector<CRadPoly *> radpolylist;
|
||||
typedef std::vector<CRadPoly *>::iterator radpolyit;
|
||||
typedef std::vector<CRadVertex> radvertexlist;
|
||||
typedef std::vector<CRadVertex>::iterator radvertexit;
|
||||
typedef std::list<CLightPatch *> lightpatchlist;
|
||||
typedef std::list<CLightPatch *>::iterator lightpatchit;
|
||||
typedef std::list<CRadMesh *> radmeshlist;
|
||||
typedef std::list<CRadMesh *>::iterator radmeshit;
|
||||
|
||||
typedef std::vector<std::pair<CRadPoly*,unsigned int> >::iterator SharedIter;
|
||||
typedef std::vector<CRadVertex *> radpvertexlist;
|
||||
typedef std::vector<CRadVertex *>::iterator radpvertexit;
|
||||
|
||||
#define PLANE_MX 3
|
||||
#define PLANE_MY 4
|
||||
#define PLANE_MZ 5
|
||||
|
||||
const float cfNormalizeThreshold = 0.00001f;
|
||||
|
||||
//need this shitty class because it is a bit too late to use a smart pointer and let it reference
|
||||
//use a map and the address as key
|
||||
class CRasterCubeManager
|
||||
{
|
||||
public:
|
||||
CRasterCubeManager(){};
|
||||
~CRasterCubeManager();
|
||||
void AddReference(const CRadMesh* cpRadMesh);
|
||||
CRasterCubeImpl* CreateRasterCube();
|
||||
const bool RemoveReference(CRadMesh* cpRadMesh);
|
||||
void Clear();
|
||||
|
||||
protected:
|
||||
std::map<CRasterCubeImpl*, std::set<const CRadMesh*> > m_mRasterCubeMap; //keeps track of each rastercube allocation
|
||||
};
|
||||
|
||||
// contains all information which a certain dot3 dominant light dir texel was stored with
|
||||
// also controls subsampling
|
||||
typedef struct SComplexOSDot3Texel
|
||||
{
|
||||
Vec3d vDot3Light; //!< world space light vector
|
||||
CRadPoly *pSourcePatch; //!< pointer to triangle where tangent space comes from, is always on this patch
|
||||
float fAlpha; //!< barycentric alpha value
|
||||
float fBeta; //!< barycentric beta value
|
||||
unsigned int uiLightMask; //!< lightmask
|
||||
unsigned int bNotHit; //!< true if this was a snapped texel
|
||||
SComplexOSDot3Texel():vDot3Light(),pSourcePatch(NULL),fAlpha(0.f),fBeta(0.f),uiLightMask(0),bNotHit(false){}
|
||||
const Vec3d TransformIntoTS(Vec3d& rSource)const;
|
||||
}SComplexOSDot3Texel;
|
||||
|
||||
//calc the area of a triangle using texture coords
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
inline float CalcTriangleArea( const Vec3d &A, const Vec3d &B, const Vec3d &C )
|
||||
{
|
||||
return( GetLength( (C-A).Cross(B-A) )*0.5f );
|
||||
}
|
||||
|
||||
__inline int CalcPlaneType2(const Vec3d& n)
|
||||
{
|
||||
if (((1.0f-n.x)<0.001f) && ((1.0f-n.x)>=0))
|
||||
return PLANE_X;
|
||||
else
|
||||
if (((1.0f-n.y)<0.001f) && ((1.0f-n.y)>=0))
|
||||
return PLANE_Y;
|
||||
else
|
||||
if (((1.0f-n.z)<0.001f) && ((1.0f-n.x)>=0))
|
||||
return PLANE_Z;
|
||||
else
|
||||
{
|
||||
float ax = fabs(n[0]);
|
||||
float ay = fabs(n[1]);
|
||||
float az = fabs(n[2]);
|
||||
|
||||
if (ax>=ay && ax>=az)
|
||||
return PLANE_MX;
|
||||
else
|
||||
if (ay>=ax && ay>=az)
|
||||
return PLANE_MY;
|
||||
else
|
||||
return PLANE_MZ;
|
||||
}
|
||||
}
|
||||
|
||||
const float DistToLine(const Vec3d& rX0, const Vec3d& rX1, const Vec3d& rPoint);
|
||||
const Vec3d ProjectOntoEdge(const Vec3d& rX0, const Vec3d& rX1, const Vec3d& rPoint, const float cfDistLV);
|
||||
|
||||
inline const unsigned int RoundFromFloat(const float cfTex)
|
||||
{
|
||||
unsigned int uiNumber = (unsigned int)cfTex;
|
||||
if(cfTex - (float)uiNumber >= 0.5f)
|
||||
uiNumber++;
|
||||
return uiNumber;
|
||||
}
|
||||
|
||||
const Vec3d RotateIntoPlane(const Vec3d& vPlaneNormal0, const Vec3d& vPlaneNormal1, const Vec3d& rInPosition, const Vec3d& rSource0);
|
||||
|
||||
//! \brief used local during generation of light clustering arrangement
|
||||
struct GLMCluster
|
||||
{
|
||||
Vec3d vMin;
|
||||
Vec3d vMax;
|
||||
std::set<IEntityRender *> vGLMsAffectingCluster;
|
||||
};
|
||||
|
||||
class CRadVertex
|
||||
{
|
||||
public:
|
||||
Vec3d m_vPos; //!< in world space
|
||||
Vec3d m_vNormal; //!< vertex normal for smooth lighting calulation
|
||||
float m_fpX,m_fpY; //!< used as projection coordinates and final texture coordinates as well
|
||||
|
||||
Vec3d m_vTNormal; //!<
|
||||
Vec3d m_vBinormal; //!<
|
||||
Vec3d m_vTangent; //!<
|
||||
|
||||
CRadVertex() : m_vPos(0.f,0.f,0.f), m_vNormal(0.f,0.f,0.f), m_fpX(0.f), m_fpY(0.f), m_vTNormal(0.f,0.f,0.f), m_vBinormal(0.f,0.f,0.f), m_vTangent(0.f,0.f,0.f)
|
||||
{}
|
||||
};
|
||||
|
||||
class CRadPoly
|
||||
{
|
||||
private:
|
||||
void FreeLightmaps( void );
|
||||
|
||||
//! used by GetNearestPolyAt()
|
||||
const float PointInTriangle(const Vec3d &point, const int ciIndex0, const int ciIndex1);
|
||||
|
||||
public:
|
||||
static const unsigned int scuiOneVertexShareFlag = 0x7F;
|
||||
//calculates the tangent space from the face information and applies it
|
||||
void CalculateTangentSpace(SUV uv[3]);
|
||||
|
||||
//passes pointer to all contained polys to give them access for averaging
|
||||
void SynchronizeLightmaps();
|
||||
|
||||
static void ApplyBaryCoordsToVertex(CRadVertex& rDest, const CRadVertex& rSource0, const CRadVertex& rSource1, const CRadVertex& rSource2, float cfAlpha, float cfBeta, const bool cbCOmputeTS = true);
|
||||
const bool CheckPointInTriangle(Vec3d &inPosition, const Vec3d &rVert0, const Vec3d &rVert1, const Vec3d &rVert2, float &rOutfAlpha, float &rOutfBeta, float &rfArea3d);
|
||||
|
||||
//! construtor
|
||||
CRadPoly();
|
||||
|
||||
//! construtor
|
||||
CRadPoly(CRadPoly *pSource);
|
||||
|
||||
//! destructor
|
||||
~CRadPoly();
|
||||
|
||||
//! /return true=the given polys have at least one vertex in common
|
||||
bool Connected(CRadPoly *pOther);
|
||||
|
||||
//! copy the data to the give patch, the poly lightmap data is removed from memory, too
|
||||
//! /param inpDestLightPatch destination
|
||||
//! /param nMapS
|
||||
//! /param nMapT
|
||||
//! /param inpSrcPoly pointer to the poly, must not be 0
|
||||
//! /param sw source pitch = width in bytes
|
||||
//! /param sh number of lines
|
||||
//! /param dw destination pitch
|
||||
void CopyData( CLightPatch *inpDestLightPatch, int dw );
|
||||
|
||||
bool IsTextureUniform(const int nTreshold);
|
||||
|
||||
//! compress patch to 1x1 if constant value
|
||||
void Compress( const unsigned int cuiMinBlockSize );
|
||||
|
||||
//! gather all subsamples for on etexel and sets the new value
|
||||
//! /param cuiX x-coord for texel to subsample
|
||||
//! /param cuiY y-coord for texel to subsample
|
||||
//! /param cuiSubSamples subsample count excluding center texel
|
||||
//! /param cpaIndicator pointer to indicator array indicating which subsample has received values
|
||||
//! /param cpfColours pointer to colour subsample array
|
||||
//! /param pDot3 pointer to dot3 subsample values
|
||||
//! /param ruiMaxComponent current max of colour patch components
|
||||
#ifdef APPLY_COLOUR_FIX
|
||||
void GatherSubSamples(
|
||||
const unsigned int cuiX, const unsigned int cuiY, const unsigned int cuiSubSamples,
|
||||
const unsigned int *cpaIndicator, const float *cpfColours, const SComplexOSDot3Texel *pDot3,
|
||||
unsigned int& ruiMaxComponent, const SOcclusionMapTexel *cpfOccl, const GLMOcclLightInfo& rOcclInfo);
|
||||
#else
|
||||
void GatherSubSamples(
|
||||
const unsigned int cuiX, const unsigned int cuiY, const unsigned int cuiSubSamples,
|
||||
const unsigned int *cpaIndicator, const float *cpfColours, const SComplexOSDot3Texel *pDot3, const SOcclusionMapTexel *cpfOccl, const GLMOcclLightInfo& rOcclInfo);
|
||||
#endif
|
||||
//!
|
||||
//! /return true=polygon has 3 vertices - calculation is ok, false=its not a triangle (degenerated - or wrong vertex count) calculation failed
|
||||
//! alters inPosition by projecting it into the triangls area
|
||||
bool ApplyBarycentricCoordinates( Vec3d &inPosition, CRadVertex &outVertex, SComplexOSDot3Texel& rDot3Texel, const bool cbImmedReturn = false, const bool cbSnap = true);
|
||||
|
||||
//!
|
||||
//! /param inPosition
|
||||
//! /return could be 0
|
||||
CRadPoly *GetNearestPolyAt( const Vec3d &inPosition );
|
||||
|
||||
//lighpatch
|
||||
void AddWarningBorders( void );
|
||||
|
||||
#ifndef DISPLAY_MORE_INFO
|
||||
const unsigned int CalcExtent(CLightScene *pScene, const CString& rGLMName, const CString& rCGFName, bool bOriginal, const float fGridSize, const UINT iMinBlockSize, const UINT iMaxBlockSize, unsigned int& rHugePatchFoundNumber);
|
||||
#else
|
||||
const unsigned int CalcExtent(CLightScene *pScene, const CString& rGLMName, const CString& rCGFName, bool bOriginal, const float fGridSize, const UINT iMinBlockSize, const UINT iMaxBlockSize);
|
||||
#endif
|
||||
|
||||
//!
|
||||
void GenerateImage( void );
|
||||
|
||||
//!
|
||||
//! m_nW and m_nH is used
|
||||
void AllocateDot3Lightmap(const bool cbGenerateHDRMaps, const bool cbGenerateOcclMaps = false);
|
||||
|
||||
bool InterpolateVertexAt( const float infX, const float infY, CRadVertex &outVertex, SComplexOSDot3Texel& rDot3Texel, const bool cbSubSample, const bool cbSnap=true) ;
|
||||
|
||||
/**
|
||||
* snaps a vertex which lies outside a triangle onto the nearest edge to get some valid barycentric coordinates
|
||||
* it does not extrapolate
|
||||
* @param inPosition vertex outside the triangle
|
||||
* @param outfAlpha alpha value for barycentric coordinate
|
||||
* @param outfBeta beta value for barycentric coordinate
|
||||
* @param cfTriangleArea area of triangle for computation of the new barycentric cooridnates
|
||||
*/
|
||||
const bool SnapVertex(Vec3d &inPosition, float &outfAlpha, float &outfBeta, const float cfTriangleArea);
|
||||
|
||||
/**
|
||||
* tries to map coordinates into triangles sharing at least one vertex of this triangle, performs the smoothing
|
||||
* @param outVertex output vertex interpolated from shared triangles
|
||||
* @param inPosition vertex outside the triangle
|
||||
* @param cfArea3d traingle area for snapping call
|
||||
* @param rDot3Texel information for dot3 texel to set up
|
||||
* @return true if one shared triangle has been found, false otherwise
|
||||
*/
|
||||
const bool SmoothVertex(CRadVertex &outVertex, const Vec3d &inPosition, const float cfArea3d, SComplexOSDot3Texel& rDot3Texel);
|
||||
|
||||
/**
|
||||
* applies tangent space vectors from this patch to a vertex having a pos outside this triangle
|
||||
* @param outVertex output vertex interpolated from shared triangles
|
||||
* @param outfAlpha alpha value for barycentric coordinate
|
||||
* @param outfBeta beta value for barycentric coordinate
|
||||
*/
|
||||
void ApplyTangentSpaceToVertex(CRadVertex &outVertex, float cfAlpha, float cfBeta);
|
||||
|
||||
void SetHDRLightmapTexel( const float infX, const float infY, const float lr, const float lg, const float lb);
|
||||
void SetOcclLightmapTexel(const float infX, const float infY, const SOcclusionMapTexel& rTexel);
|
||||
//!
|
||||
//! /param infX [0..m_nW[
|
||||
//! /param infY [0..m_nH[
|
||||
//! /param r 0.. , is automatic clamped to 0..255, usual lightmap color
|
||||
//! /param g 0.. , is automatic clamped to 0..255, usual lightmap color
|
||||
//! /param b 0.. , is automatic clamped to 0..255, usual lightmap color
|
||||
void SetSimpleLightmapTexel( const float infX, const float infY, const int lr, const int lg, const int lb, unsigned char iDP3Fac);
|
||||
//! stores the world space dot3 light vector and calls SetSimpleLightmapTexel
|
||||
#ifdef APPLY_COLOUR_FIX
|
||||
const unsigned int SetDot3LightmapTexel(const CRadVertex& rVertex,
|
||||
const float fColorRLamb, const float fColorGLamb, const float fColorBLamb,
|
||||
Vec3d &inLightDir, const float cfLM_DP3LerpFactor,
|
||||
SComplexOSDot3Texel& rDot3Texel, const SOcclusionMapTexel& rTexel, bool bHDR);
|
||||
#else
|
||||
void SetDot3LightmapTexel(const CRadVertex& rVertex,
|
||||
const float fColorRLamb, const float fColorGLamb, const float fColorBLamb,
|
||||
Vec3d &inLightDir, const float cfLM_DP3LerpFactor,
|
||||
SComplexOSDot3Texel& rDot3Texel, const SOcclusionMapTexel& rTexel, bool bHDR);
|
||||
#endif
|
||||
//! stores the tangent space light vector as colour
|
||||
#ifdef APPLY_COLOUR_FIX
|
||||
void SetDot3TSLightmapTexel(const unsigned int cuiX, const unsigned int cuiY, const unsigned int cuiColourFixAlpha, const float cfColourScale);
|
||||
#else
|
||||
void SetDot3TSLightmapTexel(const unsigned int cuiX, const unsigned int cuiY);
|
||||
#endif
|
||||
//unsigned int consists of 4 chars as follows: [0]=1st shared vertex of this [1]=2nd shared vertex of this [2]=1st shared vertex of shared triangle [3]=2nd shared vertex of shared triangle
|
||||
std::vector<std::pair<CRadPoly*,unsigned int> > m_SharingPolygons; //!< vertex sharing polygons
|
||||
|
||||
radpolylist m_lstMerged; //!< only patches merge
|
||||
|
||||
radvertexlist m_lstOriginals; //!<
|
||||
|
||||
Plane m_Plane; //!<
|
||||
|
||||
CRadPoly * m_pSource; //!<
|
||||
|
||||
CRadPoly * m_pMergeSource; //!< the source for this radpoly where it is contained in m_lstMerged
|
||||
|
||||
float m_fX1,m_fY1,m_fX2,m_fY2; //!<
|
||||
|
||||
int16 m_nX1,m_nY1,m_nX2,m_nY2; //!<
|
||||
|
||||
uint16 m_nW,m_nH; //!< really occupied width and height in the lightmap (always >=0)
|
||||
|
||||
uint8 m_nAx1,m_nAx2; //!<
|
||||
|
||||
uint8 m_nAxis; //!<
|
||||
|
||||
uint8 m_dwFlags; //!<
|
||||
|
||||
Vec3 *m_pHDRLightmapData; //! RGBE8 Lightmap
|
||||
unsigned char *m_pLightmapData; //! Lightmap / or colormap when using dot3
|
||||
unsigned char *m_pDominantDirData; //!< used for Dot3Lightmaps (normalized tangent space direction to the dominant lightsource, dot3 factor in alpha channel)
|
||||
SComplexOSDot3Texel *m_pWSDominantDirData; //!< used for Dot3Lightmaps, stores the world space vector and where the tangent space comes from
|
||||
SOcclusionMapTexel *m_pOcclMapData; //!< used for occlusionmap data
|
||||
|
||||
uint16 m_nOffsetW, m_nOffsetH; //!< offset into big lightmap
|
||||
|
||||
friend class CLightScene;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class CRadMesh
|
||||
{
|
||||
public:
|
||||
//! destructor
|
||||
~CRadMesh();
|
||||
|
||||
//! call after putting in the light sources to get the right HashValue
|
||||
void CreateEmpty( IEntityRender *pIEtyRend, const Matrix44& matEtyMtx );
|
||||
const bool FillInValues( IEntityRender *pIEtyRend, const CBrushObject *pBrushObject, const Matrix44& matEtyMtx );
|
||||
void PrepareLightmaps(CLightScene *pScene, bool bMergePolys,const float fGridSize, const Vec3d& vMinBB, const Vec3d& vMaxBB);
|
||||
bool SaveLightmaps(CLightScene *pScene,bool bDebug=false);
|
||||
|
||||
//! /return hashing value to detect changes in the data
|
||||
DWORD GetHashValue( void ) const {return(m_dwHashValue);};
|
||||
|
||||
void UpdateHash(const DWORD newHash){CalcNCombineHash(newHash,m_dwHashValue);}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
||||
IEntityRender * m_pESource; //!<
|
||||
|
||||
radpolylist m_lstOldPolys; //!< this class is the owner of these objects (delete is called)
|
||||
|
||||
Vec3d m_vCenter; //!<
|
||||
float m_fRadius,m_fRadius2; //!<
|
||||
|
||||
std::vector<LMCompLight *> m_LocalLights; //!< the lights that may affect this RadMesh (this class is not the owner = delete will not be called)
|
||||
|
||||
std::vector<LMCompLight *> m_LocalOcclLights; //!< the occlusion map lights types that may affect this RadMesh (this class is not the owner = delete will not be called)
|
||||
|
||||
CString m_sGLMName; //!< name of glm corresponding to this mesh
|
||||
|
||||
CRasterCubeImpl *m_pClusterRC; //!< Raster cube of the cluster in which this mesh is in
|
||||
|
||||
float m_fLMAccuracy; //!< individual GLM accuracy ranging from 0.. with 1 = default global world<->texel ratio
|
||||
|
||||
bool m_bReceiveLightmap; //!< indicates whether an object will receive lightmaps or not
|
||||
|
||||
unsigned int m_uiFlags; //!< flags, currently used during normal check and triangle initialisation
|
||||
|
||||
float m_fMaxVariance; //!< variance in normal length (purely for information)
|
||||
|
||||
IVariable *pLightmapQualityVar; //!< lightmap quality variable to adjust it if necessary
|
||||
|
||||
unsigned int m_uiTexCoordsRequired; //!< required texture coordinates by engine, should always match number of indices
|
||||
|
||||
GLMOcclLightInfo m_OcclInfo; //!< required information what light corresponds to which colour channel
|
||||
|
||||
//! constructor
|
||||
CRadMesh() :
|
||||
m_uiCoarseTexelCount(0), pLightmapQualityVar(NULL), m_fMaxVariance(0.f), m_fLMAccuracy(1.f), m_pESource(NULL),
|
||||
m_dwHashValue(0), m_pClusterRC(NULL), m_bReceiveLightmap(true), m_uiFlags(0), m_uiTexCoordsRequired(0){}
|
||||
|
||||
private:
|
||||
unsigned int m_uiCoarseTexelCount; //!< texel count required (simple summation over all patches after CalcExtent)
|
||||
|
||||
DWORD m_dwHashValue; //!< for selective recomputation
|
||||
|
||||
DWORD CalcLocalLightHashValue( void ) const;
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
class CLightPatch
|
||||
{
|
||||
public:
|
||||
CLightPatch(UINT iPatchResolution) : m_pLightmapImage(0),m_pHDRLightmapImage(0),m_pDominantDirImage(0),m_pOcclMapImage(NULL),m_nTextureNum(0)
|
||||
{
|
||||
m_nPatchSpace.resize(iPatchResolution);
|
||||
}
|
||||
|
||||
~CLightPatch()
|
||||
{
|
||||
if(m_pLightmapImage) { delete [] m_pLightmapImage;m_pLightmapImage=NULL; }
|
||||
if(m_pHDRLightmapImage) { delete [] m_pHDRLightmapImage;m_pHDRLightmapImage=NULL; }
|
||||
if(m_pDominantDirImage) { delete [] m_pDominantDirImage;m_pDominantDirImage=NULL; }
|
||||
if(m_pOcclMapImage) { delete [] m_pOcclMapImage;m_pOcclMapImage=NULL; }
|
||||
}
|
||||
|
||||
//! /param nSizeX 1..
|
||||
//! /param nSizey 1..
|
||||
void CreateDot3Lightmap( int nSizeX, int nSizeY,const bool cbGenerateHDRMaps, const bool cbGenerateOcclMaps = false );
|
||||
void Reset();
|
||||
|
||||
//!
|
||||
const bool GetSpace(int w,int h, uint16 &x, uint16 &y);
|
||||
|
||||
std::vector<int> m_nPatchSpace; //!<
|
||||
int m_nTextureNum; //!<
|
||||
int m_nWidth,m_nHeight; //!<
|
||||
std::string m_szFilename; //!<
|
||||
|
||||
unsigned char *m_pHDRLightmapImage; //!< HDR Lightmap texture (in Dot3Lightmaps this is used for the non dominant light sources)
|
||||
unsigned char *m_pLightmapImage; //!< Lightmap texture (in Dot3Lightmaps this is used for the non dominant light sources)
|
||||
unsigned char *m_pDominantDirImage; //!< only used for Dot3Lightmaps (normalized worldspace direction to the dominant lightsource)
|
||||
SOcclusionMapTexel *m_pOcclMapImage; //!< used for occlusionmap data
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
class CLightScene
|
||||
{
|
||||
public:
|
||||
CLightScene();
|
||||
~CLightScene();
|
||||
|
||||
bool CreateFromEntity(
|
||||
const IndoorBaseInterface &pInterface,
|
||||
LMGenParam sParam,
|
||||
std::vector<std::pair<IEntityRender*, CBrushObject*> >& vNodes,
|
||||
CLMLightCollection& cLights,
|
||||
struct ICompilerProgress *pIProgress,
|
||||
const ELMMode Mode,
|
||||
volatile SSharedLMEditorData* pSharedData,
|
||||
const std::set<const CBrushObject*>& vSelectionIndices,
|
||||
bool &rErrorsOccured);
|
||||
|
||||
radmeshlist m_lstRadMeshes; //!< this class is the owner of these objects (delete is called)
|
||||
radpolylist m_lstScenePolys; //!<
|
||||
unsigned int m_uiCurrentPatchNumber; //!< to number the current lightmap
|
||||
CLightPatch * m_pCurrentPatch; //!<
|
||||
LMGenParam m_sParam;
|
||||
|
||||
void CreateNewLightmap( void );
|
||||
|
||||
// The assign queue system
|
||||
struct LMAssignQueueItem
|
||||
{
|
||||
IEntityRender * pI_GLM; //!
|
||||
std::vector<struct TexCoord2Comp> vSortedTexCoords; //!
|
||||
DWORD m_dwHashValue; //!< hashing value to detect changes in the data
|
||||
std::vector<std::pair<EntityId, EntityId> > vOcclIDs; //!< occlusion indices corresponding to the 0..4 colour channels
|
||||
};
|
||||
|
||||
std::list<LMAssignQueueItem> m_lstAssignQueue; //!
|
||||
|
||||
std::vector<CString>& GetLogInfo()
|
||||
{
|
||||
return m_LogInfo;
|
||||
}
|
||||
|
||||
std::multimap<unsigned int,std::string>& GetWarningInfo()
|
||||
{
|
||||
return m_WarningInfo;
|
||||
}
|
||||
|
||||
const float ComputeHalvedLightmapQuality(const float fOldValue);
|
||||
|
||||
protected:
|
||||
void DoLightCalculation(
|
||||
unsigned int &ruiMaxColourComp,
|
||||
const std::vector<LMCompLight*>& vLights,
|
||||
const std::vector<LMCompLight*>& vOcclLights,
|
||||
SComplexOSDot3Texel& dot3Texel,
|
||||
CRadMesh *pMesh,
|
||||
CRadPoly *pSource,
|
||||
const CRadVertex& Vert,
|
||||
const bool cbFirstPass,
|
||||
const unsigned int cuiSubSampleIndex = 0);
|
||||
void CheckLight(LMCompLight& rLight, const int iCurLightIdx);
|
||||
void GenerateTexCoords(const CRadMesh& rRadMesh, LMAssignQueueItem& rNewGLMQueueItm);
|
||||
void SelectObjectLMReceiverAndShadowCasterForChanges(
|
||||
std::vector<std::pair<IEntityRender*, CBrushObject*> >& vNodes,
|
||||
const std::vector<AABB>& vAABBs,
|
||||
const Matrix33& rMatSunBasis,
|
||||
const std::vector<unsigned int>& rvNodeRadMeshIndices,
|
||||
const ELMMode Mode);
|
||||
void SelectObjectsFromChangedLMShadowCaster(
|
||||
std::vector<std::pair<IEntityRender*, CBrushObject*> >&vNodes,
|
||||
const std::vector<AABB>& vAABBs,
|
||||
const Matrix33& rMatSunBasis,
|
||||
const std::vector<unsigned int>& rvNodeRadMeshIndices);
|
||||
void ComputeSmoothingInformation(const unsigned int uiSmoothAngle = 45, const bool cbTSGeneratedByLM = false); //computes the sharing information and stores it into the respective per polygon vectors
|
||||
void MergeTangentSpace(CRadVertex& rVertex1, CRadVertex& rVertex2); //merges two tangent spaces according to normal
|
||||
const unsigned int CheckNormals(float& rfMaxVariance, const CRadMesh* const pMesh);//returns true if some normals are not normalized, rfMaxVariance is the max variance encountered
|
||||
bool Create(const IndoorBaseInterface &pInterface, const Vec3d& vMinBB, const Vec3d& vMaxBB, volatile SSharedLMEditorData *pSharedData, const ELMMode Mode, const unsigned int cuiMeshesToProcessCount);
|
||||
void FlushAssignQueue();
|
||||
#ifdef APPLY_COLOUR_FIX
|
||||
void PerformAdaptiveSubSampling(
|
||||
CRadMesh *pMesh,
|
||||
CRadPoly *pSource,
|
||||
const std::vector<LMCompLight*>& vLights,
|
||||
const std::vector<LMCompLight*>& vOcclLights,
|
||||
unsigned int uiMaxComponent);
|
||||
#else
|
||||
void PerformAdaptiveSubSampling(
|
||||
CRadMesh *pMesh,
|
||||
CRadPoly *pSource,
|
||||
const std::vector<LMCompLight*>& vLights,
|
||||
const std::vector<LMCompLight*>& vOcclLights);
|
||||
#endif
|
||||
void SetSubSampleDot3LightmapTexel(
|
||||
const unsigned int cuiSubSampleIndex,
|
||||
const float fColorRLamb, const float fColorGLamb, const float fColorBLamb,
|
||||
Vec3d &inLightDir, const float cfLM_DP3LerpFactor,
|
||||
SComplexOSDot3Texel& rDot3Texel,
|
||||
const SOcclusionMapTexel& rOcclTexel, bool bHDR);
|
||||
void GatherSubSampleTexel(const CRadPoly *pSource, const int ciX, const int ciY, std::set<std::pair<unsigned int, unsigned int> >& rvSubTexels);
|
||||
const bool FlushAndSave(volatile SSharedLMEditorData *pSharedData, const ELMMode Mode);
|
||||
void Reset()
|
||||
{
|
||||
//i need this definitely to be deallocated, thats why clear and resize call (implementations differ to much which really deallocates)
|
||||
m_lstRadMeshes.clear();
|
||||
m_lstScenePolys.clear();
|
||||
m_lstAssignQueue.clear();
|
||||
m_lstRadMeshes.resize(0);
|
||||
m_lstScenePolys.resize(0);
|
||||
m_lstAssignQueue.resize(0);
|
||||
m_lstClusters.clear();
|
||||
m_lstClusters.resize(0);
|
||||
};
|
||||
|
||||
void WriteLogInfo();
|
||||
|
||||
void Init()
|
||||
{
|
||||
Reset();
|
||||
MEMORYSTATUS sStats;
|
||||
GlobalMemoryStatus(&sStats);
|
||||
m_uiStartMemoryConsumption = ((sStats.dwTotalVirtual - sStats.dwAvailVirtual) / 1024/1024);
|
||||
}
|
||||
const unsigned int GetUsedMemory()
|
||||
{
|
||||
MEMORYSTATUS sStats;
|
||||
GlobalMemoryStatus(&sStats);
|
||||
const unsigned int cuiCurrentTotal((sStats.dwTotalVirtual - sStats.dwAvailVirtual) / 1024/1024);
|
||||
if(cuiCurrentTotal <= m_uiStartMemoryConsumption)
|
||||
return 0;
|
||||
return (cuiCurrentTotal - m_uiStartMemoryConsumption);
|
||||
};
|
||||
void DumpSysMemStats()
|
||||
{
|
||||
_TRACE(m_LogInfo, true, "System memory usage: %iMB\r\n", GetUsedMemory());
|
||||
};
|
||||
void DisplayMemStats(volatile SSharedLMEditorData *pSharedData)
|
||||
{
|
||||
if(pSharedData != NULL)
|
||||
{
|
||||
::SendMessage( pSharedData->hwnd, pSharedData->uiMemUsageMessage, min(GetUsedMemory(),1000), 0 );//update progress bar
|
||||
::SendMessage( pSharedData->hwnd, pSharedData->uiMemUsageStatic, min(GetUsedMemory(),1000), 0 );//update progress bar static element
|
||||
MSG msg;
|
||||
while( FALSE != ::PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )
|
||||
{
|
||||
::TranslateMessage( &msg );
|
||||
::DispatchMessage( &msg );
|
||||
}
|
||||
}
|
||||
else
|
||||
DumpSysMemStats();
|
||||
}
|
||||
static bool CastsLightmap(const CBrushObject *pBrushObject)
|
||||
{
|
||||
bool bCastLightmap = true;
|
||||
if(pBrushObject)
|
||||
{
|
||||
CVarBlock *pVarBlock = pBrushObject->GetVarBlock();
|
||||
if(pVarBlock)
|
||||
{
|
||||
IVariable *pVar = pVarBlock->FindVariable("CastLightmap");
|
||||
if(pVar && (pVar->GetType() == IVariable::BOOL))
|
||||
{
|
||||
pVar->Get(bCastLightmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bCastLightmap;
|
||||
}
|
||||
void InitSubSampling(const unsigned int cuiSampleCount)
|
||||
{
|
||||
m_puiIndicator = new unsigned int[cuiSampleCount]; assert(m_puiIndicator);
|
||||
m_pSubSamples = new SComplexOSDot3Texel[cuiSampleCount]; assert(m_pSubSamples);
|
||||
m_pfColours = new float [cuiSampleCount * 4/*4 colour components*/]; assert(m_pfColours);
|
||||
if(m_sParam.m_bGenOcclMaps)
|
||||
{
|
||||
m_pOcclSamples = new SOcclusionMapTexel[cuiSampleCount]; assert(m_pOcclSamples);
|
||||
}
|
||||
m_uiSampleCount = cuiSampleCount;
|
||||
}
|
||||
|
||||
private:
|
||||
std::multimap<unsigned int,std::string> m_WarningInfo; //!< will contain warning summary for logfile
|
||||
std::vector<CString> m_LogInfo; //!< will contain some logging info
|
||||
|
||||
struct ILMSerializationManager *m_pISerializationManager;
|
||||
std::list<GLMCluster> m_lstClusters;
|
||||
CRasterCubeManager m_RasterCubeManager;
|
||||
|
||||
unsigned int *m_puiIndicator; //!< index of each pixel whether a value has been set or not
|
||||
SComplexOSDot3Texel *m_pSubSamples; //!< subsamples for one texel
|
||||
SOcclusionMapTexel *m_pOcclSamples; //!< subsamples for occl map texel
|
||||
float *m_pfColours; //!< colours
|
||||
unsigned int m_uiSampleCount; //!< subsample count for one single texel
|
||||
|
||||
unsigned int m_uiStartMemoryConsumption;
|
||||
|
||||
IndoorBaseInterface m_IndInterface;
|
||||
|
||||
bool ComputeRasterCube(CRasterCubeImpl *pRasterCube, const std::set<IEntityRender *>& vGeom, const Matrix33 *pDirLightTransf = NULL);
|
||||
|
||||
void Shadow(LMCompLight& cLight, UINT& iNumHit, CRadMesh *pMesh, CRadPoly *pSource, const CRadVertex& Vert, const Vec3d& vSamplePos);
|
||||
|
||||
#define ALREADY_TESTED_ARRARY_SIZE 1024
|
||||
|
||||
class CEveryObjectOnlyOnce :public CPossibleIntersectionSink<RasterCubeUserT>
|
||||
{
|
||||
public:
|
||||
//! /param invFrom
|
||||
//! /param invDir
|
||||
//! /param infRayLength
|
||||
//! /param inpIgnore for bias free rayshooting from object surface, may be 0
|
||||
void SetupRay( const Vec3d& vRayDir, const Vec3d& vRayOrigin, float fRayLen, CRadPoly* pRayDest)
|
||||
{
|
||||
m_vRayDir = vRayDir;
|
||||
m_vRayOrigin = vRayOrigin;
|
||||
m_fRayLen = fRayLen;
|
||||
m_pRayDest = pRayDest;
|
||||
m_dwAlreadyTested=0;
|
||||
}
|
||||
|
||||
// --------------------------------------------
|
||||
|
||||
protected:
|
||||
Vec3d m_vRayOrigin; //!< position in world space
|
||||
Vec3d m_vRayDir; //!< direction in world space
|
||||
DWORD m_dwAlreadyTested; //!< 0..ALREADY_TESTED_ARRARY_SIZE
|
||||
float m_fRayLen; //!<
|
||||
const RasterCubeUserT * m_arrAlreadyTested[ALREADY_TESTED_ARRARY_SIZE]; //!< [0..ALREADY_TESTED_ARRARY_SIZE-1], this is faster than a set<> at least for typical amounts
|
||||
CRadPoly* m_pRayDest; //!< ray destination polygon
|
||||
|
||||
//! /return true=object is already tested, false otherwise
|
||||
bool InsertAlreadyTested( RasterCubeUserT *inObject )
|
||||
{
|
||||
const RasterCubeUserT * *ptr=m_arrAlreadyTested;
|
||||
|
||||
for(DWORD i=0;i<m_dwAlreadyTested;i++)
|
||||
if(*ptr++==inObject)return(true);
|
||||
|
||||
if(m_dwAlreadyTested<ALREADY_TESTED_ARRARY_SIZE-1) m_arrAlreadyTested[m_dwAlreadyTested++]=inObject;
|
||||
else assert(0); // ALREADY_TESTED_ARRARY_SIZE is not big enougth
|
||||
|
||||
return(false);
|
||||
}
|
||||
};//CEveryObjectOnlyOnce
|
||||
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
// Intersection sink
|
||||
// ---------------------------------------------------------------------------------------------
|
||||
class CAnyHit : public CEveryObjectOnlyOnce
|
||||
{
|
||||
public:
|
||||
|
||||
void SetupRay(const Vec3d& vRayDir, const Vec3d& vRayOrigin, float fRayLen, const float infGridSize, CRadPoly* pRayDest = NULL)
|
||||
{
|
||||
CEveryObjectOnlyOnce::SetupRay(vRayDir,vRayOrigin,fRayLen, pRayDest);
|
||||
m_pHitResult = 0;
|
||||
m_fClosest = FLT_MAX;
|
||||
m_fGridSize=infGridSize;
|
||||
};
|
||||
bool IsIntersecting() const { return(m_pHitResult!=0); }
|
||||
|
||||
// TODO
|
||||
float m_fD;
|
||||
Vec3d m_vPNormal;
|
||||
float m_fGridSize;
|
||||
|
||||
const bool ReturnElement(RasterCubeUserT &inObject, float &inoutfRayMaxDist);
|
||||
|
||||
RasterCubeUserT *m_pHitResult;
|
||||
protected:
|
||||
float m_fClosest;
|
||||
|
||||
// Still intersect with backfacing triangles. While this fixes a few false shadow cases, it
|
||||
// adds ugly bright seems between caster and shadow, which looks far worse
|
||||
int intersect_triangle( float orig[3], float dir[3],
|
||||
float vert0[3], float vert1[3], float vert2[3],
|
||||
float *t, float *u, float *v);
|
||||
};//CAnyHit
|
||||
friend class CRadPoly;
|
||||
};//CLightScene
|
||||
|
||||
//computes a fade for the light average weight
|
||||
static inline const float LightInfluence(const float cfDot)
|
||||
{
|
||||
static const float scfMinInfluence = 0.01f; //influence = 0
|
||||
static const float scfFullInfluence = 0.2f; //influence = 1
|
||||
if(cfDot >= scfFullInfluence)
|
||||
return 1.f;
|
||||
if(cfDot <= scfMinInfluence)
|
||||
return 0.f;
|
||||
return (cfDot - scfMinInfluence) / (scfFullInfluence - scfMinInfluence);
|
||||
}
|
||||
|
||||
#endif // __INDOOR_LIGHT_PATCHES_H__
|
||||
Reference in New Issue
Block a user