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:
+2
-2
@@ -25,9 +25,9 @@ compile() {
|
||||
fi
|
||||
}
|
||||
|
||||
for name in scene terrain; do
|
||||
for name in scene terrain object; do
|
||||
compile "$DIR/$name.vert" "$OUT/$name.vert.spv"
|
||||
compile "$DIR/$name.frag" "$OUT/$name.frag.spv"
|
||||
done
|
||||
|
||||
echo "wrote $OUT/{scene,terrain}.{vert,frag}.spv"
|
||||
echo "wrote $OUT/{scene,terrain,object}.{vert,frag}.spv"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,36 @@
|
||||
#version 450
|
||||
|
||||
// Static-map model fragment stage: sample the shared texture array and apply
|
||||
// the same directional sun the terrain uses. Cut-out props (trees, fences)
|
||||
// carry an alpha mask in their diffuse texture; discard the transparent texels
|
||||
// so the ground shows through.
|
||||
|
||||
layout(binding = 0) uniform sampler2DArray atlas;
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
vec4 cam_pos;
|
||||
vec4 fwd;
|
||||
vec4 right;
|
||||
vec4 up;
|
||||
vec4 sun;
|
||||
} pc;
|
||||
|
||||
layout(location = 0) in vec2 in_uv;
|
||||
layout(location = 1) in vec3 in_normal;
|
||||
layout(location = 2) flat in float in_layer;
|
||||
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
void main() {
|
||||
int layers = textureSize(atlas, 0).z;
|
||||
int layer = clamp(int(in_layer + 0.5), 0, layers - 1);
|
||||
vec4 tex = texture(atlas, vec3(in_uv, float(layer)));
|
||||
if (tex.a < 0.5) discard;
|
||||
|
||||
vec3 n = normalize(in_normal);
|
||||
if (!gl_FrontFacing) n = -n;
|
||||
float lambert = max(0.0, dot(n, normalize(pc.sun.xyz)));
|
||||
float ambient = pc.sun.w;
|
||||
vec3 lit = tex.rgb * (ambient + (1.0 - ambient) * lambert);
|
||||
out_color = vec4(lit, 1.0);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#version 450
|
||||
|
||||
// Static-map model vertex stage. Draws the world-space triangle soup built by
|
||||
// ra3::models (buildings and props the map places) against the exact camera the
|
||||
// terrain raymarcher uses, so both passes share one projection and depth test.
|
||||
//
|
||||
// The camera is passed as its orthonormal basis so the same math as
|
||||
// terrain.frag applies: ndc.x = dot(r, right) / (a * tan(fov/2) * aspect),
|
||||
// ndc.y = -dot(r, up) / (a * tan(fov/2)), depth = (a - NEAR) / (FAR - NEAR)
|
||||
// with `a = dot(r, fwd)` the view-space depth.
|
||||
|
||||
layout(location = 0) in vec3 in_pos;
|
||||
layout(location = 1) in vec3 in_normal;
|
||||
layout(location = 2) in vec2 in_uv;
|
||||
layout(location = 3) in float in_layer;
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
vec4 cam_pos; // xyz = eye position
|
||||
vec4 fwd; // xyz = forward
|
||||
vec4 right; // xyz = right, w = tan(fov / 2)
|
||||
vec4 up; // xyz = up, w = tan(fov / 2) * aspect
|
||||
vec4 sun; // xyz = sun direction, w = ambient
|
||||
} pc;
|
||||
|
||||
layout(location = 0) out vec2 out_uv;
|
||||
layout(location = 1) out vec3 out_normal;
|
||||
layout(location = 2) flat out float out_layer;
|
||||
|
||||
const float NEAR = 10.0;
|
||||
const float FAR = 60000.0;
|
||||
|
||||
void main() {
|
||||
vec3 r = in_pos - pc.cam_pos.xyz;
|
||||
float a = dot(r, pc.fwd.xyz);
|
||||
float b = dot(r, pc.right.xyz);
|
||||
float c = dot(r, pc.up.xyz);
|
||||
float th = pc.right.w;
|
||||
float th_aspect = pc.up.w;
|
||||
float depth = clamp((a - NEAR) / (FAR - NEAR), 0.0, 1.0);
|
||||
gl_Position = vec4(b / th_aspect, -c / th, depth * a, a);
|
||||
out_uv = in_uv;
|
||||
out_normal = in_normal;
|
||||
out_layer = in_layer;
|
||||
}
|
||||
+11
-1
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user