Add SurfaceVertex to store texture UVs

This commit is contained in:
RaveYard 2023-09-20 12:51:11 +02:00 committed by Christoph Oelckers
parent 6e345c6a08
commit ef065fb9b9
7 changed files with 146 additions and 15 deletions

View file

@ -8,9 +8,11 @@
#include "common/utility/matrix.h"
#include <memory>
#include <cstring>
#include "textureid.h"
#include <dp_rect_pack.h>
typedef dp::rect_pack::RectPacker<int> RectPacker;
class LevelMeshLight
@ -62,6 +64,8 @@ struct LevelMeshSurface
//
// Required for internal lightmapper:
//
FTextureID texture = FNullTextureID();
int portalIndex = 0;
int sectorGroup = 0;
@ -193,6 +197,7 @@ public:
virtual ~LevelMesh() = default;
TArray<FVector3> MeshVertices;
TArray<FVector2> MeshVertexUVs;
TArray<int> MeshUVIndex;
TArray<uint32_t> MeshElements;
TArray<int> MeshSurfaceIndexes;

View file

@ -413,6 +413,7 @@ void VkLightmap::CreateShaders()
{
std::string prefix = "#version 460\r\n";
std::string traceprefix = "#version 460\r\n";
traceprefix += "#extension GL_EXT_nonuniform_qualifier : enable\r\n";
if (useRayQuery)
{
traceprefix += "#extension GL_EXT_ray_query : require\r\n";
@ -484,6 +485,7 @@ void VkLightmap::CreateRaytracePipeline()
{
raytrace.descriptorSetLayout1 = DescriptorSetLayoutBuilder()
.AddBinding(0, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
.AddBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
.DebugName("raytrace.descriptorSetLayout1")
.Create(fb->GetDevice());
}
@ -528,7 +530,7 @@ void VkLightmap::CreateRaytracePipeline()
.RenderPass(raytrace.renderPass.get())
.AddVertexShader(shaders.vertRaytrace.get())
.AddFragmentShader(shaders.fragRaytrace.get())
.AddVertexBufferBinding(0, sizeof(FVector4))
.AddVertexBufferBinding(0, sizeof(SurfaceVertex))
.AddVertexAttribute(0, 0, VK_FORMAT_R32G32B32A32_SFLOAT, 0)
.Topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST)
.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT)
@ -549,6 +551,7 @@ void VkLightmap::CreateRaytracePipeline()
{
raytrace.descriptorPool1 = DescriptorPoolBuilder()
.AddPoolSize(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1)
.AddPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1)
.MaxSets(1)
.DebugName("raytrace.descriptorPool1")
.Create(fb->GetDevice());
@ -575,6 +578,7 @@ void VkLightmap::UpdateAccelStructDescriptors()
{
WriteDescriptors()
.AddAccelerationStructure(raytrace.descriptorSet1.get(), 0, fb->GetRaytrace()->GetAccelStruct())
.AddBuffer(raytrace.descriptorSet1.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->GetRaytrace()->GetVertexBuffer())
.Execute(fb->GetDevice());
}
else

View file

@ -25,6 +25,8 @@
#include "vulkan/vk_renderdevice.h"
#include "vulkan/commands/vk_commandbuffer.h"
#include "hw_levelmesh.h"
#include "hw_material.h"
#include "texturemanager.h"
VkRaytrace::VkRaytrace(VulkanRenderDevice* fb) : fb(fb)
{
@ -42,6 +44,9 @@ VkRaytrace::VkRaytrace(VulkanRenderDevice* fb) : fb(fb)
NullMesh.MeshVertices.Push({ -1.0f, -1.0f, 1.0f });
NullMesh.MeshVertices.Push({ -1.0f, 1.0f, 1.0f });
NullMesh.MeshVertices.Push({ 1.0f, 1.0f, 1.0f });
NullMesh.MeshVertexUVs.Resize(NullMesh.MeshVertices.Size());
for (int i = 0; i < 3 * 4; i++)
NullMesh.MeshElements.Push(i);
@ -95,10 +100,11 @@ void VkRaytrace::CreateBuffers()
std::vector<CollisionNode> nodes = CreateCollisionNodes();
// std430 alignment rules forces us to convert the vec3 to a vec4
std::vector<FVector4> vertices;
std::vector<SurfaceVertex> vertices;
vertices.reserve(Mesh->MeshVertices.Size());
for (const FVector3& v : Mesh->MeshVertices)
vertices.push_back({ v, 1.0f });
for (int i = 0, count = Mesh->MeshVertices.Size(); i < count; ++i)
//vertices.push_back({ { Mesh->MeshVertices[i], 1.0f } });
vertices.push_back({ { Mesh->MeshVertices[i], 1.0f }, Mesh->MeshVertexUVs[i], float(i), i + 10000.0f});
CollisionNodeBufferHeader nodesHeader;
nodesHeader.root = Mesh->Collision->get_root();
@ -121,6 +127,13 @@ void VkRaytrace::CreateBuffers()
info.PortalIndex = surface->portalIndex;
info.SamplingDistance = (float)surface->sampleDimension;
info.Sky = surface->bSky;
if (surface->texture.isValid())
{
auto mat = FMaterial::ValidateTexture(TexMan.GetGameTexture(surface->texture), 0);
info.TextureIndex = fb->GetBindlessTextureIndex(mat, CLAMP_NONE, 0);
}
surfaceInfo.Push(info);
}
@ -132,7 +145,7 @@ void VkRaytrace::CreateBuffers()
VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT |
VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR : 0) |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT)
.Size(vertices.size() * sizeof(FVector4))
.Size(vertices.size() * sizeof(SurfaceVertex))
.DebugName("vertexBuffer")
.Create(fb->GetDevice());
@ -173,7 +186,7 @@ void VkRaytrace::CreateBuffers()
.Create(fb->GetDevice());
transferBuffer = BufferTransfer()
.AddBuffer(vertexBuffer.get(), vertices.data(), vertices.size() * sizeof(FVector4))
.AddBuffer(vertexBuffer.get(), vertices.data(), vertices.size() * sizeof(SurfaceVertex))
.AddBuffer(indexBuffer.get(), Mesh->MeshElements.Data(), (size_t)Mesh->MeshElements.Size() * sizeof(uint32_t))
.AddBuffer(nodesBuffer.get(), &nodesHeader, sizeof(CollisionNodeBufferHeader), nodes.data(), nodes.size() * sizeof(CollisionNode))
.AddBuffer(surfaceIndexBuffer.get(), Mesh->MeshSurfaceIndexes.Data(), Mesh->MeshSurfaceIndexes.Size() * sizeof(int))
@ -184,6 +197,11 @@ void VkRaytrace::CreateBuffers()
PipelineBarrier()
.AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, useRayQuery ? VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_KHR : VK_ACCESS_SHADER_READ_BIT)
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, useRayQuery ? VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_KHR : VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
if(useRayQuery)
PipelineBarrier()
.AddMemory(VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT)
.Execute(fb->GetCommands()->GetTransferCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
}
void VkRaytrace::CreateBottomLevelAccelerationStructure()
@ -199,7 +217,7 @@ void VkRaytrace::CreateBottomLevelAccelerationStructure()
accelStructBLDesc.geometry.triangles = { VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_GEOMETRY_TRIANGLES_DATA_KHR };
accelStructBLDesc.geometry.triangles.vertexFormat = VK_FORMAT_R32G32B32A32_SFLOAT;
accelStructBLDesc.geometry.triangles.vertexData.deviceAddress = vertexBuffer->GetDeviceAddress();
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(FVector4);
accelStructBLDesc.geometry.triangles.vertexStride = sizeof(SurfaceVertex);
accelStructBLDesc.geometry.triangles.indexType = VK_INDEX_TYPE_UINT32;
accelStructBLDesc.geometry.triangles.indexData.deviceAddress = indexBuffer->GetDeviceAddress();
accelStructBLDesc.geometry.triangles.maxVertex = Mesh->MeshVertices.Size() - 1;

View file

@ -33,6 +33,14 @@ struct SurfaceInfo
float Sky;
float SamplingDistance;
uint32_t PortalIndex;
int32_t TextureIndex;
float Padding;
};
struct SurfaceVertex
{
FVector4 pos;
FVector2 uv;
float Padding1, Padding2;
};

View file

@ -196,7 +196,7 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap)
}
}
SetupLightmapUvs();
SetupLightmapUvs(doomMap);
Collision = std::make_unique<TriangleMeshShape>(MeshVertices.Data(), MeshVertices.Size(), MeshElements.Data(), MeshElements.Size());
}
@ -760,12 +760,15 @@ void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
MeshVertices.Push(verts[2]);
MeshVertices.Push(verts[3]);
MeshVertexUVs.Reserve(4); // TODO implement
surf.plane = ToPlane(verts[0], verts[1], verts[2], verts[3]);
surf.Type = ST_MIDDLESIDE;
surf.typeIndex = typeIndex;
surf.sampleDimension = side->textures[side_t::mid].LightmapSampleDistance;
surf.ControlSector = nullptr;
surf.sectorGroup = sectorGroup[front->Index()];
surf.texture = side->textures[side_t::mid].texture;
Surfaces.Push(surf);
}
@ -879,8 +882,11 @@ void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
MeshVertices.Push(verts[2]);
MeshVertices.Push(verts[3]);
MeshVertexUVs.Reserve(4); // TODO implement
surf.plane = ToPlane(verts[0], verts[1], verts[2], verts[3]);
surf.sectorGroup = sectorGroup[front->Index()];
surf.texture = side->textures[side_t::mid].texture;
Surfaces.Push(surf);
}
@ -919,6 +925,8 @@ void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
MeshVertices.Push(verts[2]);
MeshVertices.Push(verts[3]);
MeshVertexUVs.Reserve(4); // TODO implement
surf.plane = ToPlane(verts[0], verts[1], verts[2], verts[3]);
surf.Type = ST_LOWERSIDE;
surf.typeIndex = typeIndex;
@ -926,6 +934,7 @@ void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
surf.sampleDimension = side->textures[side_t::bottom].LightmapSampleDistance;
surf.ControlSector = nullptr;
surf.sectorGroup = sectorGroup[front->Index()];
surf.texture = side->textures[side_t::bottom].texture;
Surfaces.Push(surf);
}
@ -959,6 +968,8 @@ void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
MeshVertices.Push(verts[2]);
MeshVertices.Push(verts[3]);
MeshVertexUVs.Reserve(4); // TODO implement
surf.plane = ToPlane(verts[0], verts[1], verts[2], verts[3]);
surf.Type = ST_UPPERSIDE;
surf.typeIndex = typeIndex;
@ -966,6 +977,7 @@ void DoomLevelMesh::CreateSideSurfaces(FLevelLocals &doomMap, side_t *side)
surf.sampleDimension = side->textures[side_t::top].LightmapSampleDistance;
surf.ControlSector = nullptr;
surf.sectorGroup = sectorGroup[front->Index()];
surf.texture = side->textures[side_t::top].texture;
Surfaces.Push(surf);
}
@ -995,8 +1007,17 @@ void DoomLevelMesh::CreateFloorSurface(FLevelLocals &doomMap, subsector_t *sub,
surf.numVerts = sub->numlines;
surf.startVertIndex = MeshVertices.Size();
surf.texture = (controlSector ? controlSector : sector)->planes[sector_t::floor].Texture;
auto txt = TexMan.GetGameTexture(surf.texture);
auto w = txt->GetDisplayWidth();
auto h = txt->GetDisplayHeight();
MeshVertices.Resize(surf.startVertIndex + surf.numVerts);
MeshVertexUVs.Resize(surf.startVertIndex + surf.numVerts);
FVector3* verts = &MeshVertices[surf.startVertIndex];
FVector2* uvs = &MeshVertexUVs[surf.startVertIndex];
for (int j = 0; j < surf.numVerts; j++)
{
@ -1006,6 +1027,8 @@ void DoomLevelMesh::CreateFloorSurface(FLevelLocals &doomMap, subsector_t *sub,
verts[j].X = v1.X;
verts[j].Y = v1.Y;
verts[j].Z = (float)plane.ZatPoint(verts[j]);
uvs[j] = FVector2(v1.X / w, v1.Y / h); // TODO rotation and offset
}
surf.Type = ST_FLOOR;
@ -1037,8 +1060,17 @@ void DoomLevelMesh::CreateCeilingSurface(FLevelLocals& doomMap, subsector_t* sub
surf.numVerts = sub->numlines;
surf.startVertIndex = MeshVertices.Size();
surf.texture = (controlSector ? controlSector : sector)->planes[sector_t::ceiling].Texture;
auto txt = TexMan.GetGameTexture(surf.texture);
auto w = txt->GetDisplayWidth();
auto h = txt->GetDisplayHeight();
MeshVertices.Resize(surf.startVertIndex + surf.numVerts);
MeshVertexUVs.Resize(surf.startVertIndex + surf.numVerts);
FVector3* verts = &MeshVertices[surf.startVertIndex];
FVector2* uvs = &MeshVertexUVs[surf.startVertIndex];
for (int j = 0; j < surf.numVerts; j++)
{
@ -1048,6 +1080,8 @@ void DoomLevelMesh::CreateCeilingSurface(FLevelLocals& doomMap, subsector_t* sub
verts[j].X = v1.X;
verts[j].Y = v1.Y;
verts[j].Z = (float)plane.ZatPoint(verts[j]);
uvs[j] = FVector2(v1.X / w, v1.Y / h); // TODO rotation and offset
}
surf.Type = ST_CEILING;
@ -1242,7 +1276,7 @@ void DoomLevelMesh::DumpMesh(const FString& objFilename, const FString& mtlFilen
fclose(f);
}
void DoomLevelMesh::SetupLightmapUvs()
void DoomLevelMesh::SetupLightmapUvs(FLevelLocals& doomMap)
{
LMTextureSize = 1024; // TODO cvar
@ -1252,6 +1286,8 @@ void DoomLevelMesh::SetupLightmapUvs()
}
BuildSmoothingGroups();
CreateSurfaceTextureUVs(doomMap);
}
void DoomLevelMesh::PackLightmapAtlas()
@ -1455,3 +1491,38 @@ void DoomLevelMesh::BuildSurfaceParams(int lightMapTextureWidth, int lightMapTex
surface.texWidth = width;
surface.texHeight = height;
}
void DoomLevelMesh::CreateSurfaceTextureUVs(FLevelLocals& doomMap)
{
auto toUv = [](const DoomLevelMeshSurface* targetSurface, FVector3 vert) {
FVector3 localPos = vert - targetSurface->translateWorldToLocal;
float u = (1.0f + (localPos | targetSurface->projLocalToU)) / (targetSurface->texWidth + 2);
float v = (1.0f + (localPos | targetSurface->projLocalToV)) / (targetSurface->texHeight + 2);
return FVector2(u, v);
};
for (auto& surface : Surfaces)
{
if (surface.texture.isValid())
{
const FVector3* verts = &MeshVertices[surface.startVertIndex];
FVector2* uvs = &MeshVertexUVs[surface.startVertIndex];
const auto gtxt = TexMan.GetGameTexture(surface.texture);
if (surface.Type == ST_FLOOR || surface.Type == ST_CEILING)
{
}
else
{
for (int i = 0; i < 4; ++i)
{
uvs[surface.atlasPageIndex + i] = verts[i] - verts[0];
uvs[surface.atlasPageIndex + i].X /= gtxt->GetDisplayWidth();
uvs[surface.atlasPageIndex + i].Y /= gtxt->GetDisplayHeight();
}
}
}
}
}

View file

@ -66,10 +66,12 @@ private:
void CreateFloorSurface(FLevelLocals& doomMap, subsector_t* sub, sector_t* sector, sector_t* controlSector, int typeIndex);
void CreateSideSurfaces(FLevelLocals &doomMap, side_t *side);
void CreateSurfaceTextureUVs(FLevelLocals& doomMap);
void SetSubsectorLightmap(DoomLevelMeshSurface* surface);
void SetSideLightmap(DoomLevelMeshSurface* surface);
void SetupLightmapUvs();
void SetupLightmapUvs(FLevelLocals& doomMap);
void PropagateLight(const LevelMeshLight* light, std::set<LevelMeshPortal, RecursivePortalComparator>& touchedPortals, int lightPropagationRecursiveDepth);
void CreateLightList();

View file

@ -21,7 +21,19 @@ layout(std430, set = 1, binding = 0) buffer NodeBuffer
int nodebufferPadding3;
CollisionNode nodes[];
};
layout(std430, set = 1, binding = 1) buffer VertexBuffer { vec4 vertices[]; };
#endif
struct SurfaceVertex
{
vec4 pos;
vec2 uv;
float Padding1, Padding2;
};
layout(std430, set = 1, binding = 1) buffer VertexBuffer { SurfaceVertex vertices[]; };
#if defined(USE_RAYQUERY)
#else
layout(std430, set = 1, binding = 2) buffer ElementBuffer { int elements[]; };
#endif
@ -39,7 +51,8 @@ struct SurfaceInfo
float Sky;
float SamplingDistance;
uint PortalIndex;
float Padding1, Padding2;
int TextureIndex;
float Padding2;
};
struct PortalInfo
@ -102,6 +115,8 @@ bool TracePoint(vec3 origin, vec3 target, float tmin, vec3 dir, float tmax);
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax);
int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float t);
vec3 primitiveWeights;
void main()
{
vec3 normal = surfaces[SurfaceIndex].Normal;
@ -241,6 +256,10 @@ int TraceFirstHitTriangleNoPortal(vec3 origin, float tmin, vec3 dir, float tmax,
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT)
{
t = rayQueryGetIntersectionTEXT(rayQuery, true);
primitiveWeights.xy = rayQueryGetIntersectionBarycentricsEXT(rayQuery, true);
primitiveWeights.z = 1.0 - primitiveWeights.x - primitiveWeights.y;
return rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
}
else
@ -310,9 +329,9 @@ float intersect_triangle_ray(RayBBox ray, int a, out float barycentricB, out flo
int start_element = nodes[a].element_index;
vec3 p[3];
p[0] = vertices[elements[start_element]].xyz;
p[1] = vertices[elements[start_element + 1]].xyz;
p[2] = vertices[elements[start_element + 2]].xyz;
p[0] = vertices[elements[start_element]].pos.xyz;
p[1] = vertices[elements[start_element + 1]].pos.xyz;
p[2] = vertices[elements[start_element + 2]].pos.xyz;
// Moeller-Trumbore ray-triangle intersection algorithm:
@ -363,6 +382,10 @@ float intersect_triangle_ray(RayBBox ray, int a, out float barycentricB, out flo
// Return hit location on triangle in barycentric coordinates
barycentricB = u;
barycentricC = v;
primitiveWeights.x = u;
primitiveWeights.y = v;
primitiveWeights.z = 1.0 - u - v;
return t;
}