100 lines
2.8 KiB
WebGPU Shading Language
100 lines
2.8 KiB
WebGPU Shading Language
struct Configuration {
|
|
viewProj: mat4x4f,
|
|
lightViewProj: mat4x4f,
|
|
lightPosition: vec4f,
|
|
eyePosition: vec4f,
|
|
};
|
|
|
|
@group(0) @binding(0) var<uniform> config: Configuration;
|
|
@group(0) @binding(1) var<storage> nodeMatrix: array<mat4x4f>;
|
|
@group(0) @binding(2) var linearSampler: sampler;
|
|
|
|
@group(1) @binding(0) var baseTexture: texture_2d<f32>;
|
|
@group(1) @binding(1) var emissionTexture: texture_2d<f32>;
|
|
|
|
/*
|
|
struct Imm {
|
|
nodeIndex: i32,
|
|
};
|
|
var<immediate> imm: Imm;
|
|
*/
|
|
|
|
struct VertexInput {
|
|
@location(0) position: vec3f,
|
|
@location(1) normal: vec3f,
|
|
@location(2) texture: vec2f,
|
|
@builtin(instance_index) instance: u32,
|
|
};
|
|
|
|
struct VertexOutput {
|
|
@builtin(position) position: vec4f,
|
|
@location(0) positionWorld: vec3f,
|
|
@location(1) normal: vec3f,
|
|
@location(2) texture: vec2f,
|
|
@location(3) lightPosition: vec3f,
|
|
@location(4) eyePosition: vec3f,
|
|
};
|
|
|
|
@vertex
|
|
fn vertexMain(input: VertexInput) -> VertexOutput
|
|
{
|
|
let position = nodeMatrix[input.instance] * vec4f(input.position, 1);
|
|
//let position = vec4f(input.position, 1);
|
|
let normal = vec4f(input.normal, 0.0f);
|
|
var output: VertexOutput;
|
|
output.position = config.viewProj * position;
|
|
output.positionWorld = (position).xyz;
|
|
output.normal = (normal).xyz;
|
|
output.texture = input.texture;
|
|
output.lightPosition = config.lightPosition.xyz;
|
|
output.eyePosition = config.eyePosition.xyz;
|
|
return output;
|
|
}
|
|
|
|
fn schlickFresnel(R0: vec3f, normal: vec3f, lightVector: vec3f) -> vec3f
|
|
{
|
|
let incidentAngle = saturate(dot(normal, lightVector));
|
|
|
|
let f0 = 1.0 - incidentAngle;
|
|
let reflectPercent = R0 + (1.0f - R0) * (f0 * f0 * f0 * f0 * f0);
|
|
|
|
return reflectPercent;
|
|
}
|
|
|
|
fn blinnPhong(ndotl: f32, lightVector: vec3f, normal: vec3f, toEye: vec3f) -> vec3f
|
|
{
|
|
let roughness = 0.1;
|
|
|
|
let m = roughness * 256.0;
|
|
let halfVec = normalize(toEye + lightVector);
|
|
let roughnessFactor = (m + 8.0) * pow(ndotl, m) / 8.0f;
|
|
|
|
let fresnelR0 = vec3f(0.95f, 0.95f, 0.95f);
|
|
let fresnelFactor = schlickFresnel(fresnelR0, normal, lightVector);
|
|
|
|
let specular = fresnelFactor * roughnessFactor;
|
|
|
|
return specular;
|
|
}
|
|
|
|
fn lighting(position: vec3f, lightPosition: vec3f, eyePosition: vec3f, normal: vec3f) -> vec3f
|
|
{
|
|
let lightVector = normalize(lightPosition - position);
|
|
let ndotl = max(dot(lightVector, normal), 0.0);
|
|
let intensity = (ndotl + 0.2) / 1.2;
|
|
|
|
let toEye = normalize(eyePosition - position);
|
|
|
|
return (1.0 + blinnPhong(ndotl, lightVector, normal, toEye)) * intensity;
|
|
}
|
|
|
|
@fragment
|
|
fn fragmentMain(input: VertexOutput) -> @location(0) vec4f
|
|
{
|
|
let intensity = lighting(input.positionWorld, input.lightPosition, input.eyePosition, normalize(input.normal));
|
|
let base = textureSample(baseTexture, linearSampler, input.texture);
|
|
let emission = textureSample(emissionTexture, linearSampler, input.texture);
|
|
|
|
return vec4(base.xyz * intensity + emission.xyz, 1.0);
|
|
}
|