matrix-engine-wgpu
Version:
Networking implemented - based on kurento openvidu server. fix arcball camera,instanced draws added also effect pipeline blend with instancing option.Normalmap added, Fixed shadows casting vs camera/video texture, webGPU powered pwa application. Crazy fas
161 lines (143 loc) • 6 kB
JavaScript
export let fragmentWGSLPower = `override shadowDepthTextureSize: f32 = 1024.0;
const PI: f32 = 3.141592653589793;
struct Scene {
lightViewProjMatrix : mat4x4f,
cameraViewProjMatrix : mat4x4f,
cameraPos : vec3f,
padding2 : f32,
lightPos : vec3f,
padding : f32,
globalAmbient : vec3f,
padding3 : f32,
};
struct SpotLight {
position : vec3f,
_pad1 : f32,
direction : vec3f,
_pad2 : f32,
innerCutoff : f32,
outerCutoff : f32,
intensity : f32,
_pad3 : f32,
color : vec3f,
_pad4 : f32,
range : f32,
ambientFactor : f32,
shadowBias : f32,
_pad5 : f32,
lightViewProj : mat4x4<f32>,
};
struct MaterialPBR {
baseColorFactor : vec4f,
metallicFactor : f32,
roughnessFactor : f32,
_pad1 : f32,
_pad2 : f32,
};
struct PBRMaterialData {
baseColor : vec3f,
metallic : f32,
roughness : f32,
};
const MAX_SPOTLIGHTS = 20u;
var<uniform> scene : Scene;
var shadowMapArray: texture_depth_2d_array;
var shadowSampler: sampler_comparison;
var meshTexture: texture_2d<f32>;
var meshSampler: sampler;
var<uniform> spotlights: array<SpotLight, MAX_SPOTLIGHTS>;
// PBR textures
var metallicRoughnessTex: texture_2d<f32>;
var metallicRoughnessSampler: sampler;
var<uniform> material: MaterialPBR;
struct FragmentInput {
shadowPos : vec4f,
fragPos : vec3f,
fragNorm : vec3f,
uv : vec2f,
};
fn getPBRMaterial(uv: vec2f) -> PBRMaterialData {
let texColor = textureSample(meshTexture, meshSampler, uv);
let baseColor = texColor.rgb * material.baseColorFactor.rgb;
let mrTex = textureSample(metallicRoughnessTex, metallicRoughnessSampler, uv);
let metallic = mrTex.b * material.metallicFactor;
let roughness = mrTex.g * material.roughnessFactor;
return PBRMaterialData(baseColor, metallic, roughness);
}
fn fresnelSchlick(cosTheta: f32, F0: vec3f) -> vec3f {
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
fn distributionGGX(N: vec3f, H: vec3f, roughness: f32) -> f32 {
let a = roughness * roughness;
let a2 = a * a;
let NdotH = max(dot(N, H), 0.0);
let NdotH2 = NdotH * NdotH;
let denom = (NdotH2 * (a2 - 1.0) + 1.0);
return a2 / (PI * denom * denom);
}
fn geometrySchlickGGX(NdotV: f32, roughness: f32) -> f32 {
let r = (roughness + 1.0);
let k = (r * r) / 8.0;
return NdotV / (NdotV * (1.0 - k) + k);
}
fn geometrySmith(N: vec3f, V: vec3f, L: vec3f, roughness: f32) -> f32 {
let NdotV = max(dot(N, V), 0.0);
let NdotL = max(dot(N, L), 0.0);
return geometrySchlickGGX(NdotV, roughness) * geometrySchlickGGX(NdotL, roughness);
}
fn calculateSpotlightFactor(light: SpotLight, fragPos: vec3f) -> f32 {
let L = normalize(light.position - fragPos);
let theta = dot(L, normalize(-light.direction));
let epsilon = light.innerCutoff - light.outerCutoff;
return clamp((theta - light.outerCutoff) / epsilon, 0.0, 1.0);
}
// PCF shadow sampling
fn sampleShadow(shadowUV: vec2f, layer: i32, depthRef: f32, normal: vec3f, lightDir: vec3f) -> f32 {
var visibility: f32 = 0.0;
let biasConstant: f32 = 0.001;
let slopeBias = max(0.002 * (1.0 - dot(normal, lightDir)), 0.0);
let bias = biasConstant + slopeBias;
let oneOverSize = 1.0 / (shadowDepthTextureSize * 0.5);
let offsets: array<vec2f, 9> = array<vec2f, 9>(
vec2(-1.0, -1.0), vec2(0.0, -1.0), vec2(1.0, -1.0),
vec2(-1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 0.0),
vec2(-1.0, 1.0), vec2(0.0, 1.0), vec2(1.0, 1.0)
);
for(var i: u32 = 0u; i < 9u; i = i + 1u) {
visibility += textureSampleCompare(shadowMapArray, shadowSampler, shadowUV + offsets[i] * oneOverSize, layer, depthRef - bias);
}
return visibility / 9.0;
}
fn main(input: FragmentInput) -> vec4f {
let materialData = getPBRMaterial(input.uv);
let N = normalize(input.fragNorm);
let V = normalize(scene.cameraPos - input.fragPos);
var Lo = vec3f(0.0);
for(var i: u32 = 0u; i < MAX_SPOTLIGHTS; i = i + 1u) {
let L = normalize(spotlights[i].position - input.fragPos);
let H = normalize(V + L);
let distance = length(spotlights[i].position - input.fragPos);
let attenuation = clamp(1.0 - (distance / spotlights[i].range), 0.0, 1.0);
let radiance = spotlights[i].color * spotlights[i].intensity * attenuation;
let NDF = distributionGGX(N, H, materialData.roughness);
let G = geometrySmith(N, V, L, materialData.roughness);
let F0 = mix(vec3f(0.04), materialData.baseColor, materialData.metallic);
let F = fresnelSchlick(max(dot(H, V), 0.0), F0);
let kS = F;
let kD = (vec3f(1.0) - kS) * (1.0 - materialData.metallic);
let diffuse = kD * materialData.baseColor / PI; // Lambertian diffuse // ??
let NdotL = max(dot(N, L), 0.0);
let specular = (NDF * G * F) / (4.0 * max(dot(N, V), 0.0) * NdotL + 0.001);
Lo += NdotL * spotlights[i].color * spotlights[i].intensity;
}
let ambient = scene.globalAmbient * materialData.baseColor;
var color = ambient + Lo;
return vec4f(color, 1.0);
}
`;
// let N = normalize(input.fragNorm);
// let L = normalize(spotlights[0].position - input.fragPos);
// let NdotL = max(dot(N,L),0.0);
// let radiance = spotlights[0].color * 10.0; // test high intensity
// Lo += materialData.baseColor * radiance * NdotL;