diff --git a/src/common/rendering/hwrenderer/data/hw_levelmesh.h b/src/common/rendering/hwrenderer/data/hw_levelmesh.h index 92658d2c5..1d017dcef 100644 --- a/src/common/rendering/hwrenderer/data/hw_levelmesh.h +++ b/src/common/rendering/hwrenderer/data/hw_levelmesh.h @@ -8,9 +8,11 @@ #include "common/utility/matrix.h" #include #include +#include "textureid.h" #include + typedef dp::rect_pack::RectPacker 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 MeshVertices; + TArray MeshVertexUVs; TArray MeshUVIndex; TArray MeshElements; TArray MeshSurfaceIndexes; diff --git a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp index 130f8709d..b00b0543a 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_lightmap.cpp @@ -412,6 +412,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 diff --git a/src/common/rendering/vulkan/accelstructs/vk_raytrace.cpp b/src/common/rendering/vulkan/accelstructs/vk_raytrace.cpp index 3b2f7f04a..611483ad5 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_raytrace.cpp +++ b/src/common/rendering/vulkan/accelstructs/vk_raytrace.cpp @@ -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 nodes = CreateCollisionNodes(); // std430 alignment rules forces us to convert the vec3 to a vec4 - std::vector vertices; + std::vector 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; diff --git a/src/common/rendering/vulkan/accelstructs/vk_raytrace.h b/src/common/rendering/vulkan/accelstructs/vk_raytrace.h index a1115194f..e80f45e2e 100644 --- a/src/common/rendering/vulkan/accelstructs/vk_raytrace.h +++ b/src/common/rendering/vulkan/accelstructs/vk_raytrace.h @@ -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; }; diff --git a/src/rendering/hwrenderer/doom_levelmesh.cpp b/src/rendering/hwrenderer/doom_levelmesh.cpp index 16b6e7cd7..b7fe81a02 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.cpp +++ b/src/rendering/hwrenderer/doom_levelmesh.cpp @@ -196,7 +196,7 @@ DoomLevelMesh::DoomLevelMesh(FLevelLocals &doomMap) } } - SetupLightmapUvs(); + SetupLightmapUvs(doomMap); Collision = std::make_unique(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(); + } + } + } + } +} \ No newline at end of file diff --git a/src/rendering/hwrenderer/doom_levelmesh.h b/src/rendering/hwrenderer/doom_levelmesh.h index e290a26bb..41387f999 100644 --- a/src/rendering/hwrenderer/doom_levelmesh.h +++ b/src/rendering/hwrenderer/doom_levelmesh.h @@ -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& touchedPortals, int lightPropagationRecursiveDepth); void CreateLightList(); diff --git a/wadsrc/static/shaders/lightmap/frag_raytrace.glsl b/wadsrc/static/shaders/lightmap/frag_raytrace.glsl index 80b44a323..538149076 100644 --- a/wadsrc/static/shaders/lightmap/frag_raytrace.glsl +++ b/wadsrc/static/shaders/lightmap/frag_raytrace.glsl @@ -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; }