Harbor

branch main
showing the latest snapshot on main
pbr.luma 1.4 KB · Plain text
gpu/shader/examples/pbr.luma 0644 Raw
-- PBR fragment shader
-- Demonstrates: multiple uniforms, texture sampling, math builtins

struct FragInput
	@location(0) uv: vec2
	@location(1) normal: vec3
	@location(2) world_pos: vec3
end

struct FragOutput
	@location(0) color: vec4
end

struct Material
	base_color: vec3
	roughness: float
	metallic: float
end

struct Light
	position: vec3
	color: vec3
	intensity: float
end

@group(0) @binding(0)
uniform material: Material

@group(0) @binding(1)
uniform light: Light

@group(1) @binding(0)
uniform albedo_map: sampler2D

const PI = 3.14159265

-- Helper: Schlick Fresnel approximation
function fresnel_schlick(cos_theta: float, f0: vec3) -> vec3
	return f0 + (vec3(1.0, 1.0, 1.0) - f0) * pow(1.0 - cos_theta, 5.0)
end

@entry(fragment)
function main(input: FragInput) -> FragOutput
	let n = normalize(input.normal)
	let v = normalize(-input.world_pos)
	let l = normalize(light.position - input.world_pos)
	let h = normalize(v + l)

	let albedo = sample(albedo_map, input.uv).rgb * material.base_color
	let ndotl = max(dot(n, l), 0.0)
	let ndoth = max(dot(n, h), 0.0)

	let f0 = mix(vec3(0.04, 0.04, 0.04), albedo, material.metallic)
	let f = fresnel_schlick(max(dot(h, v), 0.0), f0)

	let diffuse = albedo * (1.0 - material.metallic)
	let specular = f * pow(ndoth, (1.0 - material.roughness) * 256.0)

	let result = (diffuse + specular) * light.color * light.intensity * ndotl

	return FragOutput {
		color = vec4(result, 1.0),
	}
end