phase(N.5) Task 5: mesh_modern.vert + .frag — bindless + SSBO + indirect
New entity shaders for the WB modern rendering path. Modeled on WB's StaticObjectModern.* but adapted to acdream's lighting model: - Drops uActiveCells (we cull cells on CPU in WbDrawDispatcher) - Drops uDrawIDOffset (full passes, no pagination) - Drops uHighlightColor (deferred to Phase B.4 follow-up; field reserved in InstanceData struct comment) - Preserves mesh_instanced's SceneLighting UBO at binding=1 with 8 lights, fog params, lightning flash, per-channel clamp — full visual identity vert reads InstanceData[] @ binding=0 indexed by gl_BaseInstanceARB + gl_InstanceID for the per-entity model matrix; reads BatchData[] @ binding=1 indexed by gl_DrawIDARB for the per-group bindless texture handle + layer. frag samples sampler2DArray reconstructed from a uvec2 bindless handle + uint layer. uRenderPass uniform picks two-pass alpha-test thresholds: 0 = opaque (discard alpha<0.95), 1 = transparent (discard alpha>=0.95 and alpha<0.05). Not yet wired to the dispatcher — Task 6 sets up shader load + capability detection in GameWindow; Task 7-10 rewrite the dispatcher to use SSBO + glMultiDrawElementsIndirect. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6f90997a43
commit
aad2aa67da
2 changed files with 149 additions and 0 deletions
96
src/AcDream.App/Rendering/Shaders/mesh_modern.frag
Normal file
96
src/AcDream.App/Rendering/Shaders/mesh_modern.frag
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
#version 430 core
|
||||
#extension GL_ARB_bindless_texture : require
|
||||
|
||||
in vec3 vNormal;
|
||||
in vec2 vTexCoord;
|
||||
in vec3 vWorldPos;
|
||||
in flat uvec2 vTextureHandle;
|
||||
in flat uint vTextureLayer;
|
||||
|
||||
// 0 = opaque (discard alpha<0.95), 1 = transparent (discard alpha>=0.95)
|
||||
uniform int uRenderPass;
|
||||
|
||||
// SceneLighting UBO — IDENTICAL layout to mesh_instanced.frag binding=1.
|
||||
struct Light {
|
||||
vec4 posAndKind;
|
||||
vec4 dirAndRange;
|
||||
vec4 colorAndIntensity;
|
||||
vec4 coneAngleEtc;
|
||||
};
|
||||
layout(std140, binding = 1) uniform SceneLighting {
|
||||
Light uLights[8];
|
||||
vec4 uCellAmbient;
|
||||
vec4 uFogParams;
|
||||
vec4 uFogColor;
|
||||
vec4 uCameraAndTime;
|
||||
};
|
||||
|
||||
vec3 accumulateLights(vec3 N, vec3 worldPos) {
|
||||
vec3 lit = uCellAmbient.xyz;
|
||||
int activeLights = int(uCellAmbient.w);
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
if (i >= activeLights) break;
|
||||
int kind = int(uLights[i].posAndKind.w);
|
||||
vec3 Lcol = uLights[i].colorAndIntensity.xyz * uLights[i].colorAndIntensity.w;
|
||||
if (kind == 0) {
|
||||
vec3 Ldir = -uLights[i].dirAndRange.xyz;
|
||||
float ndl = max(0.0, dot(N, Ldir));
|
||||
lit += Lcol * ndl;
|
||||
} else {
|
||||
vec3 toL = uLights[i].posAndKind.xyz - worldPos;
|
||||
float d = length(toL);
|
||||
float range = uLights[i].dirAndRange.w;
|
||||
if (d < range && range > 1e-3) {
|
||||
vec3 Ldir = toL / max(d, 1e-4);
|
||||
float ndl = max(0.0, dot(N, Ldir));
|
||||
float atten = 1.0;
|
||||
if (kind == 2) {
|
||||
float cos_edge = cos(uLights[i].coneAngleEtc.x * 0.5);
|
||||
float cos_l = dot(-Ldir, uLights[i].dirAndRange.xyz);
|
||||
atten *= (cos_l > cos_edge) ? 1.0 : 0.0;
|
||||
}
|
||||
lit += Lcol * ndl * atten;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lit;
|
||||
}
|
||||
|
||||
vec3 applyFog(vec3 lit, vec3 worldPos) {
|
||||
int mode = int(uFogParams.w);
|
||||
if (mode == 0) return lit;
|
||||
float d = length(worldPos - uCameraAndTime.xyz);
|
||||
float fogStart = uFogParams.x;
|
||||
float fogEnd = uFogParams.y;
|
||||
float span = max(1e-3, fogEnd - fogStart);
|
||||
float fog = clamp((d - fogStart) / span, 0.0, 1.0);
|
||||
return mix(lit, uFogColor.xyz, fog);
|
||||
}
|
||||
|
||||
out vec4 FragColor;
|
||||
|
||||
void main() {
|
||||
sampler2DArray tex = sampler2DArray(vTextureHandle);
|
||||
vec4 color = texture(tex, vec3(vTexCoord, float(vTextureLayer)));
|
||||
|
||||
// Two-pass alpha-test (N.5 Decision 2).
|
||||
if (uRenderPass == 0) {
|
||||
if (color.a < 0.95) discard; // opaque pass
|
||||
} else {
|
||||
if (color.a >= 0.95) discard; // transparent pass
|
||||
if (color.a < 0.05) discard; // skip totally-empty
|
||||
}
|
||||
|
||||
vec3 N = normalize(vNormal);
|
||||
vec3 lit = accumulateLights(N, vWorldPos);
|
||||
|
||||
// Lightning flash — additive scene bump (matches mesh_instanced.frag).
|
||||
lit += uFogParams.z * vec3(0.6, 0.6, 0.75);
|
||||
|
||||
// Retail clamp per-channel to 1.0 (r13 §13.1).
|
||||
lit = min(lit, vec3(1.0));
|
||||
|
||||
vec3 rgb = color.rgb * lit;
|
||||
rgb = applyFog(rgb, vWorldPos);
|
||||
FragColor = vec4(rgb, color.a);
|
||||
}
|
||||
53
src/AcDream.App/Rendering/Shaders/mesh_modern.vert
Normal file
53
src/AcDream.App/Rendering/Shaders/mesh_modern.vert
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
#version 430 core
|
||||
#extension GL_ARB_bindless_texture : require
|
||||
#extension GL_ARB_shader_draw_parameters : require
|
||||
|
||||
layout(location = 0) in vec3 aPosition;
|
||||
layout(location = 1) in vec3 aNormal;
|
||||
layout(location = 2) in vec2 aTexCoord;
|
||||
|
||||
struct InstanceData {
|
||||
mat4 transform;
|
||||
// Reserved for Phase B.4 follow-up (selection-blink retail-faithful
|
||||
// highlight): vec4 highlightColor; — extend stride here, increase the
|
||||
// _instanceSsbo upload size in WbDrawDispatcher, add a flat varying out,
|
||||
// and consume in mesh_modern.frag.
|
||||
};
|
||||
|
||||
struct BatchData {
|
||||
uvec2 textureHandle; // bindless handle for sampler2DArray
|
||||
uint textureLayer; // layer index (always 0 for per-instance composites)
|
||||
uint flags; // reserved
|
||||
};
|
||||
|
||||
layout(std430, binding = 0) readonly buffer InstanceBuffer {
|
||||
InstanceData Instances[];
|
||||
};
|
||||
|
||||
layout(std430, binding = 1) readonly buffer BatchBuffer {
|
||||
BatchData Batches[];
|
||||
};
|
||||
|
||||
uniform mat4 uViewProjection;
|
||||
|
||||
out vec3 vNormal;
|
||||
out vec2 vTexCoord;
|
||||
out vec3 vWorldPos;
|
||||
out flat uvec2 vTextureHandle;
|
||||
out flat uint vTextureLayer;
|
||||
|
||||
void main() {
|
||||
int instanceIndex = gl_BaseInstanceARB + gl_InstanceID;
|
||||
mat4 model = Instances[instanceIndex].transform;
|
||||
|
||||
vec4 worldPos = model * vec4(aPosition, 1.0);
|
||||
gl_Position = uViewProjection * worldPos;
|
||||
|
||||
vWorldPos = worldPos.xyz;
|
||||
vNormal = normalize(mat3(model) * aNormal);
|
||||
vTexCoord = aTexCoord;
|
||||
|
||||
BatchData b = Batches[gl_DrawIDARB];
|
||||
vTextureHandle = b.textureHandle;
|
||||
vTextureLayer = b.textureLayer;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue