power_play/res/sh/material.hlsl
2025-07-16 17:44:46 -05:00

127 lines
4.0 KiB
HLSL

#include "sh/common.hlsl"
/* ========================== *
* Root signature
* ========================== */
#define ROOTSIG \
"RootConstants(num32BitConstants = 16, b0), " \
"DescriptorTable(SRV(t0, space = 0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE)), " \
"SRV(t0, space = 1), " \
"SRV(t0, space = 2), " \
\
"StaticSampler(s0, " \
"filter = FILTER_MIN_MAG_MIP_POINT, " \
"addressU = TEXTURE_ADDRESS_CLAMP, " \
"addressV = TEXTURE_ADDRESS_CLAMP, " \
"addressW = TEXTURE_ADDRESS_CLAMP, " \
"maxAnisotropy = 1)"
ConstantBuffer<struct sh_material_constants> g_constants : register(b0);
Texture2D g_textures[] : register(t0, space0);
StructuredBuffer<struct sh_material_instance> g_instances : register(t0, space1);
StructuredBuffer<struct sh_material_grid> g_grids : register(t0, space2);
SamplerState g_sampler : register(s0);
/* ========================== *
* Vertex shader
* ========================== */
struct vs_input {
DECLS(uint, SV_InstanceID);
DECLS(uint, SV_VertexID);
};
struct vs_output {
nointerpolation DECLS(int, tex_nurid);
nointerpolation DECLS(int, grid_id);
DECLS(float2, uv);
DECLS(float4, tint_lin);
DECLS(float4, emittance_lin);
DECLS(float4, SV_Position);
};
SH_ENTRY(ROOTSIG) struct vs_output vs(struct vs_input input)
{
static const float2 unit_quad_verts[4] = {
float2(-0.5f, -0.5f),
float2(0.5f, -0.5f),
float2(0.5f, 0.5f),
float2(-0.5f, 0.5f)
};
struct sh_material_instance instance = g_instances[input.SV_InstanceID];
float2 vert = unit_quad_verts[input.SV_VertexID];
float2 world_pos = mul(instance.xf, float3(vert, 1)).xy;
struct vs_output output;
output.SV_Position = mul(g_constants.projection, float4(world_pos, 0, 1));
output.tex_nurid = instance.tex_nurid;
output.grid_id = instance.grid_id;
output.uv = instance.uv0 + ((vert + 0.5) * (instance.uv1 - instance.uv0));
output.tint_lin = linear_from_srgb32(instance.tint_srgb);
output.emittance_lin = linear_from_srgb32(instance.emittance_srgb);
return output;
}
/* ========================== *
* Pixel shader
* ========================== */
struct ps_input {
struct vs_output vs;
};
struct ps_output {
DECLS(float4, SV_Target0); /* Albedo */
DECLS(float4, SV_Target1); /* Emittance */
};
SH_ENTRY(ROOTSIG) struct ps_output ps(struct ps_input input)
{
struct ps_output output;
float4 albedo = input.vs.tint_lin;
float4 emittance = input.vs.emittance_lin;
/* Texture */
if (input.vs.tex_nurid >= 0) {
albedo *= g_textures[NURID(input.vs.tex_nurid)].Sample(g_sampler, input.vs.uv);
}
/* Grid */
if (input.vs.grid_id >= 0) {
struct sh_material_grid grid = g_grids[input.vs.grid_id];
float2 grid_pos = input.vs.SV_Position.xy + grid.offset;
float half_thickness = grid.line_thickness / 2;
float spacing = grid.line_spacing;
uint color_srgb = grid.bg0_srgb;
float2 v = abs(round(grid_pos / spacing) * spacing - grid_pos);
float dist = min(v.x, v.y);
if (grid_pos.y <= half_thickness && grid_pos.y >= -half_thickness) {
color_srgb = grid.x_srgb;
} else if (grid_pos.x <= half_thickness && grid_pos.x >= -half_thickness) {
color_srgb = grid.y_srgb;
} else if (dist < half_thickness) {
color_srgb = grid.line_srgb;
} else {
bool checker = 0;
uint cell_x = (uint)(abs(grid_pos.x) / spacing) + (grid_pos.x < 0);
uint cell_y = (uint)(abs(grid_pos.y) / spacing) + (grid_pos.y < 0);
if (cell_x % 2 == 0) {
checker = cell_y % 2 == 0;
} else {
checker = cell_y % 2 == 1;
}
if (checker) {
color_srgb = grid.bg1_srgb;
}
}
albedo = linear_from_srgb32(color_srgb);
}
output.SV_Target0 = albedo;
output.SV_Target1 = emittance;
return output;
}