Raycasted intersector lightmapping
This commit is contained in:
parent
0c32e21955
commit
d0ecf09b06
@ -18,12 +18,15 @@ App::App()
|
|||||||
|
|
||||||
size_t s1i = world_.AddSector(room001);
|
size_t s1i = world_.AddSector(room001);
|
||||||
game::Sector& s1 = world_.GetSector(s1i);
|
game::Sector& s1 = world_.GetSector(s1i);
|
||||||
s1.AddLight(glm::vec3(0.0f, 0.0f, 1.8f), glm::vec3(0.0f, 1.0f, 1.0f), 5.0f);
|
s1.AddLight(glm::vec3(0.0f, 2.0f, 1.8f), glm::vec3(0.0f, 1.0f, 1.0f), 5.0f);
|
||||||
|
s1.AddLight(glm::vec3(1.0f, 3.0f, 1.8f), glm::vec3(1.0f, 0.0f, 0.0f), 5.0f);
|
||||||
|
|
||||||
size_t s2i = world_.AddSector(room001);
|
size_t s2i = world_.AddSector(room001);
|
||||||
game::Sector& s2 = world_.GetSector(s2i);
|
game::Sector& s2 = world_.GetSector(s2i);
|
||||||
s2.AddLight(glm::vec3(0.0f, 0.0f, 1.8f), glm::vec3(1.0f, 1.0f, 0.9f), 6.0f);
|
s2.AddLight(glm::vec3(0.0f, 2.0f, 1.8f), glm::vec3(1.0f, 1.0f, 0.9f), 6.0f);
|
||||||
|
s2.AddLight(glm::vec3(2.0f, -0.0f, 1.0f), glm::vec3(0.0f, 1.0f, 0.0f), 3.0f);
|
||||||
|
|
||||||
|
world_.LinkPortals(s1i, "EDoor", s1i, "EDoor", 0);
|
||||||
world_.LinkPortals(s1i, "NDoor", s2i, "WDoor", 0);
|
world_.LinkPortals(s1i, "NDoor", s2i, "WDoor", 0);
|
||||||
world_.LinkPortals(s2i, "NDoor", s2i, "SDoor", 0);
|
world_.LinkPortals(s2i, "NDoor", s2i, "SDoor", 0);
|
||||||
world_.LinkPortals(s2i, "EDoor", s2i, "EDoor", game::LINK_ROTATE180);
|
world_.LinkPortals(s2i, "EDoor", s2i, "EDoor", game::LINK_ROTATE180);
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h>
|
||||||
|
|
||||||
game::Sector::Sector(World* world, size_t idx, std::shared_ptr<assets::SectorDef> def) :
|
game::Sector::Sector(World* world, size_t idx, std::shared_ptr<assets::SectorDef> def) :
|
||||||
world_(world),
|
world_(world),
|
||||||
@ -50,16 +51,20 @@ game::Sector::Sector(World* world, size_t idx, std::shared_ptr<assets::SectorDef
|
|||||||
|
|
||||||
portal_map_[def_portal.name] = i;
|
portal_map_[def_portal.name] = i;
|
||||||
|
|
||||||
|
glm::vec3 portal_normal = glm::normalize(glm::vec3(portal.plane));
|
||||||
|
const float half_portal_thickness = 0.1f;
|
||||||
|
glm::vec3 portal_position = def_portal.origin - portal_normal * half_portal_thickness;
|
||||||
|
|
||||||
// create portal collision object
|
// create portal collision object
|
||||||
portal.bt_col_shape = std::make_unique<btBoxShape>(
|
portal.bt_col_shape = std::make_unique<btBoxShape>(
|
||||||
btVector3(portal.def->size.x * portal.scale * 0.5f, 0.1f, portal.def->size.y * portal.scale * 0.5f)
|
btVector3(portal.def->size.x * portal.scale * 0.5f, half_portal_thickness, portal.def->size.y * portal.scale * 0.5f)
|
||||||
);
|
);
|
||||||
|
|
||||||
portal.bt_col_obj = std::make_unique<btCollisionObject>();
|
portal.bt_col_obj = std::make_unique<btCollisionObject>();
|
||||||
portal.bt_col_obj->setCollisionShape(portal.bt_col_shape.get());
|
portal.bt_col_obj->setCollisionShape(portal.bt_col_shape.get());
|
||||||
|
|
||||||
btQuaternion bt_rotation(angles_rad.x, angles_rad.y, angles_rad.z);
|
btQuaternion bt_rotation(angles_rad.x, angles_rad.y, angles_rad.z);
|
||||||
btVector3 bt_position(def_portal.origin.x, def_portal.origin.y, def_portal.origin.z);
|
btVector3 bt_position(portal_position.x, portal_position.y, portal_position.z);
|
||||||
btTransform bt_transform(bt_rotation, bt_position);
|
btTransform bt_transform(bt_rotation, bt_position);
|
||||||
portal.bt_col_obj->setWorldTransform(bt_transform);
|
portal.bt_col_obj->setWorldTransform(bt_transform);
|
||||||
|
|
||||||
@ -84,6 +89,7 @@ void game::Sector::AddLight(const glm::vec3& position, const glm::vec3& color, f
|
|||||||
light.position = position;
|
light.position = position;
|
||||||
light.color = color;
|
light.color = color;
|
||||||
light.radius = radius;
|
light.radius = radius;
|
||||||
|
light.through_portal = nullptr; // The light is here
|
||||||
lights_.push_back(light);
|
lights_.push_back(light);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,10 +270,161 @@ const game::Portal* game::Sector::TestPortalContact(btCapsuleShapeZ& capsule, co
|
|||||||
return result_callback.portal;
|
return result_callback.portal;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool PointIsOnRight(const glm::vec2& p0, const glm::vec2& p1, const glm::vec2& p)
|
namespace game
|
||||||
{
|
{
|
||||||
// Check if point p is on the right side of the line segment p0 -> p1
|
struct SectorClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
|
||||||
return (p1.x - p0.x) * (p.y - p0.y) - (p1.y - p0.y) * (p.x - p0.x) < 0.0f;
|
{
|
||||||
|
using Super = btCollisionWorld::ClosestRayResultCallback;
|
||||||
|
|
||||||
|
glm::vec3 dir;
|
||||||
|
float min_fraction = 0.0f; // Minimum fraction to consider a hit valid
|
||||||
|
|
||||||
|
SectorClosestRayResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld) :
|
||||||
|
Super(rayFromWorld, rayToWorld)
|
||||||
|
{
|
||||||
|
glm::vec3 start(rayFromWorld.x(), rayFromWorld.y(), rayFromWorld.z());
|
||||||
|
glm::vec3 end(rayToWorld.x(), rayToWorld.y(), rayToWorld.z());
|
||||||
|
dir = end - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) override
|
||||||
|
{
|
||||||
|
void* ptr = rayResult.m_collisionObject->getUserPointer();
|
||||||
|
CollisionObjectData* data = static_cast<CollisionObjectData*>(ptr);
|
||||||
|
|
||||||
|
if (data && data->type == CO_PORTAL)
|
||||||
|
{
|
||||||
|
float dot = glm::dot(glm::vec3(data->portal->plane), dir);
|
||||||
|
if (dot > 0.0f)
|
||||||
|
{
|
||||||
|
// The ray is going in the opposite direction of the portal plane, ignore this hit
|
||||||
|
return m_closestHitFraction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rayResult.m_hitFraction < min_fraction)
|
||||||
|
{
|
||||||
|
// Ignore hits that are before the minimum fraction
|
||||||
|
return m_closestHitFraction;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Super::addSingleResult(rayResult, normalInWorldSpace);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool game::Sector::Raycast(const Sector*& sector, const glm::vec3& start, const glm::vec3& end, std::vector<const Portal*>* out_traversed_portals)
|
||||||
|
{
|
||||||
|
glm::vec3 start_to_end = end - start;
|
||||||
|
float distance = glm::length(start_to_end);
|
||||||
|
glm::vec3 dir = start_to_end / distance;
|
||||||
|
|
||||||
|
float start_offset = 0.1f; // Start the ray a bit earlier to avoid missing close portals
|
||||||
|
distance += start_offset;
|
||||||
|
|
||||||
|
glm::vec3 ray_start = start - dir * start_offset;
|
||||||
|
glm::vec3 ray_end = end;
|
||||||
|
float min_fraction = start_offset / distance;
|
||||||
|
|
||||||
|
const int MAX_PORTAL_TRAVERSALS = 4;
|
||||||
|
for (int i = 0; i < MAX_PORTAL_TRAVERSALS; ++i)
|
||||||
|
{
|
||||||
|
btVector3 bt_start(ray_start.x, ray_start.y, ray_start.z);
|
||||||
|
btVector3 bt_end(ray_end.x, ray_end.y, ray_end.z);
|
||||||
|
|
||||||
|
SectorClosestRayResultCallback cb(bt_start, bt_end);
|
||||||
|
cb.min_fraction = min_fraction;
|
||||||
|
cb.m_flags = btTriangleRaycastCallback::kF_FilterBackfaces;
|
||||||
|
|
||||||
|
sector->bt_world_.rayTest(bt_start, bt_end, cb);
|
||||||
|
|
||||||
|
if (!cb.hasHit())
|
||||||
|
{
|
||||||
|
// No hit, we reached the end of the ray
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We hit something, check if it's a portal
|
||||||
|
void* ptr = cb.m_collisionObject->getUserPointer();
|
||||||
|
CollisionObjectData* data = static_cast<CollisionObjectData*>(ptr);
|
||||||
|
|
||||||
|
if (data && data->type == CO_PORTAL)
|
||||||
|
{
|
||||||
|
const Portal* portal = data->portal;
|
||||||
|
|
||||||
|
if (out_traversed_portals)
|
||||||
|
{
|
||||||
|
out_traversed_portals->push_back(portal);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!portal->link)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transform the ray start and end to the portal's sector space
|
||||||
|
glm::vec3 hit_point(
|
||||||
|
cb.m_hitPointWorld.x(),
|
||||||
|
cb.m_hitPointWorld.y(),
|
||||||
|
cb.m_hitPointWorld.z()
|
||||||
|
);
|
||||||
|
|
||||||
|
ray_start = glm::vec3(portal->tr_position * glm::vec4(hit_point, 1.0f));
|
||||||
|
ray_end = glm::vec3(portal->tr_position * glm::vec4(ray_end, 1.0f));
|
||||||
|
min_fraction = 0.0f;
|
||||||
|
|
||||||
|
// Update the sector to the linked one
|
||||||
|
sector = portal->link->sector;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We hit something that is not a portal, return success
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::Sector::GetLightsAt(const glm::vec3& pos, std::vector<Light>& out_lights) const
|
||||||
|
{
|
||||||
|
for (const Light& light : all_lights_)
|
||||||
|
{
|
||||||
|
float dist = glm::distance(light.position, pos);
|
||||||
|
if (dist >= light.radius)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Sector* sector = this;
|
||||||
|
static std::vector<const Portal*> traversed_portals;
|
||||||
|
traversed_portals.clear();
|
||||||
|
|
||||||
|
bool hit = Raycast(sector, pos, light.position, &traversed_portals);
|
||||||
|
|
||||||
|
if (hit)
|
||||||
|
{
|
||||||
|
continue; // The light ray is blocked
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!light.through_portal && !traversed_portals.empty())
|
||||||
|
{
|
||||||
|
// The light is not through a portal, but we traversed some portals
|
||||||
|
// This means the light is not visible from this position
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (light.through_portal && !(traversed_portals.size() == 1 && traversed_portals[0] == light.through_portal))
|
||||||
|
{
|
||||||
|
// Ray didnt traverse through the portal that the light is visible through
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_lights.push_back(light);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static float SignedDistanceToLine(const glm::vec2& p0, const glm::vec2& p1, const glm::vec2& p)
|
static float SignedDistanceToLine(const glm::vec2& p0, const glm::vec2& p1, const glm::vec2& p)
|
||||||
@ -276,9 +433,47 @@ static float SignedDistanceToLine(const glm::vec2& p0, const glm::vec2& p1, cons
|
|||||||
return (p1.x - p0.x) * (p.y - p0.y) - (p1.y - p0.y) * (p.x - p0.x);
|
return (p1.x - p0.x) * (p.y - p0.y) - (p1.y - p0.y) * (p.x - p0.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void game::Sector::Bake()
|
||||||
|
{
|
||||||
|
GenerateAllLights();
|
||||||
|
BakeLightmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void game::Sector::GenerateAllLights()
|
||||||
|
{
|
||||||
|
all_lights_.clear();
|
||||||
|
|
||||||
|
// Add lights from this sector
|
||||||
|
for (const Light& light : lights_)
|
||||||
|
{
|
||||||
|
all_lights_.push_back(light);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add lights from linked sectors
|
||||||
|
for (const Portal& portal : portals_)
|
||||||
|
{
|
||||||
|
if (!portal.link)
|
||||||
|
{
|
||||||
|
continue; // No link, skip
|
||||||
|
}
|
||||||
|
|
||||||
|
const Sector* linked_sector = portal.link->sector;
|
||||||
|
|
||||||
|
for (const Light& ext_light : linked_sector->lights_)
|
||||||
|
{
|
||||||
|
Light light = ext_light;
|
||||||
|
light.position = glm::vec3(portal.link->tr_position * glm::vec4(ext_light.position, 1.0f)); // Transform light position to this sector's space
|
||||||
|
light.radius = ext_light.radius * portal.tr_scale; // Scale the radius
|
||||||
|
light.through_portal = &portal;
|
||||||
|
|
||||||
|
all_lights_.push_back(light);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void game::Sector::BakeLightmap()
|
void game::Sector::BakeLightmap()
|
||||||
{
|
{
|
||||||
const size_t lightmap_size = 256;
|
const size_t lightmap_size = 512;
|
||||||
const glm::vec3 ambient_light(0.2f); // Ambient light color
|
const glm::vec3 ambient_light(0.2f); // Ambient light color
|
||||||
const float margin = 2.0f;
|
const float margin = 2.0f;
|
||||||
|
|
||||||
@ -287,21 +482,24 @@ void game::Sector::BakeLightmap()
|
|||||||
|
|
||||||
struct LightmapTexel
|
struct LightmapTexel
|
||||||
{
|
{
|
||||||
bool used = false;
|
bool used = false; // Inside triangle or margin
|
||||||
|
bool inside = false; // Actually inside a triangle
|
||||||
glm::vec3 color = glm::vec3(0.0f);
|
glm::vec3 color = glm::vec3(0.0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<LightmapTexel> lightmap(lightmap_size * lightmap_size);
|
std::vector<LightmapTexel> lightmap(lightmap_size * lightmap_size);
|
||||||
|
|
||||||
|
std::vector<Light> lights;
|
||||||
|
|
||||||
for (const assets::MeshTriangle& tri : mesh_tris)
|
for (const assets::MeshTriangle& tri : mesh_tris)
|
||||||
{
|
{
|
||||||
//const assets::MeshVertex* verts[3];
|
|
||||||
glm::vec2 verts[3];
|
glm::vec2 verts[3];
|
||||||
glm::vec3 vert_pos[3];
|
glm::vec3 vert_pos[3];
|
||||||
glm::vec3 vert_norm[3];
|
glm::vec3 vert_norm[3];
|
||||||
|
|
||||||
collision::AABB2 tri_aabb;
|
collision::AABB2 tri_aabb;
|
||||||
|
|
||||||
|
|
||||||
for (size_t i = 0; i < 3; ++i)
|
for (size_t i = 0; i < 3; ++i)
|
||||||
{
|
{
|
||||||
const assets::MeshVertex& vert = mesh_verts[tri.vert[i]];
|
const assets::MeshVertex& vert = mesh_verts[tri.vert[i]];
|
||||||
@ -325,30 +523,25 @@ void game::Sector::BakeLightmap()
|
|||||||
{
|
{
|
||||||
LightmapTexel& texel = lightmap[y * lightmap_size + x];
|
LightmapTexel& texel = lightmap[y * lightmap_size + x];
|
||||||
|
|
||||||
if (texel.used)
|
if (texel.inside)
|
||||||
{
|
{
|
||||||
continue;
|
continue; // Texel was already inside another triangle
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 texel_pos((float)x + 0.5f, (float)y + 0.5f); // Center of the texel
|
glm::vec2 texel_pos((float)x + 0.5f, (float)y + 0.5f); // Center of the texel
|
||||||
|
|
||||||
//if (PointIsOnRight(verts[0], verts[1], texel_pos) ||
|
// Calculate signed distance to the triangle edges
|
||||||
// PointIsOnRight(verts[1], verts[2], texel_pos) ||
|
|
||||||
// PointIsOnRight(verts[2], verts[0], texel_pos))
|
|
||||||
//{
|
|
||||||
// continue; // Texel is outside the triangle
|
|
||||||
//}
|
|
||||||
|
|
||||||
float sd = SignedDistanceToLine(verts[0], verts[1], texel_pos);
|
float sd = SignedDistanceToLine(verts[0], verts[1], texel_pos);
|
||||||
sd = glm::min(sd, SignedDistanceToLine(verts[1], verts[2], texel_pos));
|
sd = glm::min(sd, SignedDistanceToLine(verts[1], verts[2], texel_pos));
|
||||||
sd = glm::min(sd, SignedDistanceToLine(verts[2], verts[0], texel_pos));
|
sd = glm::min(sd, SignedDistanceToLine(verts[2], verts[0], texel_pos));
|
||||||
|
|
||||||
if (sd > margin)
|
if (sd > margin)
|
||||||
{
|
{
|
||||||
continue; // Texel is outside the triangle
|
continue; // Texel is outside the triangle even with margin
|
||||||
}
|
}
|
||||||
|
|
||||||
texel.used = sd < 0.0f;
|
texel.inside = sd < 0.0f;
|
||||||
|
texel.used = true; // Mark as used, even if its in the margin area
|
||||||
|
|
||||||
// Compute barycentric coordinates
|
// Compute barycentric coordinates
|
||||||
glm::vec2 v0 = verts[1] - verts[0];
|
glm::vec2 v0 = verts[1] - verts[0];
|
||||||
@ -360,6 +553,7 @@ void game::Sector::BakeLightmap()
|
|||||||
float d20 = glm::dot(v2, v0);
|
float d20 = glm::dot(v2, v0);
|
||||||
float d21 = glm::dot(v2, v1);
|
float d21 = glm::dot(v2, v1);
|
||||||
float denom = d00 * d11 - d01 * d01;
|
float denom = d00 * d11 - d01 * d01;
|
||||||
|
|
||||||
if (denom == 0.0f)
|
if (denom == 0.0f)
|
||||||
{
|
{
|
||||||
continue; // Degenerate triangle, skip
|
continue; // Degenerate triangle, skip
|
||||||
@ -374,7 +568,10 @@ void game::Sector::BakeLightmap()
|
|||||||
|
|
||||||
glm::vec3 light_color = ambient_light;
|
glm::vec3 light_color = ambient_light;
|
||||||
|
|
||||||
for (const Light& light : lights_)
|
lights.clear();
|
||||||
|
GetLightsAt(texel_pos_ws, lights);
|
||||||
|
|
||||||
|
for (const Light& light : lights)
|
||||||
{
|
{
|
||||||
glm::vec3 light_dir = glm::normalize(light.position - texel_pos_ws);
|
glm::vec3 light_dir = glm::normalize(light.position - texel_pos_ws);
|
||||||
float dot = glm::dot(texel_norm_ws, light_dir);
|
float dot = glm::dot(texel_norm_ws, light_dir);
|
||||||
@ -393,15 +590,66 @@ void game::Sector::BakeLightmap()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint8_t> lightmap_data(lightmap_size * lightmap_size * 3);
|
std::vector<uint8_t> lightmap_data(lightmap_size * lightmap_size * 3, 0);
|
||||||
for (size_t i = 0; i < lightmap.size(); ++i)
|
for (int y = 0; y < lightmap_size; ++y)
|
||||||
{
|
{
|
||||||
const LightmapTexel& texel = lightmap[i];
|
for (int x = 0; x < lightmap_size; ++x)
|
||||||
glm::vec3 color = glm::clamp(texel.color * 0.5f, glm::vec3(0.0f), glm::vec3(1.0f));
|
{
|
||||||
|
size_t i = y * lightmap_size + x;
|
||||||
|
|
||||||
|
glm::vec3 color(0.0f);
|
||||||
|
|
||||||
|
if (!lightmap[i].used)
|
||||||
|
{
|
||||||
|
// Not used texel, skip
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
float total_weight = 0.0f;
|
||||||
|
|
||||||
|
// Apply blur
|
||||||
|
for (int oy = -1; oy <= 1; ++oy)
|
||||||
|
{
|
||||||
|
for (int ox = -1; ox <= 1; ++ox)
|
||||||
|
{
|
||||||
|
int nx = x + ox;
|
||||||
|
int ny = y + oy;
|
||||||
|
if (nx < 0 || nx >= lightmap_size || ny < 0 || ny >= lightmap_size)
|
||||||
|
{
|
||||||
|
continue; // Out of bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t ni = ny * lightmap_size + nx;
|
||||||
|
|
||||||
|
const LightmapTexel& texel = lightmap[ni];
|
||||||
|
|
||||||
|
if (!texel.used)
|
||||||
|
{
|
||||||
|
continue; // Not used texel
|
||||||
|
}
|
||||||
|
|
||||||
|
float weight = 1.0f;
|
||||||
|
if (ox != 0 || oy != 0)
|
||||||
|
{
|
||||||
|
weight = (glm::abs(ox) + glm::abs(oy) == 1) ? 0.5f : 0.25f; // 0.5 for neighbors, 0.25 for corners
|
||||||
|
}
|
||||||
|
|
||||||
|
color += texel.color * weight;
|
||||||
|
total_weight += weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
color /= total_weight;
|
||||||
|
|
||||||
|
// Multiply by 0.5 - shader will multiply by 2.0 to make it possible to store higher values
|
||||||
|
color = glm::clamp(color * 0.5f, glm::vec3(0.0f), glm::vec3(1.0f));
|
||||||
|
|
||||||
lightmap_data[i * 3 + 0] = static_cast<uint8_t>(color.r * 255.0f);
|
lightmap_data[i * 3 + 0] = static_cast<uint8_t>(color.r * 255.0f);
|
||||||
lightmap_data[i * 3 + 1] = static_cast<uint8_t>(color.g * 255.0f);
|
lightmap_data[i * 3 + 1] = static_cast<uint8_t>(color.g * 255.0f);
|
||||||
lightmap_data[i * 3 + 2] = static_cast<uint8_t>(color.b * 255.0f);
|
lightmap_data[i * 3 + 2] = static_cast<uint8_t>(color.b * 255.0f);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
lightmap_ = std::make_shared<gfx::Texture>(
|
lightmap_ = std::make_shared<gfx::Texture>(
|
||||||
|
|||||||
@ -58,6 +58,8 @@ namespace game
|
|||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
glm::vec3 color;
|
glm::vec3 color;
|
||||||
float radius;
|
float radius;
|
||||||
|
|
||||||
|
const Portal* through_portal;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Sector
|
class Sector
|
||||||
@ -68,7 +70,9 @@ namespace game
|
|||||||
|
|
||||||
std::shared_ptr<assets::Mesh> mesh_;
|
std::shared_ptr<assets::Mesh> mesh_;
|
||||||
|
|
||||||
std::vector<Light> lights_;
|
std::vector<Light> lights_; // Light in this sector
|
||||||
|
std::vector<Light> all_lights_; // Lights in this sector and linked sectors
|
||||||
|
|
||||||
std::shared_ptr<gfx::Texture> lightmap_;
|
std::shared_ptr<gfx::Texture> lightmap_;
|
||||||
|
|
||||||
std::vector<Portal> portals_;
|
std::vector<Portal> portals_;
|
||||||
@ -94,6 +98,7 @@ namespace game
|
|||||||
size_t GetIndex() const { return idx_; }
|
size_t GetIndex() const { return idx_; }
|
||||||
const std::shared_ptr<assets::Mesh>& GetMesh() const { return mesh_; }
|
const std::shared_ptr<assets::Mesh>& GetMesh() const { return mesh_; }
|
||||||
const std::shared_ptr<gfx::Texture>& GetLightmap() const { return lightmap_; }
|
const std::shared_ptr<gfx::Texture>& GetLightmap() const { return lightmap_; }
|
||||||
|
btCollisionWorld& GetBtWorld() { return bt_world_; }
|
||||||
|
|
||||||
int GetPortalIndex(const std::string& name) const;
|
int GetPortalIndex(const std::string& name) const;
|
||||||
const Portal& GetPortal(size_t idx) const { return portals_[idx]; }
|
const Portal& GetPortal(size_t idx) const { return portals_[idx]; }
|
||||||
@ -111,6 +116,14 @@ namespace game
|
|||||||
|
|
||||||
const Portal* TestPortalContact(btCapsuleShapeZ& capsule, const glm::mat3& basis, const glm::vec3& pos);
|
const Portal* TestPortalContact(btCapsuleShapeZ& capsule, const glm::mat3& basis, const glm::vec3& pos);
|
||||||
|
|
||||||
|
static bool Raycast(const Sector*& sector, const glm::vec3& start, const glm::vec3& end, std::vector<const Portal*>* out_traversed_portals = nullptr);
|
||||||
|
|
||||||
|
void GetLightsAt(const glm::vec3& pos, std::vector<Light>& out_lights) const;
|
||||||
|
|
||||||
|
void Bake();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void GenerateAllLights();
|
||||||
void BakeLightmap();
|
void BakeLightmap();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,6 @@ void game::World::Bake()
|
|||||||
{
|
{
|
||||||
for (auto& sector : sectors_)
|
for (auto& sector : sectors_)
|
||||||
{
|
{
|
||||||
sector->BakeLightmap();
|
sector->Bake();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user