Screen reading shaders
Some effects requires reading from the same target the shader is writing to.
Good example - glass shader with some distortion and refraction. Or water shader in our case!
The idea here:
- render whole scene
- render the mesh for water with refraction shader
- make refractions realistic - read screen data in the shader
First step: render water layer with default material
#![allow(unused)] fn main() { impl World { ... fn draw(&mut self) { // draw the whole world ... // draw tiled layer with water self.tiled_map.draw_tiles("water", dest_rect, level.area); } } }
Second step: add some refractions
Just as in previous chapter we need a material with custom shader
#![allow(unused)] fn main() { let water_material = load_material(WATER_VERTEX_SHADER, WATER_FRAGMENT_SHADER, Default::default()).unwrap(); ... // use that material gl_use_material(self.water_material); // draw tiled layer with water self.tiled_map.draw_tiles("water", dest_rect, level.area); gl_use_default_material(); }
This was pretty much the same as in previous, post-processing chapter.
The most intresting part is in the shader.
In macroquad there are bunch of built-in shader variables.
TODO: link to a list of builtins
For water shader we are going to use two of them:
uniform vec4 _Time;
uniform sampler2D _ScreenTexture;
_Time
contains time passed since game start.
_ScreenTexture
is a very special texture. When material with _ScreenTexture
in the shader is used for the first time in current frame, macroquad will take a "snapshot" of current active render target and will place a copy of it into _ScreenTexture.
So in the sahder we will be able to read the frame how it is rendered so far and use the frame data while rendering water mesh itself.