Fixed black tunnels
This commit is contained in:
@@ -642,16 +642,19 @@ door builder also adds a black occluder covering the doorway, childed to
|
||||
the grid node (it does NOT swing with the hinge) and tracked via
|
||||
`DoorComponent::occluder`; `DoorSystem` hides it while the door is fully
|
||||
closed so the player never sees the missing room interior through the
|
||||
opened doorway before the switch fires. Doors swinging TOWARDS the player
|
||||
get a flat box (`CellGridDoorOccluderBox` mesh) a few cm behind the closed
|
||||
leaf plane; doors swinging AWAY (`doorSwingReversed`) get an open-front
|
||||
tunnel mesh (`CellGridDoorOccluderTunnel_*`, shared per size) whose back
|
||||
panel sits behind the fully-open leaf sweep, with side/top/bottom walls
|
||||
flared 1 cm into the frame so no sliver of the void shows around the
|
||||
frame. The shared `CellGridDoorOccluderBlack` material keeps lighting
|
||||
ENABLED with all-black colours (diffuse/ambient/specular/emissive) —
|
||||
with lighting disabled RTSS ignores material colours and renders the pass
|
||||
white.
|
||||
opened doorway before the switch fires. Every scene-switch door gets the
|
||||
same open-front tunnel mesh (`CellGridDoorOccluderTunnel_*`, shared per
|
||||
size and side) on the VOID side of the doorway: door-local +Z points
|
||||
outward from the owning cell, where normal grids hide the missing room,
|
||||
while exteriorOnly grids hide their missing interior inward, so
|
||||
`CellGridSystem` passes `DoorBuildParams::occluderSide = -1` there (the
|
||||
builder default is +1; standalone doors keep it). The tunnel depth covers
|
||||
the fully-open leaf sweep, so the leaf stays visible whether it swings
|
||||
towards or away from the player, and the side/top/bottom walls flared
|
||||
1 cm into the frame keep the darkness hole-free. The shared
|
||||
`CellGridDoorOccluderBlack` material keeps lighting ENABLED with
|
||||
all-black colours (diffuse/ambient/specular/emissive) — with lighting
|
||||
disabled RTSS ignores material colours and renders the pass white.
|
||||
|
||||
New `CellGridComponent` fields (serialized in the scene JSON and exposed to
|
||||
Lua): `doorsEnabled`, `doorRectName`, `doorMeshName`, `doorUseMeshMaterial`,
|
||||
|
||||
@@ -770,16 +770,18 @@ switch via the toggle path). `DoorSystem` fires the switch — and the new
|
||||
`door_scene_switch` event (params `path`/`target`/`door_id`) — only when
|
||||
the leaf reaches `openAngle` (`setEditorApp()` wires the `EditorApp` call;
|
||||
without it only the event fires, which is what the headless test uses).
|
||||
The door builder creates the black occluder (shared unit-box mesh
|
||||
`CellGridDoorOccluderBox` + `CellGridDoorOccluderBlack` material),
|
||||
childed to the grid node so it does not swing, sized from the closed-leaf
|
||||
collider extents and pushed 2 cm behind the leaf plane; `DoorSystem`
|
||||
hides it while fully closed. Doors swinging AWAY from the player
|
||||
(`doorSwingReversed`) instead get an open-front tunnel mesh
|
||||
(`CellGridDoorOccluderTunnel_*`, shared per doorway size): the back panel
|
||||
sits behind the fully-open leaf sweep so the swinging leaf stays visible,
|
||||
and side/top/bottom walls flared 1 cm into the frame keep the darkness
|
||||
hole-free. The occluder material keeps lighting enabled with all-black
|
||||
The door builder creates the black occluder (open-front tunnel mesh
|
||||
`CellGridDoorOccluderTunnel_*`, shared per doorway size and side, +
|
||||
`CellGridDoorOccluderBlack` material), childed to the grid node so it
|
||||
does not swing. Every scene-switch door gets the same tunnel on the VOID
|
||||
side of the doorway — door-local +Z points outward from the owning cell
|
||||
(normal grids hide the missing room there); `CellGridSystem` passes
|
||||
`occluderSide = -1` for exteriorOnly grids, whose missing interior is
|
||||
inward. The back panel sits behind the fully-open leaf sweep so the
|
||||
swinging leaf stays visible for both swing directions, and
|
||||
side/top/bottom walls flared 1 cm into the frame keep the darkness
|
||||
hole-free; `DoorSystem` hides the occluder while fully closed. The
|
||||
occluder material keeps lighting enabled with all-black
|
||||
colours — an unlit pass renders white under RTSS (FFPColour defaults the
|
||||
output to white when no lighting SRS runs). Scene-switch doors never
|
||||
restore the persisted open state: `declareDoorDefaults()` resets their
|
||||
@@ -809,11 +811,14 @@ sub-millisecond while swings are real-time).
|
||||
sceneSwitchTarget})`. The existing loading cover hides the switch.
|
||||
- **Black occluder:** `buildDoorEntities()` (and the F2 standalone builder)
|
||||
additionally creates a black occluder entity childed to the door entity,
|
||||
for doors with a non-empty `sceneSwitchPath`. Doors swinging towards the
|
||||
player get a flat box sized to the doorway opening, placed a few cm
|
||||
behind the closed leaf plane; doors swinging away (`swingReversed`) get
|
||||
an open-front tunnel whose back panel sits behind the fully-open leaf
|
||||
sweep, with side/top/bottom walls closing the gaps around the frame.
|
||||
for doors with a non-empty `sceneSwitchPath`. All of them get the same
|
||||
open-front tunnel on the VOID side of the doorway
|
||||
(`DoorBuildParams::occluderSide`: +1 = door-local +Z, outward from the
|
||||
owning cell, the default; `CellGridSystem` passes -1 for exteriorOnly
|
||||
grids, whose missing interior is inward). The tunnel depth covers the
|
||||
fully-open leaf sweep, so the leaf stays visible whether it swings
|
||||
towards or away from the player, and side/top/bottom walls close the
|
||||
gaps around the frame.
|
||||
Its visibility follows the door state: hidden while fully closed, visible
|
||||
while open/swinging (visible flag toggled by `DoorSystem` from
|
||||
`currentAngle`), so the player never sees the missing room interior
|
||||
|
||||
@@ -70,12 +70,13 @@ struct DoorComponent {
|
||||
// reaches openAngle. Runtime only, set by ActuatorSystem.
|
||||
bool sceneSwitchPending = false;
|
||||
|
||||
// F1: black box covering the doorway of a scene-switch door,
|
||||
// created by the door builder a few cm behind the closed leaf plane
|
||||
// (an open-front tunnel behind the fully-open leaf sweep for doors
|
||||
// swinging away from the player); child of the grid node, so it
|
||||
// does NOT swing with the hinge. Hidden while the door is fully
|
||||
// closed. Runtime only.
|
||||
// F1: black open-front tunnel covering the doorway of a scene-switch
|
||||
// door, created by the door builder on the VOID side of the doorway
|
||||
// (door-local +Z outward from the owning cell; -Z for exteriorOnly
|
||||
// grids); its depth covers the fully-open leaf sweep, so the leaf
|
||||
// stays visible for both swing directions. Child of the grid node,
|
||||
// so it does NOT swing with the hinge. Hidden while the door is
|
||||
// fully closed. Runtime only.
|
||||
Ogre::Entity *occluder = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -482,18 +482,21 @@ struct SceneSwitchTestListener : public Ogre::FrameListener {
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* The exit door swings TOWARDS the player, so it
|
||||
* keeps the flat occluder box. */
|
||||
/* F1: every scene-switch door gets the void-side
|
||||
* tunnel occluder (depth covers the leaf sweep,
|
||||
* so both swing directions stay visible). */
|
||||
{
|
||||
const DoorComponent &d =
|
||||
findDoorById(exitDoorId)
|
||||
.get<DoorComponent>();
|
||||
if (!d.occluder ||
|
||||
d.occluder->getMesh()->getName() !=
|
||||
"CellGridDoorOccluderBox") {
|
||||
d.occluder->getMesh()
|
||||
->getName()
|
||||
.find("CellGridDoorOccluderTunnel") !=
|
||||
0) {
|
||||
failed = true;
|
||||
failReason =
|
||||
"F1 swing-towards door lost the flat occluder";
|
||||
"F1 exit door has no tunnel occluder";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,18 +374,21 @@ struct SceneSwitchTestListener : public Ogre::FrameListener {
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* The exit door swings TOWARDS the player, so it
|
||||
* keeps the flat occluder box. */
|
||||
/* F1: every scene-switch door gets the void-side
|
||||
* tunnel occluder (depth covers the leaf sweep,
|
||||
* so both swing directions stay visible). */
|
||||
{
|
||||
const DoorComponent &d =
|
||||
findDoorById(exitDoorId)
|
||||
.get<DoorComponent>();
|
||||
if (!d.occluder ||
|
||||
d.occluder->getMesh()->getName() !=
|
||||
"CellGridDoorOccluderBox") {
|
||||
d.occluder->getMesh()
|
||||
->getName()
|
||||
.find("CellGridDoorOccluderTunnel") !=
|
||||
0) {
|
||||
failed = true;
|
||||
failReason =
|
||||
"F1 swing-towards door lost the flat occluder";
|
||||
"F1 exit door has no tunnel occluder";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -406,9 +409,9 @@ struct SceneSwitchTestListener : public Ogre::FrameListener {
|
||||
if (!entityExists("x1"))
|
||||
break;
|
||||
/* F1: the return door swings AWAY from the player
|
||||
* (doorSwingReversed in demo_scene_b.json), so it
|
||||
* must have the deep tunnel occluder that keeps
|
||||
* the swinging leaf visible. */
|
||||
* (doorSwingReversed in demo_scene_b.json); the
|
||||
* void-side tunnel occluder covers the full leaf
|
||||
* sweep, so the swinging leaf stays visible. */
|
||||
{
|
||||
flecs::entity returnDoor =
|
||||
findDoorById(returnDoorId);
|
||||
|
||||
@@ -5065,6 +5065,11 @@ void CellGridSystem::buildDoorEntities(flecs::entity entity,
|
||||
!params.sceneSwitchPath.empty())
|
||||
params.doorId = grid.ensureGridUid() + ":" + key;
|
||||
params.edgeKey = key;
|
||||
/* F1: the occluder tunnel goes on the VOID side of the
|
||||
* doorway: door-local +Z points outward from the owning
|
||||
* cell, where normal grids hide the missing room; for
|
||||
* exteriorOnly grids the missing interior is inward (-Z). */
|
||||
params.occluderSide = grid.exteriorOnlyMode() ? -1.0f : 1.0f;
|
||||
params.friction = grid.friction;
|
||||
params.leafMeshName = leafMeshName;
|
||||
params.customMesh = usingCustomMesh;
|
||||
|
||||
@@ -16,24 +16,15 @@
|
||||
#include <OgrePass.h>
|
||||
#include <OgreManualObject.h>
|
||||
#include <OgreLogManager.h>
|
||||
#include <ProceduralBoxGenerator.h>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
/* F1: shared occluder resources: the flat unit box and the black
|
||||
* material. NOTE: the material must keep lighting ENABLED with
|
||||
* all-black colours - with lighting disabled RTSS ignores the material
|
||||
* colours (FFPColour defaults the pass output to white), which made the
|
||||
* occluder render white. */
|
||||
static void ensureOccluderResources(const Ogre::String &group)
|
||||
/* F1: the black occluder material. NOTE: the material must keep
|
||||
* lighting ENABLED with all-black colours - with lighting disabled RTSS
|
||||
* ignores the material colours (FFPColour defaults the pass output to
|
||||
* white), which made the occluder render white. */
|
||||
static void ensureOccluderMaterial(const Ogre::String &group)
|
||||
{
|
||||
if (Ogre::MeshManager::getSingleton()
|
||||
.getByName("CellGridDoorOccluderBox", group)
|
||||
.isNull()) {
|
||||
Procedural::BoxGenerator boxGen;
|
||||
boxGen.setSizeX(1.0f).setSizeY(1.0f).setSizeZ(1.0f);
|
||||
boxGen.realizeMesh("CellGridDoorOccluderBox", group);
|
||||
}
|
||||
if (Ogre::MaterialManager::getSingleton()
|
||||
.getByName("CellGridDoorOccluderBlack", group)
|
||||
.isNull()) {
|
||||
@@ -49,17 +40,18 @@ static void ensureOccluderResources(const Ogre::String &group)
|
||||
}
|
||||
}
|
||||
|
||||
/* F1: open-front black tunnel for scene-switch doors that swing AWAY
|
||||
* from the player (swingReversed): the back panel sits behind the
|
||||
* fully-open leaf sweep so the swinging leaf stays visible, and
|
||||
* side/top/bottom walls close the gaps around the frame so no sliver of
|
||||
* the ungenerated void shows. The coordinates are baked into the mesh
|
||||
* in hinge-local space (+X along the doorway from the hinge, +Z away
|
||||
* from the player), so the occluder node gets no position offset and no
|
||||
* scale. Meshes are shared between doors of equal size. */
|
||||
/* F1: open-front black tunnel for scene-switch doors, covering the
|
||||
* doorway on the void side (door-local Z times `side`): the back panel
|
||||
* sits behind the fully-open leaf sweep so the swinging leaf stays
|
||||
* visible whichever way it swings, and side/top/bottom walls close the
|
||||
* gaps around the frame so no sliver of the ungenerated void shows.
|
||||
* The coordinates are baked into the mesh in hinge-local space (+X
|
||||
* along the doorway from the hinge, the tunnel extending to `side` *
|
||||
* Z), so the occluder node gets no position offset and no scale.
|
||||
* Meshes are shared between doors of equal size and side. */
|
||||
static Ogre::String
|
||||
occluderTunnelMesh(const Ogre::Vector3 ¢er,
|
||||
const Ogre::Vector3 &halfExtents,
|
||||
const Ogre::Vector3 &halfExtents, float side,
|
||||
const Ogre::String &group)
|
||||
{
|
||||
const float hx = halfExtents.x;
|
||||
@@ -70,20 +62,20 @@ occluderTunnelMesh(const Ogre::Vector3 ¢er,
|
||||
* panel one leaf thickness plus a small margin behind that. */
|
||||
const float x0 = center.x - hx, x1 = center.x + hx;
|
||||
const float y0 = center.y - hy, y1 = center.y + hy;
|
||||
const float z0 = center.z + hz + 0.02f;
|
||||
const float z1 = z0 + x1 + hz * 2.0f + 0.05f;
|
||||
const float z0 = center.z + side * (hz + 0.02f);
|
||||
const float z1 = z0 + side * (x1 + hz * 2.0f + 0.05f);
|
||||
/* Flare the walls 1 cm INTO the frame/jamb: no gap at the
|
||||
* opening edges and no z-fighting with the jamb faces. */
|
||||
const float f = 0.01f;
|
||||
|
||||
char name[160];
|
||||
snprintf(name, sizeof(name),
|
||||
"CellGridDoorOccluderTunnel_%d_%d_%d_%d_%d_%d",
|
||||
"CellGridDoorOccluderTunnel_%d_%d_%d_%d_%d_%d_%d",
|
||||
(int)lroundf(center.x * 1000.0f),
|
||||
(int)lroundf(center.y * 1000.0f),
|
||||
(int)lroundf(center.z * 1000.0f),
|
||||
(int)lroundf(hx * 1000.0f), (int)lroundf(hy * 1000.0f),
|
||||
(int)lroundf(hz * 1000.0f));
|
||||
(int)lroundf(hz * 1000.0f), (int)side);
|
||||
if (!Ogre::MeshManager::getSingleton().getByName(name, group).isNull())
|
||||
return name;
|
||||
|
||||
@@ -108,10 +100,10 @@ occluderTunnelMesh(const Ogre::Vector3 ¢er,
|
||||
mo.triangle(base, base + 1, base + 2);
|
||||
mo.triangle(base, base + 2, base + 3);
|
||||
};
|
||||
/* Back panel (facing the player, -Z). */
|
||||
/* Back panel (facing the player, against the tunnel depth). */
|
||||
quad(Ogre::Vector3(x0f, y0f, z1), Ogre::Vector3(x1f, y0f, z1),
|
||||
Ogre::Vector3(x1f, y1f, z1), Ogre::Vector3(x0f, y1f, z1),
|
||||
Ogre::Vector3::NEGATIVE_UNIT_Z);
|
||||
Ogre::Vector3(0, 0, -side));
|
||||
/* Left / right walls (facing into the tunnel). */
|
||||
quad(Ogre::Vector3(x0f, y0f, z0), Ogre::Vector3(x0f, y1f, z0),
|
||||
Ogre::Vector3(x0f, y1f, z1), Ogre::Vector3(x0f, y0f, z1),
|
||||
@@ -284,39 +276,27 @@ flecs::entity DoorBuilder::build(flecs::world &world,
|
||||
|
||||
/* F1: scene-switch doors get a black occluder covering the
|
||||
* doorway, so the player never sees the missing room interior
|
||||
* through the opened doorway before the switch fires. Doors
|
||||
* swinging TOWARDS the player keep the flat box a few cm behind
|
||||
* the closed leaf plane; doors swinging AWAY (swingReversed) get
|
||||
* an open-front tunnel whose back panel sits behind the
|
||||
* fully-open leaf sweep, with side/top/bottom walls closing the
|
||||
* gaps around the frame. The node hangs off the PARENT node
|
||||
* (not the hinge), so it does not swing with the leaf; DoorSystem
|
||||
* toggles its visibility from the swing angle. */
|
||||
* through the opened doorway before the switch fires. All of
|
||||
* them get the same open-front tunnel on the VOID side of the
|
||||
* doorway (params.occluderSide: door-local +Z outward from the
|
||||
* owning cell, -Z for exteriorOnly grids whose missing interior
|
||||
* is inward); its depth covers the fully-open leaf sweep, so the
|
||||
* leaf stays visible whether it swings towards or away from the
|
||||
* player, and the side/top/bottom walls close the gaps around
|
||||
* the frame. The geometry is baked into the mesh in hinge-local
|
||||
* space and the node hangs off the PARENT node (not the hinge),
|
||||
* so it does not swing with the leaf; DoorSystem toggles its
|
||||
* visibility from the swing angle. */
|
||||
if (!door.sceneSwitchPath.empty()) {
|
||||
const Ogre::String group =
|
||||
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME;
|
||||
ensureOccluderResources(group);
|
||||
ensureOccluderMaterial(group);
|
||||
|
||||
Ogre::String meshName = "CellGridDoorOccluderBox";
|
||||
Ogre::Vector3 occScale(colliderHalfExtents.x * 2.0f,
|
||||
colliderHalfExtents.y * 2.0f,
|
||||
0.05f);
|
||||
Ogre::Vector3 occPos =
|
||||
hingePos +
|
||||
doorwayRot *
|
||||
(colliderCenter +
|
||||
Ogre::Vector3(0, 0,
|
||||
colliderHalfExtents.z +
|
||||
0.02f));
|
||||
if (params.swingReversed) {
|
||||
/* Swing-away door: deep tunnel occluder with the
|
||||
* geometry baked into the mesh (hinge-local). */
|
||||
meshName = occluderTunnelMesh(colliderCenter,
|
||||
colliderHalfExtents,
|
||||
group);
|
||||
occScale = Ogre::Vector3::UNIT_SCALE;
|
||||
occPos = hingePos;
|
||||
}
|
||||
Ogre::String meshName = occluderTunnelMesh(
|
||||
colliderCenter, colliderHalfExtents,
|
||||
params.occluderSide, group);
|
||||
Ogre::Vector3 occScale = Ogre::Vector3::UNIT_SCALE;
|
||||
Ogre::Vector3 occPos = hingePos;
|
||||
|
||||
Ogre::Entity *occEnt = nullptr;
|
||||
try {
|
||||
|
||||
@@ -18,10 +18,11 @@
|
||||
* leaf, DoorComponent, RigidBodyComponent static, ActuatorComponent)
|
||||
* ├── collider child (PhysicsColliderComponent box of the closed
|
||||
* │ leaf; disabled by DoorSystem while not fully closed)
|
||||
* └── occluder child (F1, scene-switch doors only: black box
|
||||
* behind the leaf plane - an open-front tunnel for doors
|
||||
* swinging away from the player -, node on the PARENT node so
|
||||
* it does not swing; DoorSystem toggles its visibility)
|
||||
* └── occluder child (F1, scene-switch doors only: open-front
|
||||
* black tunnel on the void side of the doorway - door-local
|
||||
* +Z normally, -Z for exteriorOnly grids -, node on the
|
||||
* PARENT node so it does not swing; DoorSystem toggles its
|
||||
* visibility)
|
||||
*
|
||||
* The builder also declares the F6 store defaults for persistent doors
|
||||
* (DoorSystem::declareDoorDefaults) and snaps a door that was left open
|
||||
@@ -40,6 +41,13 @@ struct DoorBuildParams {
|
||||
float openAngle = 100.0f; // degrees
|
||||
float openSpeed = 180.0f; // degrees per second
|
||||
bool swingReversed = false; // F3
|
||||
/* F1: side of the doorway the scene-switch occluder tunnel
|
||||
* extends to, in door-local Z: +1 = +Z (outward from the owning
|
||||
* cell - the default; the missing room/void is there), -1 = -Z
|
||||
* (exteriorOnly grids, whose missing interior is inward). The
|
||||
* tunnel depth covers the full leaf sweep, so either swing
|
||||
* direction stays visible. */
|
||||
float occluderSide = 1.0f;
|
||||
std::string actionName; // optional actuator action
|
||||
std::string sceneSwitchPath; // F1 (empty = normal swinging door)
|
||||
std::string sceneSwitchTarget;
|
||||
|
||||
Reference in New Issue
Block a user