Only offset portal surface when trying decals are on the same surface

This commit is contained in:
James Lambert 2023-11-26 21:20:11 -07:00
parent 5c345c25d8
commit 516b30b0b4
8 changed files with 58 additions and 18 deletions

View file

@ -316,7 +316,7 @@ function Box3.nearest_point_in_box(box, point)
return Vector3.min(box.max, point):max(box.min)
end
--- Returns the point inside or on the box that is nearest to the given point
--- Returns true of the two bounding boxes have some volume in common
--- @function overlaps
--- @tparam Vector3|Box3 box_or_point
--- @treturn boolean

View file

@ -51,6 +51,8 @@ void sceneSerializePortals(struct Serializer* serializer, SerializeAction action
}
}
#define PORTAL_FLAGS_TO_DESERIALIZE (PortalFlagsPlayerPortal | PortalFlagsZOffset)
void sceneDeserializePortals(struct Serializer* serializer, struct Scene* scene) {
for (int portalIndex = 0; portalIndex < 2; ++portalIndex) {
char flags;
@ -98,11 +100,8 @@ void sceneDeserializePortals(struct Serializer* serializer, struct Scene* scene)
collisionSceneSetPortal(portalIndex, &portal->rigidBody.transform, roomIndex, colliderIndex);
collisionObjectUpdateBB(&portal->collisionObject);
if (flags & PortalFlagsPlayerPortal) {
portal->flags |= PortalFlagsPlayerPortal;
} else {
portal->flags &= ~PortalFlagsPlayerPortal;
}
portal->flags &= ~PORTAL_FLAGS_TO_DESERIALIZE;
portal->flags |= PORTAL_FLAGS_TO_DESERIALIZE & flags;
portal->opacity = 0.0f;
}

View file

@ -17,6 +17,7 @@
enum PortalFlags {
PortalFlagsOddParity = (1 << 0),
PortalFlagsPlayerPortal = (1 << 2),
PortalFlagsZOffset = (1 << 3),
};
struct Portal {

View file

@ -27,6 +27,7 @@ struct PortalSurface {
u8 edgeCount;
u8 vertexCount;
u8 shouldCleanup;
u8 hasDecals;
struct Vector3 right;
struct Vector3 up;

View file

@ -563,13 +563,15 @@ void renderPlanExecute(struct RenderPlan* renderPlan, struct Scene* scene, Mtx*
faceModel = portal_portal_orange_face_model_gfx;
portalModel = portal_portal_orange_model_gfx;
}
// render the portal cover with a slightly offset z
// so it doesn't z fight with the surface it is attached to
Vp* vpWithOffset = renderStateRequestViewport(renderState);
*vpWithOffset = *current->viewport;
vpWithOffset->vp.vtrans[2] -= 1;
gSPViewport(renderState->dl++, vpWithOffset);
if (portal->flags & PortalFlagsZOffset) {
// render the portal cover with a slightly offset z
// so it doesn't z fight with the surface it is attached to
Vp* vpWithOffset = renderStateRequestViewport(renderState);
*vpWithOffset = *current->viewport;
vpWithOffset->vp.vtrans[2] -= 2;
gSPViewport(renderState->dl++, vpWithOffset);
}
gSPDisplayList(renderState->dl++, faceModel);
gSPViewport(renderState->dl++, current->viewport);
if (current->previousProperties == NULL && portalIndex == renderPlan->clippedPortalIndex && renderPlan->nearPolygonCount) {

View file

@ -860,6 +860,12 @@ int sceneOpenPortal(struct Scene* scene, struct Transform* at, int transformInde
portal->flags &= ~PortalFlagsPlayerPortal;
}
if (existingSurface->hasDecals) {
portal->flags |= PortalFlagsZOffset;
} else {
portal->flags &= ~PortalFlagsZOffset;
}
if (collisionSceneIsPortalOpen()) {
// the second portal is fully transparent right away
portal->opacity = 0.0f;

View file

@ -58,7 +58,7 @@ local function get_edge_index(edges, edge_key)
return 0xFF
end
local function calculate_portal_single_surface(mesh, mesh_display_list)
local function calculate_portal_single_surface(mesh, mesh_display_list, has_decals)
local origin = mesh.bb:lerp(0.5)
local right, up, normal = calculate_surface_basis(mesh)
@ -129,6 +129,7 @@ local function calculate_portal_single_surface(mesh, mesh_display_list)
edgeCount = #edges,
vertexCount = #vertices,
shouldCleanup = 0,
hasDecals = has_decals,
right = right,
up = up,
@ -142,7 +143,7 @@ end
for _, surface in pairs(static_export.static_nodes) do
if surface.accept_portals then
table.insert(static_to_portable_surface_mapping, #portal_surfaces)
table.insert(portal_surfaces, calculate_portal_single_surface(surface.mesh, surface.display_list))
table.insert(portal_surfaces, calculate_portal_single_surface(surface.mesh, surface.display_list, surface.has_decals))
else
table.insert(static_to_portable_surface_mapping, -1)
end

View file

@ -33,7 +33,7 @@ local function is_coplanar(mesh, plane)
end
local function should_join_mesh(entry)
return entry.plane ~= nil
return entry.should_join_mesh
end
local function bb_union_cost(a, b)
@ -76,6 +76,28 @@ local function bb_list(bb)
}
end
local function check_for_decals(portal_surface, all_static_ndes)
if not portal_surface.accept_portals then
return false
end
local box_with_padding = sk_math.box3(portal_surface.original_bb.min - 0.1, portal_surface.original_bb.max + 0.1)
for _, other in pairs(all_static_ndes) do
local material = other.chunk.mesh.material
if material.renderMode and
material.renderMode.zMode == "ZMODE_DEC" and
portal_surface.transform_index == other.transform_index and
is_coplanar(other.chunk.mesh, portal_surface.plane) and
box_with_padding:overlaps(other.original_bb) then
return true
end
end
return false
end
local function list_static_nodes(nodes)
local result = {}
local bb_scale = sk_input.settings.fixed_point_scale
@ -100,10 +122,11 @@ local function list_static_nodes(nodes)
end
local plane = sk_math.plane3_with_point(chunkV.mesh.normals[1], chunkV.mesh.vertices[1])
local accept_portals =chunkV.mesh.material and portalable_surfaces[chunkV.mesh.material.name] and not sk_scene.find_flag_argument(v.arguments, "no_portals")
local should_join_mesh = true
local accept_portals = chunkV.mesh.material and portalable_surfaces[chunkV.mesh.material.name] and not sk_scene.find_flag_argument(v.arguments, "no_portals")
if transform_index or signal or accept_portals or not is_coplanar(chunkV.mesh, plane) then
plane = nil
should_join_mesh = false
end
insert_or_merge(result, {
@ -113,13 +136,19 @@ local function list_static_nodes(nodes)
transform_index = transform_index,
room_index = room_export.node_nearest_room_index(v.node) or 0,
accept_portals = accept_portals,
has_decals = false,
signal = signal,
original_bb = original_bb,
plane = plane,
should_join_mesh = should_join_mesh,
})
end
end
for _, node in pairs(result) do
node.has_decals = check_for_decals(node, result)
end
return result;
end
@ -320,6 +349,7 @@ local function process_static_nodes(nodes)
transform_index = source_node.transform_index,
room_index = source_node.room_index,
accept_portals = source_node.accept_portals,
has_decals = source_node.has_decals,
signal = source_node.signal,
})
end