mirror of
https://github.com/ZDoom/ZDRay.git
synced 2024-11-24 21:01:15 +00:00
Implement basic linedef sunlight portal support
This commit is contained in:
parent
1427ca5f35
commit
38916e7f75
7 changed files with 254 additions and 42 deletions
|
@ -445,6 +445,7 @@ struct FLevel
|
|||
FloatVertex GetSegVertex(int index);
|
||||
|
||||
int FindFirstSectorFromTag(int tag);
|
||||
unsigned FindFirstLineId(int lineId);
|
||||
|
||||
inline IntSector* PointInSector(const dvec2& pos) { return GetSectorFromSubSector(PointInSubSector(int(pos.x), int(pos.y))); }
|
||||
private:
|
||||
|
|
|
@ -551,6 +551,19 @@ int FLevel::FindFirstSectorFromTag(int tag)
|
|||
return -1;
|
||||
}
|
||||
|
||||
unsigned FLevel::FindFirstLineId(int lineId)
|
||||
{
|
||||
for (unsigned i = 0; i < Lines.Size(); ++i)
|
||||
{
|
||||
for (const auto& e : Lines[i].ids)
|
||||
{
|
||||
if (e == lineId)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FProcessor::GetPolySpots ()
|
||||
{
|
||||
if (Extended && CheckPolyobjs)
|
||||
|
|
|
@ -39,7 +39,13 @@ struct SurfaceInfo
|
|||
vec3 Normal;
|
||||
float Sky;
|
||||
float SamplingDistance;
|
||||
float Padding1, Padding2, Padding3;
|
||||
uint PortalIndex;
|
||||
float Padding1, Padding2;
|
||||
};
|
||||
|
||||
struct PortalInfo
|
||||
{
|
||||
mat4 Transformation;
|
||||
};
|
||||
|
||||
struct LightInfo
|
||||
|
@ -59,6 +65,7 @@ struct LightInfo
|
|||
layout(set = 0, binding = 1) buffer SurfaceIndexBuffer { uint surfaceIndices[]; };
|
||||
layout(set = 0, binding = 2) buffer SurfaceBuffer { SurfaceInfo surfaces[]; };
|
||||
layout(set = 0, binding = 3) buffer LightBuffer { LightInfo lights[]; };
|
||||
layout(set = 0, binding = 4) buffer PortalBuffer { PortalInfo portals[]; };
|
||||
|
||||
layout(push_constant) uniform PushConstants
|
||||
{
|
||||
|
@ -209,38 +216,7 @@ float RadicalInverse_VdC(uint bits)
|
|||
|
||||
#if defined(USE_RAYQUERY)
|
||||
|
||||
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||
{
|
||||
rayQueryEXT rayQuery;
|
||||
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tmin, dir, tmax);
|
||||
while(rayQueryProceedEXT(rayQuery)) { }
|
||||
return rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT;
|
||||
}
|
||||
|
||||
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||
{
|
||||
rayQueryEXT rayQuery;
|
||||
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tmin, dir, tmax);
|
||||
|
||||
while(rayQueryProceedEXT(rayQuery))
|
||||
{
|
||||
if (rayQueryGetIntersectionTypeEXT(rayQuery, false) == gl_RayQueryCommittedIntersectionTriangleEXT)
|
||||
{
|
||||
rayQueryConfirmIntersectionEXT(rayQuery);
|
||||
}
|
||||
}
|
||||
|
||||
if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionTriangleEXT)
|
||||
{
|
||||
return rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float t)
|
||||
int TraceFirstHitTriangleNoPortal(vec3 origin, float tmin, vec3 dir, float tmax, out float t)
|
||||
{
|
||||
rayQueryEXT rayQuery;
|
||||
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tmin, dir, tmax);
|
||||
|
@ -264,6 +240,16 @@ int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out fl
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||
{
|
||||
rayQueryEXT rayQuery;
|
||||
rayQueryInitializeEXT(rayQuery, acc, gl_RayFlagsTerminateOnFirstHitEXT, 0xFF, origin, tmin, dir, tmax);
|
||||
while(rayQueryProceedEXT(rayQuery)) { }
|
||||
return rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT;
|
||||
}
|
||||
*/
|
||||
|
||||
#else
|
||||
|
||||
struct RayBBox
|
||||
|
@ -376,6 +362,7 @@ bool is_leaf(int node_index)
|
|||
return nodes[node_index].element_index != -1;
|
||||
}
|
||||
|
||||
/*
|
||||
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||
{
|
||||
if (tmax <= 0.0f)
|
||||
|
@ -410,6 +397,7 @@ bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
|
|||
} while (stackIndex > 0);
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
struct TraceHit
|
||||
{
|
||||
|
@ -457,13 +445,7 @@ TraceHit find_first_hit(RayBBox ray)
|
|||
return hit;
|
||||
}
|
||||
|
||||
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||
{
|
||||
float t;
|
||||
return TraceFirstHitTriangleT(origin, tmin, dir, tmax, t);
|
||||
}
|
||||
|
||||
int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float hitFraction)
|
||||
int TraceFirstHitTriangleNoPortal(vec3 origin, float tmin, vec3 dir, float tmax, out float tparam)
|
||||
{
|
||||
// Perform segmented tracing to keep the ray AABB box smaller
|
||||
vec3 ray_start = origin;
|
||||
|
@ -480,14 +462,54 @@ int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out fl
|
|||
TraceHit hit = find_first_hit(ray);
|
||||
if (hit.fraction < 1.0)
|
||||
{
|
||||
hit.fraction = segstart * (1.0 - hit.fraction) + segend * hit.fraction;
|
||||
tparam = hit.fraction = segstart * (1.0 - hit.fraction) + segend * hit.fraction;
|
||||
return hit.triangle;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
int TraceFirstHitTriangleT(vec3 origin, float tmin, vec3 dir, float tmax, out float t)
|
||||
{
|
||||
int primitiveID;
|
||||
while(true)
|
||||
{
|
||||
primitiveID = TraceFirstHitTriangleNoPortal(origin, tmin, dir, tmax, t);
|
||||
|
||||
if(primitiveID < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
SurfaceInfo surface = surfaces[surfaceIndices[primitiveID]];
|
||||
|
||||
if(surface.PortalIndex == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Portal was hit: Apply transformation onto the ray
|
||||
mat4 transformationMatrix = portals[surface.PortalIndex].Transformation;
|
||||
|
||||
origin = (transformationMatrix * vec4(origin + dir * t, 1.0)).xyz;
|
||||
dir = (transformationMatrix * vec4(dir, 0.0)).xyz;
|
||||
tmax -= t;
|
||||
}
|
||||
return primitiveID;
|
||||
}
|
||||
|
||||
int TraceFirstHitTriangle(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||
{
|
||||
float t;
|
||||
return TraceFirstHitTriangleT(origin, tmin, dir, tmax, t);
|
||||
}
|
||||
|
||||
bool TraceAnyHit(vec3 origin, float tmin, vec3 dir, float tmax)
|
||||
{
|
||||
return TraceFirstHitTriangle(origin, tmin, dir, tmax) >= 0;
|
||||
}
|
||||
|
||||
)glsl";
|
||||
|
|
|
@ -489,6 +489,7 @@ void GPURaytracer::FinishCommands()
|
|||
void GPURaytracer::CreateVertexAndIndexBuffers()
|
||||
{
|
||||
std::vector<SurfaceInfo> surfaces = CreateSurfaceInfo();
|
||||
std::vector<PortalInfo> portals = CreatePortalInfo();
|
||||
std::vector<CollisionNode> nodes = CreateCollisionNodes();
|
||||
|
||||
// std430 alignment rules forces us to convert the vec3 to a vec4
|
||||
|
@ -536,6 +537,12 @@ void GPURaytracer::CreateVertexAndIndexBuffers()
|
|||
.DebugName("surfaceBuffer")
|
||||
.Create(device.get());
|
||||
|
||||
portalBuffer = BufferBuilder()
|
||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||
.Size(portals.size() * sizeof(PortalInfo))
|
||||
.DebugName("portalBuffer")
|
||||
.Create(device.get());
|
||||
|
||||
nodesBuffer = BufferBuilder()
|
||||
.Usage(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT)
|
||||
.Size(sizeof(CollisionNodeBufferHeader) + nodes.size() * sizeof(CollisionNode))
|
||||
|
@ -547,6 +554,7 @@ void GPURaytracer::CreateVertexAndIndexBuffers()
|
|||
.AddBuffer(indexBuffer.get(), mesh->MeshElements.Data(), (size_t)mesh->MeshElements.Size() * sizeof(uint32_t))
|
||||
.AddBuffer(surfaceIndexBuffer.get(), mesh->MeshSurfaces.Data(), (size_t)mesh->MeshSurfaces.Size() * sizeof(uint32_t))
|
||||
.AddBuffer(surfaceBuffer.get(), surfaces.data(), surfaces.size() * sizeof(SurfaceInfo))
|
||||
.AddBuffer(portalBuffer.get(), portals.data(), portals.size() * sizeof(PortalInfo))
|
||||
.AddBuffer(nodesBuffer.get(), &nodesHeader, sizeof(CollisionNodeBufferHeader), nodes.data(), nodes.size() * sizeof(CollisionNode))
|
||||
.Execute(device.get(), cmdbuffer.get());
|
||||
|
||||
|
@ -728,6 +736,7 @@ void GPURaytracer::CreateRaytracePipeline()
|
|||
.AddBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||
.AddBinding(2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||
.AddBinding(3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||
.AddBinding(4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT)
|
||||
.DebugName("raytrace.descriptorSetLayout0")
|
||||
.Create(device.get());
|
||||
|
||||
|
@ -838,6 +847,7 @@ void GPURaytracer::CreateRaytracePipeline()
|
|||
.AddBuffer(raytrace.descriptorSet0.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceIndexBuffer.get())
|
||||
.AddBuffer(raytrace.descriptorSet0.get(), 2, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, surfaceBuffer.get())
|
||||
.AddBuffer(raytrace.descriptorSet0.get(), 3, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, sceneLightBuffer.get())
|
||||
.AddBuffer(raytrace.descriptorSet0.get(), 4, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, portalBuffer.get())
|
||||
.Execute(device.get());
|
||||
}
|
||||
|
||||
|
@ -977,6 +987,16 @@ std::vector<SurfaceInfo> GPURaytracer::CreateSurfaceInfo()
|
|||
info.Sky = surface->bSky ? 1.0f : 0.0f;
|
||||
info.Normal = surface->plane.Normal();
|
||||
info.SamplingDistance = float(surface->sampleDimension);
|
||||
|
||||
if (surface->portalIndex >= 0)
|
||||
{
|
||||
info.PortalIndex = surface->portalIndex + 1; // Index 0 is already occupied. See GPURaytracer::CreatePortalInfo()
|
||||
}
|
||||
else
|
||||
{
|
||||
info.PortalIndex = 0;
|
||||
}
|
||||
|
||||
surfaces.push_back(info);
|
||||
}
|
||||
if (surfaces.empty()) // vulkan doesn't support zero byte buffers
|
||||
|
@ -984,6 +1004,28 @@ std::vector<SurfaceInfo> GPURaytracer::CreateSurfaceInfo()
|
|||
return surfaces;
|
||||
}
|
||||
|
||||
std::vector<PortalInfo> GPURaytracer::CreatePortalInfo()
|
||||
{
|
||||
std::vector<PortalInfo> portals;
|
||||
{
|
||||
PortalInfo noPortal;
|
||||
noPortal.Transformation = mat4::identity(); // index 0 will always contain identity matrix (for convenience)
|
||||
portals.push_back(noPortal);
|
||||
}
|
||||
|
||||
for (const auto& surface : mesh->surfaces)
|
||||
{
|
||||
if (surface->portalDestinationIndex >= 0)
|
||||
{
|
||||
PortalInfo info;
|
||||
info.Transformation = mesh->portals[surface->portalIndex]->transformation;
|
||||
portals.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
return portals;
|
||||
}
|
||||
|
||||
std::vector<CollisionNode> GPURaytracer::CreateCollisionNodes()
|
||||
{
|
||||
std::vector<CollisionNode> nodes;
|
||||
|
|
|
@ -33,9 +33,19 @@ struct SurfaceInfo
|
|||
vec3 Normal;
|
||||
float Sky;
|
||||
float SamplingDistance;
|
||||
float Padding1, Padding2, Padding3;
|
||||
uint32_t PortalIndex;
|
||||
float Padding1, Padding2;
|
||||
};
|
||||
|
||||
static_assert(sizeof(SurfaceInfo) == sizeof(float) * 8);
|
||||
|
||||
struct PortalInfo
|
||||
{
|
||||
mat4 Transformation;
|
||||
};
|
||||
|
||||
static_assert(sizeof(PortalInfo) == sizeof(float) * 16);
|
||||
|
||||
struct LightInfo
|
||||
{
|
||||
vec3 Origin;
|
||||
|
@ -128,6 +138,7 @@ private:
|
|||
void PrintVulkanInfo();
|
||||
|
||||
std::vector<SurfaceInfo> CreateSurfaceInfo();
|
||||
std::vector<PortalInfo> CreatePortalInfo();
|
||||
std::vector<CollisionNode> CreateCollisionNodes();
|
||||
|
||||
static vec2 ToUV(const vec3& vert, const Surface* targetSurface);
|
||||
|
@ -158,6 +169,7 @@ private:
|
|||
std::unique_ptr<VulkanBuffer> transferBuffer;
|
||||
std::unique_ptr<VulkanBuffer> surfaceIndexBuffer;
|
||||
std::unique_ptr<VulkanBuffer> surfaceBuffer;
|
||||
std::unique_ptr<VulkanBuffer> portalBuffer;
|
||||
std::unique_ptr<VulkanBuffer> nodesBuffer;
|
||||
|
||||
std::unique_ptr<VulkanBuffer> blScratchBuffer;
|
||||
|
|
|
@ -480,6 +480,117 @@ void LevelMesh::CreateSideSurfaces(FLevel &doomMap, IntSideDef *side)
|
|||
vec2 dx(v2.x - v1.x, v2.y - v1.y);
|
||||
float distance = length(dx);
|
||||
|
||||
// line portal
|
||||
if (side->line->special == Line_SetPortal && side->line->frontsector == front)
|
||||
{
|
||||
const unsigned destLineIndex = doomMap.FindFirstLineId(side->line->args[0]);
|
||||
|
||||
if (destLineIndex < doomMap.Lines.Size())
|
||||
{
|
||||
float texWidth = 128.0f;
|
||||
float texHeight = 128.0f;
|
||||
|
||||
auto surf = std::make_unique<Surface>();
|
||||
surf->material = side->midtexture;
|
||||
surf->verts.resize(4);
|
||||
surf->bSky = false;
|
||||
|
||||
surf->verts[0].x = surf->verts[2].x = v1.x;
|
||||
surf->verts[0].y = surf->verts[2].y = v1.y;
|
||||
surf->verts[1].x = surf->verts[3].x = v2.x;
|
||||
surf->verts[1].y = surf->verts[3].y = v2.y;
|
||||
surf->verts[0].z = v1Bottom;
|
||||
surf->verts[1].z = v2Bottom;
|
||||
surf->verts[2].z = v1Top;
|
||||
surf->verts[3].z = v2Top;
|
||||
|
||||
surf->plane.SetNormal(surf->verts[0], surf->verts[1], surf->verts[2], surf->verts[3]);
|
||||
surf->plane.SetDistance(surf->verts[0]);
|
||||
surf->type = ST_MIDDLESIDE;
|
||||
surf->typeIndex = typeIndex;
|
||||
surf->controlSector = nullptr;
|
||||
surf->sampleDimension = (surf->sampleDimension = side->GetSampleDistanceMiddle()) ? surf->sampleDimension : defaultSamples;
|
||||
|
||||
float texZ = surf->verts[0].z;
|
||||
|
||||
surf->texUV.resize(4);
|
||||
surf->texUV[0].x = 0.0f;
|
||||
surf->texUV[1].x = distance / texWidth;
|
||||
surf->texUV[2].x = 0.0f;
|
||||
surf->texUV[3].x = distance / texWidth;
|
||||
surf->texUV[0].y = (surf->verts[0].z - texZ) / texHeight;
|
||||
surf->texUV[1].y = (surf->verts[1].z - texZ) / texHeight;
|
||||
surf->texUV[2].y = (surf->verts[2].z - texZ) / texHeight;
|
||||
surf->texUV[3].y = (surf->verts[3].z - texZ) / texHeight;
|
||||
|
||||
surf->portalDestinationIndex = destLineIndex;
|
||||
|
||||
// Portal calculation
|
||||
{
|
||||
auto portal = std::make_unique<Portal>();
|
||||
|
||||
// Calculate portal transformation
|
||||
{
|
||||
auto& destLine = doomMap.Lines[destLineIndex];
|
||||
FloatVertex destV1 = doomMap.GetSegVertex(destLine.v1);
|
||||
FloatVertex destV2 = doomMap.GetSegVertex(destLine.v2);
|
||||
|
||||
int alignment = side->line->args[3];
|
||||
|
||||
double dstAZ = 0;
|
||||
double dstBZ = 0;
|
||||
double srcAZ = 0;
|
||||
double srcBZ = 0;
|
||||
|
||||
const auto* dstFront = doomMap.GetFrontSector(&doomMap.Sides[destLine.sidenum[0]]);
|
||||
|
||||
if (alignment == 1) // floor
|
||||
{
|
||||
srcAZ = front->floorplane.zAt(v1.x, v1.y);
|
||||
srcBZ = front->floorplane.zAt(v2.x, v2.y);
|
||||
dstAZ = dstFront->floorplane.zAt(destV1.x, destV1.y);
|
||||
dstBZ = dstFront->floorplane.zAt(destV2.x, destV2.y);
|
||||
}
|
||||
else if (alignment == 2) // ceiling
|
||||
{
|
||||
srcAZ = front->ceilingplane.zAt(v1.x, v1.y);
|
||||
srcBZ = front->ceilingplane.zAt(v2.x, v2.y);
|
||||
dstAZ = dstFront->ceilingplane.zAt(destV1.x, destV1.y);
|
||||
dstBZ = dstFront->ceilingplane.zAt(destV2.x, destV2.y);
|
||||
}
|
||||
|
||||
const vec3 vecSrcA = vec3(vec2(v1.x, v1.y), srcAZ);
|
||||
const vec3 vecSrcB = vec3(vec2(v2.x, v2.y), srcAZ);
|
||||
const vec3 vecDstA = vec3(vec2(destV1.x, destV1.y), dstAZ);
|
||||
const vec3 vecDstB = vec3(vec2(destV2.x, destV2.y), dstBZ);
|
||||
|
||||
// Translation
|
||||
vec3 originSrc = (vecSrcB + vecSrcA) * 0.5f;
|
||||
vec3 originDst = (vecDstB + vecDstA) * 0.5f;
|
||||
|
||||
vec3 translation = originDst - originSrc;
|
||||
|
||||
// Rotation
|
||||
// TODO :(
|
||||
|
||||
// printf("Portal translation: %.3f %.3f %.3f\n", translation.x, translation.y, translation.z);
|
||||
|
||||
portal->transformation = mat4::translate(translation);
|
||||
}
|
||||
|
||||
surf->portalIndex = portals.size();
|
||||
portals.push_back(std::move(portal));
|
||||
}
|
||||
|
||||
surfaces.push_back(std::move(surf));
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Warn about broken portal?
|
||||
}
|
||||
}
|
||||
|
||||
// line_horizont consumes everything
|
||||
if (side->line->special == Line_Horizon && front != back)
|
||||
{
|
||||
|
|
|
@ -59,6 +59,11 @@ enum SurfaceType
|
|||
ST_FLOOR
|
||||
};
|
||||
|
||||
struct Portal
|
||||
{
|
||||
mat4 transformation = mat4::identity();
|
||||
};
|
||||
|
||||
struct Surface
|
||||
{
|
||||
// Surface geometry
|
||||
|
@ -77,6 +82,10 @@ struct Surface
|
|||
int sampleDimension = 0;
|
||||
bool bSky = false;
|
||||
|
||||
// Portal
|
||||
int portalDestinationIndex = -1; // line or sector index
|
||||
int portalIndex = -1;
|
||||
|
||||
// Touching light sources
|
||||
std::vector<ThingLight*> LightList;
|
||||
|
||||
|
@ -124,6 +133,8 @@ public:
|
|||
|
||||
std::vector<Plane> smoothingGroups;
|
||||
|
||||
std::vector<std::unique_ptr<Portal>> portals;
|
||||
|
||||
int defaultSamples = 16;
|
||||
int textureWidth = 128;
|
||||
int textureHeight = 128;
|
||||
|
|
Loading…
Reference in a new issue