 dd14f3a477
			
		
	
	
		dd14f3a477
		
			
		
	
	
	
	
		
			
			 # Objective Lightmaps, textures that store baked global illumination, have been a mainstay of real-time graphics for decades. Bevy currently has no support for them, so this pull request implements them. ## Solution The new `Lightmap` component can be attached to any entity that contains a `Handle<Mesh>` and a `StandardMaterial`. When present, it will be applied in the PBR shader. Because multiple lightmaps are frequently packed into atlases, each lightmap may have its own UV boundaries within its texture. An `exposure` field is also provided, to control the brightness of the lightmap. Note that this PR doesn't provide any way to bake the lightmaps. That can be done with [The Lightmapper] or another solution, such as Unity's Bakery. --- ## Changelog ### Added * A new component, `Lightmap`, is available, for baked global illumination. If your mesh has a second UV channel (UV1), and you attach this component to the entity with that mesh, Bevy will apply the texture referenced in the lightmap. [The Lightmapper]: https://github.com/Naxela/The_Lightmapper --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com>
		
			
				
	
	
		
			115 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			WebGPU Shading Language
		
	
	
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			WebGPU Shading Language
		
	
	
	
	
	
| #import bevy_pbr::{
 | |
|     mesh_functions,
 | |
|     skinning,
 | |
|     morph::morph,
 | |
|     forward_io::{Vertex, VertexOutput},
 | |
|     view_transformations::position_world_to_clip,
 | |
| }
 | |
| #import bevy_render::instance_index::get_instance_index
 | |
| 
 | |
| #ifdef MORPH_TARGETS
 | |
| fn morph_vertex(vertex_in: Vertex) -> Vertex {
 | |
|     var vertex = vertex_in;
 | |
|     let weight_count = bevy_pbr::morph::layer_count();
 | |
|     for (var i: u32 = 0u; i < weight_count; i ++) {
 | |
|         let weight = bevy_pbr::morph::weight_at(i);
 | |
|         if weight == 0.0 {
 | |
|             continue;
 | |
|         }
 | |
|         vertex.position += weight * morph(vertex.index, bevy_pbr::morph::position_offset, i);
 | |
| #ifdef VERTEX_NORMALS
 | |
|         vertex.normal += weight * morph(vertex.index, bevy_pbr::morph::normal_offset, i);
 | |
| #endif
 | |
| #ifdef VERTEX_TANGENTS
 | |
|         vertex.tangent += vec4(weight * morph(vertex.index, bevy_pbr::morph::tangent_offset, i), 0.0);
 | |
| #endif
 | |
|     }
 | |
|     return vertex;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| @vertex
 | |
| fn vertex(vertex_no_morph: Vertex) -> VertexOutput {
 | |
|     var out: VertexOutput;
 | |
| 
 | |
| #ifdef MORPH_TARGETS
 | |
|     var vertex = morph_vertex(vertex_no_morph);
 | |
| #else
 | |
|     var vertex = vertex_no_morph;
 | |
| #endif
 | |
| 
 | |
| #ifdef SKINNED
 | |
|     var model = skinning::skin_model(vertex.joint_indices, vertex.joint_weights);
 | |
| #else
 | |
|     // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
 | |
|     // See https://github.com/gfx-rs/naga/issues/2416 .
 | |
|     var model = mesh_functions::get_model_matrix(vertex_no_morph.instance_index);
 | |
| #endif
 | |
| 
 | |
| #ifdef VERTEX_NORMALS
 | |
| #ifdef SKINNED
 | |
|     out.world_normal = skinning::skin_normals(model, vertex.normal);
 | |
| #else
 | |
|     out.world_normal = mesh_functions::mesh_normal_local_to_world(
 | |
|         vertex.normal,
 | |
|         // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
 | |
|         // See https://github.com/gfx-rs/naga/issues/2416
 | |
|         get_instance_index(vertex_no_morph.instance_index)
 | |
|     );
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
| #ifdef VERTEX_POSITIONS
 | |
|     out.world_position = mesh_functions::mesh_position_local_to_world(model, vec4<f32>(vertex.position, 1.0));
 | |
|     out.position = position_world_to_clip(out.world_position.xyz);
 | |
| #endif
 | |
| 
 | |
| #ifdef VERTEX_UVS
 | |
|     out.uv = vertex.uv;
 | |
| #endif
 | |
| 
 | |
| #ifdef VERTEX_UVS_B
 | |
|     out.uv_b = vertex.uv_b;
 | |
| #endif
 | |
| 
 | |
| #ifdef VERTEX_TANGENTS
 | |
|     out.world_tangent = mesh_functions::mesh_tangent_local_to_world(
 | |
|         model,
 | |
|         vertex.tangent,
 | |
|         // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
 | |
|         // See https://github.com/gfx-rs/naga/issues/2416
 | |
|         get_instance_index(vertex_no_morph.instance_index)
 | |
|     );
 | |
| #endif
 | |
| 
 | |
| #ifdef VERTEX_COLORS
 | |
|     out.color = vertex.color;
 | |
| #endif
 | |
| 
 | |
| #ifdef VERTEX_OUTPUT_INSTANCE_INDEX
 | |
|     // Use vertex_no_morph.instance_index instead of vertex.instance_index to work around a wgpu dx12 bug.
 | |
|     // See https://github.com/gfx-rs/naga/issues/2416
 | |
|     out.instance_index = get_instance_index(vertex_no_morph.instance_index);
 | |
| #endif
 | |
| 
 | |
| #ifdef BASE_INSTANCE_WORKAROUND
 | |
|     // Hack: this ensures the push constant is always used, which works around this issue:
 | |
|     // https://github.com/bevyengine/bevy/issues/10509
 | |
|     // This can be removed when wgpu 0.19 is released
 | |
|     out.position.x += min(f32(get_instance_index(0u)), 0.0);
 | |
| #endif
 | |
| 
 | |
|     return out;
 | |
| }
 | |
| 
 | |
| @fragment
 | |
| fn fragment(
 | |
|     mesh: VertexOutput,
 | |
| ) -> @location(0) vec4<f32> {
 | |
| #ifdef VERTEX_COLORS
 | |
|     return mesh.color;
 | |
| #else
 | |
|     return vec4<f32>(1.0, 0.0, 1.0, 1.0);
 | |
| #endif
 | |
| }
 |