Bake models into the level mesh
This commit is contained in:
parent
cfe282f4bd
commit
3f1dcce970
5 changed files with 188 additions and 28 deletions
|
|
@ -42,6 +42,7 @@ struct SurfaceAllocInfo
|
|||
{
|
||||
LevelMeshSurface* Surface = nullptr;
|
||||
int Index = 0;
|
||||
int Count = 0;
|
||||
};
|
||||
|
||||
struct LightAllocInfo
|
||||
|
|
@ -124,14 +125,14 @@ public:
|
|||
|
||||
GeometryAllocInfo AllocGeometry(int vertexCount, int indexCount);
|
||||
UniformsAllocInfo AllocUniforms(int count);
|
||||
SurfaceAllocInfo AllocSurface();
|
||||
SurfaceAllocInfo AllocSurface(int count = 1);
|
||||
LightAllocInfo AllocLight();
|
||||
LightListAllocInfo AllocLightList(int count);
|
||||
int AllocTile(const LightmapTile& tile);
|
||||
|
||||
void FreeGeometry(int vertexStart, int vertexCount, int indexStart, int indexCount);
|
||||
void FreeUniforms(int start, int count);
|
||||
void FreeSurface(unsigned int surfaceIndex);
|
||||
void FreeSurface(unsigned int surfaceIndex, int count = 1);
|
||||
void FreeLightList(int start, int count);
|
||||
void FreeTile(int index);
|
||||
|
||||
|
|
@ -288,12 +289,13 @@ inline LightAllocInfo LevelMesh::AllocLight()
|
|||
return info;
|
||||
}
|
||||
|
||||
inline SurfaceAllocInfo LevelMesh::AllocSurface()
|
||||
inline SurfaceAllocInfo LevelMesh::AllocSurface(int count)
|
||||
{
|
||||
SurfaceAllocInfo info;
|
||||
info.Index = FreeLists.Surface.Alloc(1);
|
||||
info.Index = FreeLists.Surface.Alloc(count);
|
||||
info.Surface = &Mesh.Surfaces[info.Index];
|
||||
UploadRanges.Surface.Add(info.Index, 1);
|
||||
info.Count = count;
|
||||
UploadRanges.Surface.Add(info.Index, info.Count);
|
||||
return info;
|
||||
}
|
||||
|
||||
|
|
@ -333,9 +335,9 @@ inline void LevelMesh::FreeLightList(int start, int count)
|
|||
FreeLists.LightIndex.Free(start, count);
|
||||
}
|
||||
|
||||
inline void LevelMesh::FreeSurface(unsigned int surfaceIndex)
|
||||
inline void LevelMesh::FreeSurface(unsigned int surfaceIndex, int count)
|
||||
{
|
||||
FreeLists.Surface.Free(surfaceIndex, 1);
|
||||
FreeLists.Surface.Free(surfaceIndex, count);
|
||||
}
|
||||
|
||||
inline void LevelMesh::FreeTile(int index)
|
||||
|
|
|
|||
|
|
@ -102,7 +102,9 @@ void MeshBuilderModelRender::BeginDrawModel(FRenderStyle style, int smf_flags, c
|
|||
void MeshBuilderModelRender::EndDrawModel(FRenderStyle style, int smf_flags)
|
||||
{
|
||||
renderstate.SetBoneIndexBase(-1);
|
||||
renderstate.SetModelMatrix(VSMatrix::identity(), VSMatrix::identity());
|
||||
|
||||
// Don't do this so we don't have to track matrix changes in MeshBuilder (only models uses matrices like this)
|
||||
//renderstate.SetModelMatrix(VSMatrix::identity(), VSMatrix::identity());
|
||||
}
|
||||
|
||||
IModelVertexBuffer* MeshBuilderModelRender::CreateVertexBuffer(bool needindex, bool singleframe)
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ public:
|
|||
// Buffers
|
||||
int SetViewpoint(const HWViewpointUniforms& vp) override { return 0; }
|
||||
void SetViewpoint(int index) override { }
|
||||
void SetModelMatrix(const VSMatrix& matrix, const VSMatrix& normalMatrix) override { }
|
||||
void SetModelMatrix(const VSMatrix& matrix, const VSMatrix& normalMatrix) override { objectToWorld = matrix; normalToWorld = normalMatrix; }
|
||||
void SetTextureMatrix(const VSMatrix& matrix) override { mTextureMatrix = matrix; }
|
||||
int UploadLights(const FDynLightData& lightdata) override { return -1; }
|
||||
int UploadBones(const TArray<VSMatrix>& bones) override { return -1; }
|
||||
|
|
@ -150,6 +150,9 @@ public:
|
|||
TArray<FFlatVertex> mVertices;
|
||||
TArray<uint32_t> mIndexes;
|
||||
|
||||
VSMatrix objectToWorld = VSMatrix::identity();
|
||||
VSMatrix normalToWorld = VSMatrix::identity();
|
||||
|
||||
private:
|
||||
void Apply();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "c_dispatch.h"
|
||||
#include "models.h"
|
||||
#include "a_dynlight.h"
|
||||
#include "r_sky.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include "hw_vertexbuilder.h"
|
||||
#include "hw_dynlightdata.h"
|
||||
|
|
@ -236,6 +237,8 @@ CCMD(surfaceinfo)
|
|||
|
||||
EXTERN_CVAR(Float, lm_scale);
|
||||
|
||||
CVAR(Bool, lm_models, false, 0);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap)
|
||||
|
|
@ -277,30 +280,22 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals& doomMap)
|
|||
tile.NeedsInitialBake = true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Collect all the models we want to bake into the level mesh
|
||||
auto it = doomMap.GetThinkerIterator<AActor>();
|
||||
AActor* thing;
|
||||
while ((thing = it.Next()) != nullptr)
|
||||
if (lm_models)
|
||||
{
|
||||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
int spritenum = thing->sprite;
|
||||
FSpriteModelFrame* modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing, spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
if (modelframe && modelframe->modelIDs.size() != 0)
|
||||
auto it = doomMap.GetThinkerIterator<AActor>();
|
||||
AActor* thing;
|
||||
while ((thing = it.Next()) != nullptr)
|
||||
{
|
||||
DVector3 thingpos = thing->Pos();
|
||||
double x = thingpos.X + thing->WorldOffset.X;
|
||||
double z = thingpos.Z + thing->WorldOffset.Z;
|
||||
double y = thingpos.Y + thing->WorldOffset.Y;
|
||||
|
||||
MeshBuilder builder;
|
||||
MeshBuilderModelRender renderer(builder);
|
||||
RenderModel(&renderer, x, y, z, modelframe, thing, 0.0);
|
||||
|
||||
// To do: add the MeshBuilder output as surfaces
|
||||
bool isPicnumOverride = thing->picnum.isValid();
|
||||
int spritenum = thing->sprite;
|
||||
FSpriteModelFrame* modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing, spritenum, thing->frame, !!(thing->flags & MF_DROPPED));
|
||||
if (modelframe && modelframe->modelIDs.size() != 0)
|
||||
{
|
||||
CreateModelSurfaces(thing, modelframe);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
CreateCollision();
|
||||
UploadPortals();
|
||||
|
|
@ -313,6 +308,162 @@ DoomLevelMesh::~DoomLevelMesh()
|
|||
{
|
||||
}
|
||||
|
||||
void DoomLevelMesh::CreateModelSurfaces(AActor* thing, FSpriteModelFrame* modelframe)
|
||||
{
|
||||
DVector3 thingpos = thing->Pos();
|
||||
double x = thingpos.X + thing->WorldOffset.X;
|
||||
double z = thingpos.Z + thing->WorldOffset.Z;
|
||||
double y = thingpos.Y + thing->WorldOffset.Y;
|
||||
|
||||
state.mSortedLists.clear();
|
||||
state.mVertices.Clear();
|
||||
state.mIndexes.Clear();
|
||||
|
||||
state.SetDepthMask(true);
|
||||
state.EnableFog(true);
|
||||
state.SetRenderStyle(STYLE_Source);
|
||||
|
||||
state.SetDepthFunc(DF_LEqual);
|
||||
state.ClearDepthBias();
|
||||
state.EnableTexture(true);
|
||||
state.EnableBrightmap(true);
|
||||
state.AlphaFunc(Alpha_GEqual, 0.f);
|
||||
|
||||
MeshBuilderModelRender renderer(state);
|
||||
RenderModel(&renderer, x, y, z, modelframe, thing, 0.0);
|
||||
|
||||
// Flatten the model as we need lightmap UV coordinates uniquely for every vertex for each surface.
|
||||
int numUniforms = 0;
|
||||
int numSurfaces = 0;
|
||||
for (auto& it : state.mSortedLists)
|
||||
{
|
||||
numUniforms++;
|
||||
for (MeshDrawCommand& command : it.second.mDraws)
|
||||
{
|
||||
if (command.DrawType == DT_Triangles)
|
||||
{
|
||||
numSurfaces += command.Count / 3;
|
||||
}
|
||||
}
|
||||
for (MeshDrawCommand& command : it.second.mIndexedDraws)
|
||||
{
|
||||
if (command.DrawType == DT_Triangles)
|
||||
{
|
||||
numSurfaces += command.Count / 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VSMatrix objectToWorld = state.objectToWorld;
|
||||
//VSMatrix normalToWorld = state.normalToWorld;
|
||||
|
||||
GeometryAllocInfo ginfo = AllocGeometry(numSurfaces * 3, numSurfaces * 3);
|
||||
UniformsAllocInfo uinfo = AllocUniforms(numUniforms);
|
||||
SurfaceAllocInfo sinfo = AllocSurface(numUniforms); // Note: this is not a typo. We currently only create a SurfaceInfo for each apply state.
|
||||
|
||||
SurfaceUniforms* curUniforms = uinfo.Uniforms;
|
||||
SurfaceLightUniforms* curLightUniforms = uinfo.LightUniforms;
|
||||
FMaterialState* curMaterial = uinfo.Materials;
|
||||
|
||||
int pipelineID = 0;
|
||||
int uniformsIndex = uinfo.Start;
|
||||
int vertIndex = ginfo.VertexStart;
|
||||
for (auto& it : state.mSortedLists)
|
||||
{
|
||||
const MeshApplyState& applyState = it.first;
|
||||
|
||||
pipelineID = screen->GetLevelMeshPipelineID(applyState.applyData, applyState.surfaceUniforms, applyState.material);
|
||||
|
||||
auto indexBuffer = applyState.indexBuffer->Data.data();
|
||||
auto vertexBuffer = applyState.vertexBuffer->Data.data();
|
||||
|
||||
for (MeshDrawCommand& command : it.second.mDraws)
|
||||
{
|
||||
if (command.DrawType == DT_Triangles)
|
||||
{
|
||||
int numVertices = command.Count / 3 * 3;
|
||||
for (int i = 0; i < numVertices; i++)
|
||||
{
|
||||
*(ginfo.Indexes++) = vertIndex + i;
|
||||
}
|
||||
for (int i = command.Start, end = command.Start + numVertices; i < end; i++)
|
||||
{
|
||||
const FModelVertex& vertIn = vertexBuffer[i];
|
||||
FVector4 pos = objectToWorld * FVector4(vertIn.x, vertIn.y, vertIn.z, 1.0f);
|
||||
FFlatVertex vertOut;
|
||||
vertOut.x = pos.X;
|
||||
vertOut.y = pos.Z;
|
||||
vertOut.z = pos.Y;
|
||||
vertOut.u = vertIn.u;
|
||||
vertOut.v = vertIn.v;
|
||||
vertOut.lindex = -1.0f;
|
||||
*(ginfo.Vertices++) = vertOut;
|
||||
*(ginfo.UniformIndexes++) = uniformsIndex;
|
||||
}
|
||||
vertIndex += numVertices;
|
||||
}
|
||||
}
|
||||
|
||||
for (MeshDrawCommand& command : it.second.mIndexedDraws)
|
||||
{
|
||||
if (command.DrawType == DT_Triangles)
|
||||
{
|
||||
int numVertices = command.Count / 3 * 3;
|
||||
for (int i = 0; i < numVertices; i++)
|
||||
{
|
||||
*(ginfo.Indexes++) = vertIndex + i;
|
||||
}
|
||||
for (int i = command.Start, end = command.Start + numVertices; i < end; i++)
|
||||
{
|
||||
const FModelVertex& vertIn = vertexBuffer[indexBuffer[i]];
|
||||
FVector4 pos = objectToWorld * FVector4(vertIn.x, vertIn.y, vertIn.z, 1.0f);
|
||||
FFlatVertex vertOut;
|
||||
vertOut.x = pos.X;
|
||||
vertOut.y = pos.Z;
|
||||
vertOut.z = pos.Y;
|
||||
vertOut.u = vertIn.u;
|
||||
vertOut.v = vertIn.v;
|
||||
vertOut.lindex = -1.0f;
|
||||
*(ginfo.Vertices++) = vertOut;
|
||||
*(ginfo.UniformIndexes++) = uniformsIndex;
|
||||
}
|
||||
vertIndex += numVertices;
|
||||
}
|
||||
}
|
||||
|
||||
*(curUniforms++) = applyState.surfaceUniforms;
|
||||
*(curMaterial++) = applyState.material;
|
||||
|
||||
curLightUniforms->uVertexColor = applyState.surfaceUniforms.uVertexColor;
|
||||
curLightUniforms->uDesaturationFactor = applyState.surfaceUniforms.uDesaturationFactor;
|
||||
curLightUniforms->uLightLevel = applyState.surfaceUniforms.uLightLevel;
|
||||
curLightUniforms++;
|
||||
|
||||
sinfo.Surface->PipelineID = pipelineID;
|
||||
sinfo.Surface->SectorGroup = thing->Sector ? sectorGroup[thing->Sector->Index()] : 0;
|
||||
sinfo.Surface->Alpha = float(thing->Alpha);
|
||||
sinfo.Surface->MeshLocation.StartVertIndex = ginfo.VertexStart;
|
||||
sinfo.Surface->MeshLocation.StartElementIndex = ginfo.IndexStart;
|
||||
sinfo.Surface->MeshLocation.NumVerts = ginfo.VertexCount;
|
||||
sinfo.Surface->MeshLocation.NumElements = ginfo.IndexCount;
|
||||
sinfo.Surface->Plane = FVector4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
sinfo.Surface->Texture = TexMan.GetGameTexture(skyflatnum); // To do: how to get a FGameTexture from a material?
|
||||
sinfo.Surface->PortalIndex = 0;
|
||||
sinfo.Surface->IsSky = false;
|
||||
sinfo.Surface->Bounds = GetBoundsFromSurface(*sinfo.Surface);
|
||||
sinfo.Surface->LightList.Pos = 0; // To do: how to manage the light list for baked models?
|
||||
sinfo.Surface->LightList.Count = 0;
|
||||
sinfo.Surface->LightmapTileIndex = -1; // To do: create tiles for the model surfaces? Current SurfaceInfo is too big for this
|
||||
|
||||
for (int i = ginfo.IndexStart / 3, end = (ginfo.IndexStart + ginfo.IndexCount) / 3; i < end; i++)
|
||||
Mesh.SurfaceIndexes[i] = sinfo.Index;
|
||||
|
||||
uniformsIndex++;
|
||||
}
|
||||
|
||||
// To do: save ginfo, uinfo and sinfo in a Models list like we are doing for sides and flats? We need that if we are to ever update them
|
||||
}
|
||||
|
||||
void DoomLevelMesh::BuildSideVisibilityLists(FLevelLocals& doomMap)
|
||||
{
|
||||
VisibleSides.resize(doomMap.sides.size());
|
||||
|
|
|
|||
|
|
@ -231,6 +231,8 @@ private:
|
|||
void SetSubsectorLightmap(int surfaceIndex);
|
||||
void SetSideLightmap(int surfaceIndex);
|
||||
|
||||
void CreateModelSurfaces(AActor* thing, FSpriteModelFrame* modelframe);
|
||||
|
||||
void CreateWallSurface(side_t* side, HWWallDispatcher& disp, MeshBuilder& state, TArray<HWWall>& list, LevelMeshDrawType drawType, unsigned int sectorIndex, const LightListAllocInfo& lightlist);
|
||||
void CreateFlatSurface(HWFlatDispatcher& disp, MeshBuilder& state, TArray<HWFlat>& list, LevelMeshDrawType drawType, bool translucent, unsigned int sectorIndex, const LightListAllocInfo& lightlist, int lightlistSection);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue