struct SkyOutput { @builtin(position) position: vec4, @location(0) sampledir: vec3, }; struct Data { // from camera to screen proj: mat4x4, // from screen to camera proj_inv: mat4x4, // from world to camera view: mat4x4, // camera position cam_pos: vec4, }; @group(0) @binding(0) var r_data: Data; @vertex fn vs_sky(@builtin(vertex_index) vertex_index: u32) -> SkyOutput { // hacky way to draw a large triangle let tmp1 = i32(vertex_index) / 2; let tmp2 = i32(vertex_index) & 1; let pos = vec4( f32(tmp1) * 4.0 - 1.0, f32(tmp2) * 4.0 - 1.0, 1.0, 1.0 ); // transposition = inversion for this orthonormal matrix let inv_model_view = transpose(mat3x3(r_data.view[0].xyz, r_data.view[1].xyz, r_data.view[2].xyz)); let unprojected = r_data.proj_inv * pos; var result: SkyOutput; result.sampledir = inv_model_view * unprojected.xyz; result.position = pos; return result; } struct GroundOutput { @builtin(position) position: vec4, @location(4) pos: vec3, }; @vertex fn vs_ground(@builtin(vertex_index) vertex_index: u32) -> GroundOutput { // hacky way to draw two triangles that make a square let tmp1 = i32(vertex_index)/2-i32(vertex_index)/3; let tmp2 = i32(vertex_index)&1; let pos = vec3( f32(tmp1) * 2.0 - 1.0, 0.0, f32(tmp2) * 2.0 - 1.0 ) * 160.0; var result: GroundOutput; result.pos = pos; result.position = r_data.proj * r_data.view * vec4(pos, 1.0); return result; } struct EntityOutput { @builtin(position) position: vec4, @location(1) normal: vec3, @location(3) view: vec3, }; struct EntityTransform { matrix3: mat3x3, translation: vec3, }; @group(0) @binding(3) var r_EntityTransforms: array; @vertex fn vs_entity( @builtin(instance_index) instance_index: u32, @location(0) pos: vec3, @location(1) normal: vec3, ) -> EntityOutput { var position: vec3 = r_EntityTransforms[instance_index].matrix3 * pos+r_EntityTransforms[instance_index].translation; var result: EntityOutput; result.normal = r_EntityTransforms[instance_index].matrix3 * normal; result.view = position - r_data.cam_pos.xyz; result.position = r_data.proj * r_data.view * vec4(position, 1.0); return result; } @group(0) @binding(1) var r_texture: texture_cube; @group(0) @binding(2) var r_sampler: sampler; @fragment fn fs_sky(vertex: SkyOutput) -> @location(0) vec4 { return textureSample(r_texture, r_sampler, vertex.sampledir); } @fragment fn fs_entity(vertex: EntityOutput) -> @location(0) vec4 { let incident = normalize(vertex.view); let normal = normalize(vertex.normal); let reflected = incident - 2.0 * dot(normal, incident) * normal; let reflected_color = textureSample(r_texture, r_sampler, reflected).rgb; return vec4(vec3(0.1) + 0.5 * reflected_color, 1.0); } fn modulo_euclidean (a: f32, b: f32) -> f32 { var m = a % b; if (m < 0.0) { if (b < 0.0) { m -= b; } else { m += b; } } return m; } @fragment fn fs_ground(vertex: GroundOutput) -> @location(0) vec4 { let dir = vec3(-1.0)+vec3(modulo_euclidean(vertex.pos.x/16.,1.0),0.0,modulo_euclidean(vertex.pos.z/16.,1.0))*2.0; return vec4(textureSample(r_texture, r_sampler, dir).rgb, 1.0); }