render map objects: decode compiled W3DMesh art, skin and draw over terrain

Read the buildings and props a map places from its compiled art (the
uncompressed worldbuilder stream + embedded DDS textures):

- ra3.models: BAB asset-stream parser (lazy slices), W3DMesh + D3DHierarchy
  decode, DDS (DXT1/3/5 + uncompressed) decode, per-mesh bone remap and
  bind-pose single-joint skinning, flattened to one world-space triangle soup.
- ra3.map: parse the ObjectsList chunk into (type, x, y, z, angle).
- ra3.terrain: render3d rasterises the scene over the raymarched terrain with
  a z-buffer; gpu_terrain carries the scene for the GPU backends.
- ra3.vulkan: second pipeline + depth attachment, terrain.frag writes
  gl_FragDepth, and a small depth bias keeps ground decals from z-fighting.
- objects.fx shaders (compiled to SPIR-V), embedded like scene/terrain.

Only opaque parts are drawn: FX-light billboards (DefaultW3D.fx / BasicW3D.fx)
and damage-fill shells (BuildingsGenericDamageFill.fx) are skipped, since the
latter paint the wrecked interior (e.g. orange CBBuilding_Wood) over the shell.

Ground-decal meshes with no diffuse role and the Road templates themselves are
still not drawn.
This commit is contained in:
EnderTheCoder
2026-09-29 18:08:11 +08:00
parent 6e5df350c7
commit 70f35d8382
18 changed files with 2027 additions and 45 deletions
+11 -1
View File
@@ -25,6 +25,11 @@ layout(location = 0) out vec4 out_color;
const float CELL = 10.0; // must match ra3::terrain::cell_size
// Must match object.vert: the shared projection writes the view-space depth
// into gl_FragDepth so the static-map models depth-test against the terrain.
const float NEAR = 10.0;
const float FAR = 60000.0;
float height_at(ivec2 c) {
c = clamp(c, ivec2(0), ivec2(pc.mapinfo.xy) - 1);
return texelFetch(heightmap, c, 0).r * 65535.0 * pc.mapinfo.w;
@@ -112,6 +117,7 @@ void main() {
vec3 dir = normalize(fwd + right * ndc.x * th * aspect + up * ndc.y * th);
if (dir.z >= -1e-4) {
gl_FragDepth = 1.0;
out_color = vec4(sky_color(dir), 1.0);
return;
}
@@ -133,7 +139,7 @@ void main() {
if (w.z <= world_height(w.x, w.y)) { hit = true; hit_t = t; break; }
prev = t; dt *= 1.10; t += dt;
}
if (!hit) { out_color = vec4(sky_color(dir), 1.0); return; }
if (!hit) { gl_FragDepth = 1.0; out_color = vec4(sky_color(dir), 1.0); return; }
float lo = prev, hi = hit_t;
for (int i = 0; i < 6; ++i) {
@@ -144,6 +150,10 @@ void main() {
}
vec3 hitpos = cam + dir * hi;
// View-space depth of the hit (project onto the forward axis), matching the
// projection object.vert applies to the model vertices.
gl_FragDepth = clamp((dot(hitpos - cam, fwd) - NEAR) / (FAR - NEAR), 0.0, 1.0);
vec3 sun = normalize(pc.sun.xyz);
float ambient = pc.sun.w;