Fixed uniform alignment & starfield flicker
parent
cd6537f971
commit
67f10c940a
|
@ -11,23 +11,33 @@ pub struct GlobalData {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Default, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
// Uniforms require uniform alignment.
|
||||
// Since the largest value in this array is a [f32; 2],
|
||||
// all smaller values must be padded.
|
||||
// also, [f32; 3] are aligned as [f32; 4]
|
||||
// (since alignments must be powers of two)
|
||||
pub struct GlobalDataContent {
|
||||
/// Camera position, in game units
|
||||
pub camera_position: [f32; 2],
|
||||
|
||||
/// Camera zoom value, in game units
|
||||
pub camera_zoom: f32,
|
||||
/// Camera zoom value, in game units.
|
||||
/// Only first component has meaning.
|
||||
pub camera_zoom: [f32; 2],
|
||||
|
||||
/// Aspect ratio of window (width / height)
|
||||
pub window_aspect: f32,
|
||||
/// Size ratio of window, in physical pixels
|
||||
pub window_size: [f32; 2],
|
||||
|
||||
// Aspect ration of window
|
||||
/// Only first component has meaning.
|
||||
pub window_aspect: [f32; 2],
|
||||
|
||||
/// Texture index of starfield sprites
|
||||
pub starfield_texture: u32,
|
||||
/// Only first component has meaning.
|
||||
pub starfield_texture: [u32; 2],
|
||||
|
||||
// Size of (square) starfield tile, in game units
|
||||
pub starfield_tile_size: f32,
|
||||
|
||||
pub padding: [f32; 3],
|
||||
// Size of (square) starfield tiles, in game units
|
||||
/// Only first component has meaning.
|
||||
pub starfield_tile_size: [f32; 2],
|
||||
}
|
||||
|
||||
impl GlobalDataContent {
|
||||
|
|
|
@ -362,11 +362,14 @@ impl GPUState {
|
|||
0,
|
||||
bytemuck::cast_slice(&[GlobalDataContent {
|
||||
camera_position: game.camera.pos.into(),
|
||||
camera_zoom: game.camera.zoom,
|
||||
window_aspect: self.window_aspect,
|
||||
starfield_texture: 1,
|
||||
starfield_tile_size: STARFIELD_SIZE as f32,
|
||||
padding: Default::default(),
|
||||
camera_zoom: [game.camera.zoom, 0.0],
|
||||
window_size: [
|
||||
self.window_size.width as f32,
|
||||
self.window_size.height as f32,
|
||||
],
|
||||
window_aspect: [self.window_aspect, 0.0],
|
||||
starfield_texture: [1, 0],
|
||||
starfield_tile_size: [STARFIELD_SIZE as f32, 0.0],
|
||||
}]),
|
||||
);
|
||||
|
||||
|
|
|
@ -24,10 +24,11 @@ struct VertexOutput {
|
|||
var<uniform> global: GlobalUniform;
|
||||
struct GlobalUniform {
|
||||
camera_position: vec2<f32>,
|
||||
camera_zoom: f32,
|
||||
window_aspect: f32,
|
||||
starfield_texture: u32,
|
||||
starfield_tile_size: f32
|
||||
camera_zoom: vec2<f32>,
|
||||
window_size: vec2<f32>,
|
||||
window_aspect: vec2<f32>,
|
||||
starfield_texture: vec2<u32>,
|
||||
starfield_tile_size: vec2<f32>,
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,7 +40,7 @@ fn vertex_shader_main(
|
|||
|
||||
// Apply sprite aspect ratio & scale factor
|
||||
// This must be done *before* rotation.
|
||||
let scale = instance.height / global.camera_zoom;
|
||||
let scale = instance.height / global.camera_zoom.x;
|
||||
var pos: vec2<f32> = vec2<f32>(
|
||||
vertex.position.x * instance.aspect * scale,
|
||||
vertex.position.y * scale
|
||||
|
@ -53,13 +54,13 @@ fn vertex_shader_main(
|
|||
|
||||
// Apply screen aspect ratio, again preserving height.
|
||||
// This must be done AFTER rotation... think about it!
|
||||
pos = pos / vec2<f32>(global.window_aspect, 1.0);
|
||||
pos = pos / vec2<f32>(global.window_aspect.x, 1.0);
|
||||
|
||||
// Translate
|
||||
pos = pos + (
|
||||
// Don't forget to correct distance for screen aspect ratio too!
|
||||
(instance.position / global.camera_zoom)
|
||||
/ vec2<f32>(global.window_aspect, 1.0)
|
||||
(instance.position / global.camera_zoom.x)
|
||||
/ vec2<f32>(global.window_aspect.x, 1.0)
|
||||
);
|
||||
|
||||
var out: VertexOutput;
|
||||
|
|
|
@ -19,10 +19,11 @@ struct VertexOutput {
|
|||
var<uniform> global: GlobalUniform;
|
||||
struct GlobalUniform {
|
||||
camera_position: vec2<f32>,
|
||||
camera_zoom: f32,
|
||||
window_aspect: f32,
|
||||
starfield_texture: u32,
|
||||
starfield_tile_size: f32
|
||||
camera_zoom: vec2<f32>,
|
||||
window_size: vec2<f32>,
|
||||
window_aspect: vec2<f32>,
|
||||
starfield_texture: vec2<u32>,
|
||||
starfield_tile_size: vec2<f32>,
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,33 +40,41 @@ fn vertex_shader_main(
|
|||
// Center of the tile the camera is currently in, in game coordinates.
|
||||
// x div y = x - (x mod y)
|
||||
let tile_center = (
|
||||
global.camera_position
|
||||
global.camera_position.xy
|
||||
- (
|
||||
fmod(
|
||||
global.camera_position + global.starfield_tile_size / 2.0,
|
||||
global.starfield_tile_size
|
||||
) - global.starfield_tile_size / 2.0
|
||||
global.camera_position.xy + global.starfield_tile_size.x / 2.0,
|
||||
global.starfield_tile_size.x
|
||||
) - global.starfield_tile_size.x / 2.0
|
||||
)
|
||||
);
|
||||
|
||||
// Apply sprite aspect ratio & scale factor
|
||||
// also applies screen aspect ratio
|
||||
let scale = instance.height / global.camera_zoom;
|
||||
var scale: f32 = instance.height / global.camera_zoom.x;
|
||||
|
||||
// Minimum scale to prevent flicker at large zoom levels
|
||||
var real_size = scale * global.window_size.xy;
|
||||
if (real_size.x < 2.0 || real_size.y < 2.0) {
|
||||
scale = 2.0 / min(global.window_size.x, global.window_size.y);
|
||||
}
|
||||
|
||||
|
||||
var pos: vec2<f32> = vec2<f32>(
|
||||
vertex.position.x * scale / global.window_aspect,
|
||||
vertex.position.x * scale / global.window_aspect.x,
|
||||
vertex.position.y * scale
|
||||
);
|
||||
|
||||
// World position relative to camera
|
||||
// (Note that instance position is in a different
|
||||
// coordinate system than usual)
|
||||
let camera_pos = (instance.position + tile_center) - global.camera_position;
|
||||
let camera_pos = (instance.position + tile_center) - global.camera_position.xy;
|
||||
|
||||
// Translate
|
||||
pos = pos + (
|
||||
// Don't forget to correct distance for screen aspect ratio too!
|
||||
(camera_pos / (global.camera_zoom * (instance.parallax)))
|
||||
/ vec2<f32>(global.window_aspect, 1.0)
|
||||
(camera_pos / (global.camera_zoom.x * (instance.parallax)))
|
||||
/ vec2<f32>(global.window_aspect.x, 1.0)
|
||||
);
|
||||
|
||||
var out: VertexOutput;
|
||||
|
@ -84,8 +93,8 @@ var sampler_array: binding_array<sampler>;
|
|||
@fragment
|
||||
fn fragment_shader_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
||||
return textureSampleLevel(
|
||||
texture_array[1],
|
||||
sampler_array[1],
|
||||
texture_array[global.starfield_texture.x],
|
||||
sampler_array[global.starfield_texture.x],
|
||||
in.texture_coords,
|
||||
0.0
|
||||
).rgba * vec4<f32>(0.5, 0.5, 0.5, 1.0);
|
||||
|
|
Loading…
Reference in New Issue