Finish up portal surface mapping

This commit is contained in:
James Lambert 2022-12-21 21:12:49 -07:00
parent 80a762eee8
commit 55411ce6e2
4 changed files with 102 additions and 0 deletions

View file

@ -245,6 +245,37 @@ function Box3.nearest_point_in_box(box, point)
return Vector3.min(box.max, point):max(box.min) return Vector3.min(box.max, point):max(box.min)
end end
--- Returns the point inside or on the box that is nearest to the given point
--- @function overlaps
--- @tparam Vector3|Box3 box_or_point
--- @treturn boolean
function Box3.overlaps(box, box_or_point)
if isVector3(box_or_point) then
return box_or_point.x >= box.min.x and box_or_point.x <= box.max.x and
box_or_point.y >= box.min.y and box_or_point.y <= box.max.y and
box_or_point.z >= box.min.z and box_or_point.z <= box.max.z
end
return box.min.x < box_or_point.max.x and box_or_point.min.x < box.max.x and
box.min.y < box_or_point.max.y and box_or_point.min.y < box.max.y and
box.min.z < box_or_point.max.z and box_or_point.min.z < box.max.z;
end
--- @function __mul
--- @tparam number|Box3
--- @treturn Box3
function Box3.__mul(a, b)
if type(a) == 'number' then
return box3(a * b.min, a * b.max)
end
if type(b) == 'number' then
return box3(a.min * b, a.max * b)
end
return box3(a.min * b.min, a.max * b.max)
end
--- Gets the distance from the box to the point --- Gets the distance from the box to the point
--- If the box contains the point then the negative distance to --- If the box contains the point then the negative distance to
--- the nearest edge is returned --- the nearest edge is returned

View file

@ -13,4 +13,6 @@ sk_definition_writer.add_definition("level", "struct LevelDefinition", "_geo", {
roomStaticMapping = sk_definition_writer.reference_to(static_export.room_ranges, 1), roomStaticMapping = sk_definition_writer.reference_to(static_export.room_ranges, 1),
portalSurfaces = sk_definition_writer.reference_to(portal_surfaces.portal_surfaces, 1), portalSurfaces = sk_definition_writer.reference_to(portal_surfaces.portal_surfaces, 1),
portalSurfaceCount = #portal_surfaces.portal_surfaces, portalSurfaceCount = #portal_surfaces.portal_surfaces,
portalSurfaceMappingRange = sk_definition_writer.reference_to(portal_surfaces.portal_mapping_range, 1),
portalSurfaceMappingIndices = sk_definition_writer.reference_to(portal_surfaces.portal_mapping_data, 1),
}) })

View file

@ -212,6 +212,22 @@ local function collision_quad_bb(collision_quad)
return sk_math.box3(min, max) return sk_math.box3(min, max)
end end
local INSIDE_NORMAL_TOLERANCE = 0.1
local function is_coplanar(collision_quad, mesh, relative_scale)
for _, vertex in pairs(mesh.vertices) do
local offset = vertex * relative_scale - collision_quad.corner
local z = offset:dot(collision_quad.plane.normal)
if math.abs(z) >= INSIDE_NORMAL_TOLERANCE then
return false
end
end
return true
end
local colliders = {} local colliders = {}
local collider_types = {} local collider_types = {}
local collision_objects = {} local collision_objects = {}
@ -258,5 +274,8 @@ sk_definition_writer.add_definition("collider_types", "struct ColliderTypeData[]
sk_definition_writer.add_definition("collision_objects", "struct CollisionObject[]", "_geo", collision_objects) sk_definition_writer.add_definition("collision_objects", "struct CollisionObject[]", "_geo", collision_objects)
return { return {
is_coplanar = is_coplanar,
colliders = colliders,
collision_quad_bb = collision_quad_bb,
collision_objects = collision_objects, collision_objects = collision_objects,
} }

View file

@ -1,4 +1,5 @@
local static_export = require('tools.level_scripts.static_export') local static_export = require('tools.level_scripts.static_export')
local collision_export = require('tools.level_scripts.collision_export')
local sk_input = require('sk_input') local sk_input = require('sk_input')
local sk_math = require('sk_math') local sk_math = require('sk_math')
local sk_mesh = require('sk_mesh') local sk_mesh = require('sk_mesh')
@ -199,6 +200,55 @@ end
sk_definition_writer.add_definition("portal_surfaces", "struct PortalSurface[]", "_geo", portal_surfaces) sk_definition_writer.add_definition("portal_surfaces", "struct PortalSurface[]", "_geo", portal_surfaces)
local function is_coplanar_portal_surface(quad, mesh, collision_bb)
if not mesh.material or not portalable_surfaces[mesh.material.name] then
return false
end
if not collision_export.is_coplanar(quad, mesh, sk_input.settings.model_scale) then
return false
end
local mesh_bb = mesh.bb * sk_input.settings.model_scale
if not mesh_bb:overlaps(collision_bb) then
return false
end
return true
end
local portal_mapping_data = {}
local portal_mapping_range = {}
local mapping_index = 0
for _, quad in pairs(collision_export.colliders) do
local start_mapping_index = mapping_index
local collision_with_padding = collision_export.collision_quad_bb(quad)
collision_with_padding.min = collision_with_padding.min - 0.1
collision_with_padding.max = collision_with_padding.max + 0.1
for static_index, surface in pairs(static_export.static_nodes) do
if is_coplanar_portal_surface(quad, surface.mesh, collision_with_padding) then
table.insert(portal_mapping_data, static_to_portable_surface_mapping[static_index])
mapping_index = mapping_index + 1
end
end
if mapping_index > 255 then
error("mapping_index was greater than 255")
end
table.insert(portal_mapping_range, {start_mapping_index, mapping_index})
end
sk_definition_writer.add_definition("mapping_indices", "u8[]", "_geo", portal_mapping_data)
sk_definition_writer.add_definition("collider_to_surface", "struct PortalSurfaceMappingRange[]", "_geo", portal_mapping_range)
return { return {
portal_surfaces = portal_surfaces, portal_surfaces = portal_surfaces,
portal_mapping_data = portal_mapping_data,
portal_mapping_range = portal_mapping_range,
} }