99 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			WebGPU Shading Language
		
	
	
	
	
	
			
		
		
	
	
			99 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			WebGPU Shading Language
		
	
	
	
	
	
| struct VertexInput {
 | |
|     @location(0) position: vec3f,
 | |
|     @location(1) texcoords: vec2f,
 | |
|     @location(2) normal: vec3f,
 | |
| }
 | |
| 
 | |
| struct VertexOutput {
 | |
|     @builtin(position) clipPosition: vec4f,
 | |
|     @location(0) position: vec3f,
 | |
|     @location(1) texcoords: vec2f,
 | |
|     @location(2) normal: vec3f,
 | |
| }
 | |
| 
 | |
| struct FragmentInput {
 | |
|     @location(0) position: vec3f,
 | |
|     @location(1) texcoords: vec2f,
 | |
|     @location(2) normal: vec3f,
 | |
| }
 | |
| 
 | |
| struct FragmentOutput {
 | |
|     @location(0) color: vec4f,
 | |
| }
 | |
| 
 | |
| struct CameraUniforms {
 | |
|     viewMatrix: mat4x4f,
 | |
|     projectionMatrix: mat4x4f,
 | |
|     cameraPosition: vec3f,
 | |
| }
 | |
| 
 | |
| struct ModelUniforms {
 | |
|     modelMatrix: mat4x4f,
 | |
|     normalMatrix: mat3x3f,
 | |
| }
 | |
| 
 | |
| struct MaterialUniforms {
 | |
|     baseFactor: vec4f,
 | |
|     specularFactor: f32,
 | |
|     shininess: f32,
 | |
| }
 | |
| 
 | |
| struct SpotLightUniforms {
 | |
|     position: vec3f,
 | |
|     direction: vec3f,
 | |
|     cutoffAngle: f32,
 | |
|     ambient: f32,
 | |
|     intensity: f32,
 | |
| }
 | |
| 
 | |
| @group(0) @binding(0) var<uniform> camera: CameraUniforms;
 | |
| @group(1) @binding(0) var<uniform> model: ModelUniforms;
 | |
| @group(2) @binding(0) var<uniform> material: MaterialUniforms;
 | |
| @group(2) @binding(1) var baseTexture: texture_2d<f32>;
 | |
| @group(2) @binding(2) var baseSampler: sampler;
 | |
| @group(3) @binding(0) var<uniform> spotLight: SpotLightUniforms;
 | |
| 
 | |
| @vertex
 | |
| fn vertex(input: VertexInput) -> VertexOutput {
 | |
|     var output: VertexOutput;
 | |
| 
 | |
|     output.clipPosition = camera.projectionMatrix * camera.viewMatrix * model.modelMatrix * vec4(input.position, 1);
 | |
| 
 | |
|     output.position = (model.modelMatrix * vec4(input.position, 1)).xyz;
 | |
|     output.texcoords = input.texcoords;
 | |
|     output.normal = model.normalMatrix * input.normal;
 | |
| 
 | |
|     return output;
 | |
| }
 | |
| 
 | |
| @fragment
 | |
| fn fragment(input: FragmentInput) -> FragmentOutput {
 | |
|     var output: FragmentOutput;
 | |
| 
 | |
|     let N = normalize(input.normal);
 | |
|     let L = normalize(spotLight.position - input.position);
 | |
|     let V = normalize(camera.cameraPosition - input.position);
 | |
|     let H = normalize(L + V);
 | |
| 
 | |
|     // Spotlight factor based on cutoff angle
 | |
|     let lightDir = normalize(spotLight.direction);
 | |
|     let theta = dot(L, -lightDir);
 | |
|     let spotlightFactor = select(0.0, 1.0, theta > spotLight.cutoffAngle);
 | |
| 
 | |
|     // Diffuse and Specular components
 | |
|     let lambert = max(dot(N, L), 0) * spotlightFactor;
 | |
|     let specular = pow(max(dot(N, H), 0), material.shininess) * spotlightFactor;
 | |
| 
 | |
|     let materialColor = textureSample(baseTexture, baseSampler, input.texcoords) * material.baseFactor;
 | |
|     let lambertFactor = vec4(vec3(lambert), 1);
 | |
|     let specularFactor = vec4(vec3(specular * material.specularFactor), 1);
 | |
|     let ambientFactor = vec4(vec3(spotLight.ambient), 1);
 | |
| 
 | |
|     // Final color
 | |
| //    output.color = materialColor * ((lambertFactor + specularFactor) + specularFactor * spotLight.intensity);
 | |
| //    output.color = spotLight.intensity * (lambertFactor + specularFactor) + ambientFactor;
 | |
|     output.color = spotlightFactor * materialColor;
 | |
| 
 | |
|     return output;
 | |
| }
 |