aurora: Continue lights implementation

This commit is contained in:
Luke Street 2022-05-10 18:31:32 -04:00
parent 724deee2ab
commit 59cf0255bf
4 changed files with 84 additions and 107 deletions

View File

@ -70,7 +70,7 @@ struct ClipRect {
struct Light { struct Light {
zeus::CVector3f pos{0.f, 0.f, 0.f}; zeus::CVector3f pos{0.f, 0.f, 0.f};
zeus::CVector3f dir{0.f, 0.f, -1.f}; zeus::CVector3f dir{0.f, 0.f, -1.f};
zeus::CColor color{0.f, 0.f, 0.f, 0.f}; zeus::CColor color{0.f, 1.f};
zeus::CVector3f linAtt{1.f, 0.f, 0.f}; zeus::CVector3f linAtt{1.f, 0.f, 0.f};
zeus::CVector3f angAtt{1.f, 0.f, 0.f}; zeus::CVector3f angAtt{1.f, 0.f, 0.f};
}; };
@ -89,10 +89,6 @@ struct ScopedDebugGroup {
void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept; void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHandle& tex, float lod) noexcept;
void unbind_texture(GX::TexMapID id) noexcept; void unbind_texture(GX::TexMapID id) noexcept;
// TODO migrate to GX
void load_light(GX::LightID id, const Light& light) noexcept;
void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept;
void set_viewport(float left, float top, float width, float height, float znear, float zfar) noexcept; void set_viewport(float left, float top, float width, float height, float znear, float zfar) noexcept;
void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept; void set_scissor(uint32_t x, uint32_t y, uint32_t w, uint32_t h) noexcept;

View File

@ -92,19 +92,13 @@ void GXSetChanCtrl(GX::ChannelID id, bool lightingEnabled, GX::ColorSrc ambSrc,
Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id); Log.report(logvisor::Fatal, FMT_STRING("bad channel {}"), id);
unreachable(); unreachable();
} }
if (diffFn != GX::DF_NONE && diffFn != GX::DF_CLAMP) {
Log.report(logvisor::Fatal, FMT_STRING("unhandled diffuse fn {}"), diffFn);
unreachable();
}
if (attnFn != GX::AF_NONE && attnFn != GX::AF_SPOT) {
Log.report(logvisor::Fatal, FMT_STRING("unhandled attn fn {}"), attnFn);
unreachable();
}
u32 idx = id - GX::COLOR0A0; u32 idx = id - GX::COLOR0A0;
auto& chan = g_gxState.colorChannelConfig[idx]; auto& chan = g_gxState.colorChannelConfig[idx];
chan.lightingEnabled = lightingEnabled; chan.lightingEnabled = lightingEnabled;
chan.ambSrc = ambSrc; chan.ambSrc = ambSrc;
chan.matSrc = matSrc; chan.matSrc = matSrc;
chan.diffFn = diffFn;
chan.attnFn = attnFn;
g_gxState.colorChannelState[idx].lightState = lightState; g_gxState.colorChannelState[idx].lightState = lightState;
} }
void GXSetAlphaCompare(GX::Compare comp0, u8 ref0, GX::AlphaOp op, GX::Compare comp1, u8 ref1) noexcept { void GXSetAlphaCompare(GX::Compare comp0, u8 ref0, GX::AlphaOp op, GX::Compare comp1, u8 ref1) noexcept {
@ -361,37 +355,7 @@ void GXInitSpecularDirHA(GX::LightObj* light, float nx, float ny, float nz, floa
void GXInitLightColor(GX::LightObj* light, GX::Color col) { light->color = col; } void GXInitLightColor(GX::LightObj* light, GX::Color col) { light->color = col; }
void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id) { void GXLoadLightObjImm(const GX::LightObj* light, GX::LightID id) {
u32 idx = 0; u32 idx = std::log2<u32>(id);
switch (id) {
case GX::LIGHT0:
idx = 0;
break;
case GX::LIGHT1:
idx = 1;
break;
case GX::LIGHT2:
idx = 2;
break;
case GX::LIGHT3:
idx = 3;
break;
case GX::LIGHT4:
idx = 4;
break;
case GX::LIGHT5:
idx = 5;
break;
case GX::LIGHT6:
idx = 6;
break;
case GX::LIGHT7:
idx = 7;
break;
default:
idx = 0;
break;
}
aurora::gfx::Light realLight; aurora::gfx::Light realLight;
realLight.pos.assign(light->px, light->py, light->pz); realLight.pos.assign(light->px, light->py, light->pz);
realLight.dir.assign(light->nx, light->ny, light->nz); realLight.dir.assign(light->nx, light->ny, light->nz);
@ -442,11 +406,6 @@ void bind_texture(GX::TexMapID id, metaforce::EClampMode clamp, const TextureHan
} }
void unbind_texture(GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast<size_t>(id)].reset(); } void unbind_texture(GX::TexMapID id) noexcept { gx::g_gxState.textures[static_cast<size_t>(id)].reset(); }
void load_light(GX::LightID id, const Light& light) noexcept { gx::g_gxState.lights[std::log2<u32>(id)] = light; }
void load_light_ambient(GX::LightID id, const zeus::CColor& ambient) noexcept {
gx::g_gxState.lights[std::log2<u32>(id)] = ambient;
}
namespace gx { namespace gx {
using gpu::g_device; using gpu::g_device;
using gpu::g_graphicsConfig; using gpu::g_graphicsConfig;
@ -829,27 +788,21 @@ Range build_uniform(const ShaderInfo& info) noexcept {
buf.append(&g_gxState.colorChannelState[i].matColor, 16); buf.append(&g_gxState.colorChannelState[i].matColor, 16);
if (g_gxState.colorChannelConfig[i].lightingEnabled) { if (g_gxState.colorChannelConfig[i].lightingEnabled) {
zeus::CColor ambient = zeus::skClear;
int addedLights = 0; int addedLights = 0;
const auto& lightState = g_gxState.colorChannelState[i].lightState; const auto& lightState = g_gxState.colorChannelState[i].lightState;
for (int li = 0; li < lightState.size(); ++li) { for (int li = 0; li < lightState.size(); ++li) {
if (!lightState.test(li)) { if (!lightState.test(li)) {
continue; continue;
} }
const auto& variant = g_gxState.lights[li]; const auto& light = g_gxState.lights[li];
if (std::holds_alternative<zeus::CColor>(variant)) {
ambient += std::get<zeus::CColor>(variant);
} else if (std::holds_alternative<Light>(variant)) {
static_assert(sizeof(Light) == 80); static_assert(sizeof(Light) == 80);
buf.append(&std::get<Light>(variant), sizeof(Light)); buf.append(&light, sizeof(Light));
++addedLights; ++addedLights;
} }
}
constexpr Light emptyLight{}; constexpr Light emptyLight{};
for (int li = addedLights; li < GX::MaxLights; ++li) { for (int li = addedLights; li < GX::MaxLights; ++li) {
buf.append(&emptyLight, sizeof(Light)); buf.append(&emptyLight, sizeof(Light));
} }
buf.append(&ambient, 16);
} }
} }
for (int i = 0; i < info.sampledKColors.size(); ++i) { for (int i = 0; i < info.sampledKColors.size(); ++i) {

View File

@ -75,6 +75,8 @@ struct TextureBind {
struct ColorChannelConfig { struct ColorChannelConfig {
GX::ColorSrc matSrc = GX::SRC_REG; GX::ColorSrc matSrc = GX::SRC_REG;
GX::ColorSrc ambSrc = GX::SRC_REG; GX::ColorSrc ambSrc = GX::SRC_REG;
GX::DiffuseFn diffFn = GX::DF_NONE;
GX::AttnFn attnFn = GX::AF_NONE;
bool lightingEnabled = false; bool lightingEnabled = false;
u8 _p1 = 0; u8 _p1 = 0;
u8 _p2 = 0; u8 _p2 = 0;
@ -149,7 +151,7 @@ struct GXState {
std::array<zeus::CColor, GX::MAX_KCOLOR> kcolors; std::array<zeus::CColor, GX::MAX_KCOLOR> kcolors;
std::array<ColorChannelConfig, MaxColorChannels> colorChannelConfig; std::array<ColorChannelConfig, MaxColorChannels> colorChannelConfig;
std::array<ColorChannelState, MaxColorChannels> colorChannelState; std::array<ColorChannelState, MaxColorChannels> colorChannelState;
std::array<LightVariant, GX::MaxLights> lights; std::array<Light, GX::MaxLights> lights;
std::array<TevStage, MaxTevStages> tevStages; std::array<TevStage, MaxTevStages> tevStages;
std::array<TextureBind, MaxTextures> textures; std::array<TextureBind, MaxTextures> textures;
std::array<TexMtxVariant, MaxTexMtx> texMtxs; std::array<TexMtxVariant, MaxTexMtx> texMtxs;

View File

@ -548,7 +548,7 @@ ShaderInfo build_shader_info(const ShaderConfig& config) noexcept {
if (info.sampledColorChannels.test(i)) { if (info.sampledColorChannels.test(i)) {
info.uniformSize += 32; info.uniformSize += 32;
if (config.colorChannels[i].lightingEnabled) { if (config.colorChannels[i].lightingEnabled) {
info.uniformSize += (80 * GX::MaxLights) + 16; info.uniformSize += (80 * GX::MaxLights);
} }
} }
} }
@ -758,7 +758,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
"\n out.pos = ubuf.proj * vec4<f32>(mv_pos, 1.0);"), "\n out.pos = ubuf.proj * vec4<f32>(mv_pos, 1.0);"),
vtx_attr(config, GX::VA_POS), vtx_attr(config, GX::VA_NRM)); vtx_attr(config, GX::VA_POS), vtx_attr(config, GX::VA_NRM));
if constexpr (EnableNormalVisualization) { if constexpr (EnableNormalVisualization) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3<f32>;"), vtxOutIdx++); vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) nrm: vec3<f32>,"), vtxOutIdx++);
vtxXfrAttrsPre += "\n out.nrm = mv_nrm;"; vtxXfrAttrsPre += "\n out.nrm = mv_nrm;";
} }
@ -825,7 +825,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
} }
for (int i = 0; i < info.usesTevReg.size(); ++i) { for (int i = 0; i < info.usesTevReg.size(); ++i) {
if (info.usesTevReg.test(i)) { if (info.usesTevReg.test(i)) {
uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4<f32>;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n tevreg{}: vec4<f32>,"), i);
fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i); fragmentFnPre += fmt::format(FMT_STRING("\n var tevreg{0} = ubuf.tevreg{0};"), i);
} }
} }
@ -835,51 +835,77 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
continue; continue;
} }
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_amb: vec4<f32>;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_amb: vec4<f32>,"), i);
uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4<f32>;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n cc{0}_mat: vec4<f32>,"), i);
if (config.colorChannels[i].lightingEnabled) { const auto& cc = config.colorChannels[i];
if (cc.lightingEnabled) {
if (!addedLightStruct) { if (!addedLightStruct) {
uniformPre += uniformPre +=
"\n" "\n"
"struct Light {\n" "struct Light {\n"
" pos: vec3<f32>;\n" " pos: vec3<f32>,\n"
" dir: vec3<f32>;\n" " dir: vec3<f32>,\n"
" color: vec4<f32>;\n" " color: vec4<f32>,\n"
" lin_att: vec3<f32>;\n" " lin_att: vec3<f32>,\n"
" ang_att: vec3<f32>;\n" " ang_att: vec3<f32>,\n"
"};"; "};";
addedLightStruct = true; addedLightStruct = true;
} }
uniBufAttrs += fmt::format(FMT_STRING("\n lights{}: array<Light, {}>;"), i, GX::MaxLights); uniBufAttrs += fmt::format(FMT_STRING("\n lights{}: array<Light, {}>,"), i, GX::MaxLights);
uniBufAttrs += fmt::format(FMT_STRING("\n lighting_ambient{}: vec4<f32>;"), i); vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>,"), vtxOutIdx++, i);
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), vtxOutIdx++, i); std::string ambSrc, matSrc, lightAttnFn, lightDiffFn;
if (cc.ambSrc == GX::SRC_VTX) {
ambSrc = vtx_attr(config, static_cast<GX::Attr>(GX::VA_CLR0 + i));
} else if (cc.ambSrc == GX::SRC_REG) {
ambSrc = fmt::format(FMT_STRING("ubuf.cc{0}_amb"), i);
}
if (cc.matSrc == GX::SRC_VTX) {
matSrc = vtx_attr(config, static_cast<GX::Attr>(GX::VA_CLR0 + i));
} else if (cc.matSrc == GX::SRC_REG) {
matSrc = fmt::format(FMT_STRING("ubuf.cc{0}_mat"), i);
}
GX::DiffuseFn diffFn = cc.diffFn;
if (cc.attnFn == GX::AF_NONE) {
lightAttnFn = "attn = 1.0;";
} else if (cc.attnFn == GX::AF_SPOT) {
lightAttnFn = fmt::format(FMT_STRING(R"""(
var cosine = max(0.0, dot(ldir, light.dir));
var cos_attn = dot(light.ang_att, vec3<f32>(1.0, cosine, cosine * cosine));
var dist_attn = dot(light.lin_att, vec3<f32>(1.0, dist, dist2));
attn = max(0.0, cos_attn / dist_attn);)"""));
} else if (cc.attnFn == GX::AF_SPEC) {
diffFn = GX::DF_NONE;
Log.report(logvisor::Fatal, FMT_STRING("AF_SPEC unimplemented"));
}
if (diffFn == GX::DF_NONE) {
lightDiffFn = "1.0";
} else if (diffFn == GX::DF_SIGN) {
lightDiffFn = "dot(ldir, mv_nrm)";
} else if (diffFn == GX::DF_CLAMP) {
lightDiffFn = "max(0.0, dot(ldir, mv_nrm))";
}
vtxXfrAttrs += fmt::format(FMT_STRING(R"""( vtxXfrAttrs += fmt::format(FMT_STRING(R"""(
{{ {{
var lighting = ubuf.lighting_ambient{0} + ubuf.cc{0}_amb; var lighting = {5};
for (var i = 0; i < {1}; i = i + 1) {{ for (var i = 0; i < {1}; i = i + 1) {{
var light = ubuf.lights{0}[i]; var light = ubuf.lights{0}[i];
var delta = mv_pos.xyz - light.pos; var ldir = light.pos - mv_pos;
var dist = length(delta); var dist2 = dot(ldir, ldir);
var delta_norm = delta / dist; var dist = sqrt(dist2);
var ang_dot = max(dot(delta_norm, light.dir), 0.0); ldir = ldir / dist;
var att = 1.0 / (light.lin_att.z * dist * dist + var attn: f32;{2}
light.lin_att.y * dist + var diff = {3};
light.lin_att.x); lighting = lighting + (attn * diff * light.color);
var ang_att = light.ang_att.z * ang_dot * ang_dot +
light.ang_att.y * ang_dot +
light.ang_att.x;
var this_color = light.color.xyz * ang_att * att * max(dot(-delta_norm, mv_nrm), 0.0);
lighting = lighting + vec4<f32>(this_color, 0.0);
}} }}
out.cc{0} = clamp(lighting, vec4<f32>(0.0), vec4<f32>(1.0)); out.cc{0} = {4} * clamp(lighting, vec4<f32>(0.0), vec4<f32>(1.0));
}})"""), }})"""),
i, GX::MaxLights); i, GX::MaxLights, lightAttnFn, lightDiffFn, matSrc, ambSrc);
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else if (config.colorChannels[i].matSrc == GX::SRC_VTX) { } else if (cc.matSrc == GX::SRC_VTX) {
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>;"), vtxOutIdx++, i); vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) cc{}: vec4<f32>,"), vtxOutIdx++, i);
vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = {};"), i, vtx_attr(config, GX::Attr(GX::VA_CLR0 + i))); vtxXfrAttrs += fmt::format(FMT_STRING("\n out.cc{} = {};"), i, vtx_attr(config, GX::Attr(GX::VA_CLR0 + i)));
fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i); fragmentFnPre += fmt::format(FMT_STRING("\n var rast{0} = in.cc{0};"), i);
} else { } else {
@ -888,7 +914,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
} }
for (int i = 0; i < info.sampledKColors.size(); ++i) { for (int i = 0; i < info.sampledKColors.size(); ++i) {
if (info.sampledKColors.test(i)) { if (info.sampledKColors.test(i)) {
uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4<f32>;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n kcolor{}: vec4<f32>,"), i);
} }
} }
size_t texBindIdx = 0; size_t texBindIdx = 0;
@ -897,7 +923,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
continue; continue;
} }
const auto& tcg = config.tcgs[i]; const auto& tcg = config.tcgs[i];
vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2<f32>;"), vtxOutIdx++, i); vtxOutAttrs += fmt::format(FMT_STRING("\n @location({}) tex{}_uv: vec2<f32>,"), vtxOutIdx++, i);
if (tcg.src >= GX::TG_TEX0 && tcg.src <= GX::TG_TEX7) { if (tcg.src >= GX::TG_TEX0 && tcg.src <= GX::TG_TEX7) {
vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>({}, 0.0, 1.0);"), i, vtxXfrAttrs += fmt::format(FMT_STRING("\n var tc{} = vec4<f32>({}, 0.0, 1.0);"), i,
vtx_attr(config, GX::Attr(GX::VA_TEX0 + (tcg.src - GX::TG_TEX0)))); vtx_attr(config, GX::Attr(GX::VA_TEX0 + (tcg.src - GX::TG_TEX0))));
@ -941,10 +967,10 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
if (info.usesTexMtx.test(i)) { if (info.usesTexMtx.test(i)) {
switch (info.texMtxTypes[i]) { switch (info.texMtxTypes[i]) {
case GX::TG_MTX2x4: case GX::TG_MTX2x4:
uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x2<f32>;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x2<f32>,"), i);
break; break;
case GX::TG_MTX3x4: case GX::TG_MTX3x4:
uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x3<f32>;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n texmtx{}: mat4x3<f32>,"), i);
break; break;
default: default:
Log.report(logvisor::Fatal, FMT_STRING("unhandled tex mtx type {}"), info.texMtxTypes[i]); Log.report(logvisor::Fatal, FMT_STRING("unhandled tex mtx type {}"), info.texMtxTypes[i]);
@ -954,20 +980,20 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
} }
for (int i = 0; i < info.usesPTTexMtx.size(); ++i) { for (int i = 0; i < info.usesPTTexMtx.size(); ++i) {
if (info.usesPTTexMtx.test(i)) { if (info.usesPTTexMtx.test(i)) {
uniBufAttrs += fmt::format(FMT_STRING("\n postmtx{}: mat4x3<f32>;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n postmtx{}: mat4x3<f32>,"), i);
} }
} }
if (info.usesFog) { if (info.usesFog) {
uniformPre += uniformPre +=
"\n" "\n"
"struct Fog {\n" "struct Fog {\n"
" color: vec4<f32>;\n" " color: vec4<f32>,\n"
" a: f32;\n" " a: f32,\n"
" b: f32;\n" " b: f32,\n"
" c: f32;\n" " c: f32,\n"
" pad: f32;\n" " pad: f32,\n"
"}"; "}";
uniBufAttrs += "\n fog: Fog;"; uniBufAttrs += "\n fog: Fog,";
fragmentFn += "\n var fogF = clamp((ubuf.fog.a / (ubuf.fog.b - in.pos.z)) - ubuf.fog.c, 0.0, 1.0);"; fragmentFn += "\n var fogF = clamp((ubuf.fog.a / (ubuf.fog.b - in.pos.z)) - ubuf.fog.c, 0.0, 1.0);";
switch (config.fogType) { switch (config.fogType) {
@ -1003,7 +1029,7 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
if (!info.sampledTextures.test(i)) { if (!info.sampledTextures.test(i)) {
continue; continue;
} }
uniBufAttrs += fmt::format(FMT_STRING("\n tex{}_lod: f32;"), i); uniBufAttrs += fmt::format(FMT_STRING("\n tex{}_lod: f32,"), i);
sampBindings += fmt::format(FMT_STRING("\n@group(1) @binding({})\n" sampBindings += fmt::format(FMT_STRING("\n@group(1) @binding({})\n"
"var tex{}_samp: sampler;"), "var tex{}_samp: sampler;"),
@ -1046,15 +1072,15 @@ wgpu::ShaderModule build_shader(const ShaderConfig& config, const ShaderInfo& in
const auto shaderSource = const auto shaderSource =
fmt::format(FMT_STRING(R"""({uniformPre} fmt::format(FMT_STRING(R"""({uniformPre}
struct Uniform {{ struct Uniform {{
pos_mtx: mat4x3<f32>; pos_mtx: mat4x3<f32>,
nrm_mtx: mat4x3<f32>; nrm_mtx: mat4x3<f32>,
proj: mat4x4<f32>;{uniBufAttrs} proj: mat4x4<f32>,{uniBufAttrs}
}}; }};
@group(0) @binding(0) @group(0) @binding(0)
var<uniform> ubuf: Uniform;{uniformBindings}{sampBindings}{texBindings} var<uniform> ubuf: Uniform;{uniformBindings}{sampBindings}{texBindings}
struct VertexOutput {{ struct VertexOutput {{
@builtin(position) pos: vec4<f32>;{vtxOutAttrs} @builtin(position) pos: vec4<f32>,{vtxOutAttrs}
}}; }};
@stage(vertex) @stage(vertex)