noise.png
leaves-area.png
tree.png
| // this is the main scene (args.outputs) | |
| Texture2D tex_scene : register(t0, space2); | |
| // this is the render target that represents the wind displacement map (args.outputs[:wind]) | |
| Texture2D tex_wind : register(t1, space2); | |
| // sampler for the main scene texture | |
| SamplerState sam_scene : register(s0, space2); | |
| // sampler for the wind displacement texture | |
| SamplerState sam_wind : register(s1, space2); | |
| struct Input { | |
| // this is the color of the pixel from the main scene texture | |
| float4 tex_color : COLOR0; | |
| // this is the texture coordinate of the pixel from the main scene texture | |
| float2 tex_coord : TEXCOORD0; | |
| }; | |
| struct Output { | |
| // this is the final color of the pixel after applying the wind effect | |
| float4 frag_color : SV_Target; | |
| }; | |
| Output main(Input input) { | |
| // for the current pixel, sample the wind displacement texture to get the displacement value | |
| // white means the pixel will move to the left, gray means the pixel will stay in place, and black means the pixel will move to the right | |
| float4 wind_displacement = tex_wind.Sample(sam_wind, input.tex_coord); | |
| float displacement_perc = wind_displacement.r - 0.5; | |
| float displacement_amount = 0.08; | |
| // given the displacement percentage, calculate the new texture coordinate for the pixel | |
| float2 displacement_uv = float2((float)input.tex_coord.x + displacement_perc * displacement_amount, | |
| (float)input.tex_coord.y + displacement_perc * displacement_amount); | |
| // clamp the new texture coordinate to be within the bounds of the texture | |
| float2 resolved_uv = float2(clamp(displacement_uv.x, 0.0, 1.0), | |
| clamp(displacement_uv.y, 0.0, 1.0)); | |
| // sample the main scene texture at the new texture coordinate to get the final color of the pixel | |
| Output output; | |
| output.frag_color = tex_scene.Sample(sam_scene, resolved_uv); | |
| return output; | |
| } |
| # require the shader | |
| require "shaders/leaves.fragment.hlsl" | |
| module Main | |
| # start is invoked when Kernel.tick_count == 0 | |
| def start | |
| # represents the wind speed that we should be at | |
| @target_wind_speed = 1.5 | |
| # current wind speed | |
| @wind_speed = 1.5 | |
| # represents the wind intensity that we should be at | |
| @target_wind_intensity = 1.0 | |
| # current wind intensity | |
| @wind_intensity = 1.0 | |
| end | |
| def wind_offset | |
| # the noise texture is shifted by the wind speed and tick_count | |
| # we clamp movement to 8 pixels so that the noise texture shifts | |
| # at pixel whole numbers | |
| (Kernel.tick_count * @wind_speed % 1280).ifloor(8) | |
| end | |
| def tick | |
| # every five seconds, compute a new target wind speed and intensity | |
| if Kernel.tick_count.zmod?(300) | |
| @target_wind_speed = Numeric.rand(0..0.2) + 1.5 | |
| @target_wind_intensity = rand | |
| end | |
| # lerp the current wind speed and intensity towards the target values | |
| # we do this so that the wind speed and intensity change smoothly over time instead of instantly | |
| @wind_speed = @wind_speed.lerp(@target_wind_speed, 0.01, tolerance: 0) | |
| @wind_intensity = @wind_intensity.lerp(@target_wind_intensity, 0.01, tolerance: 0) | |
| # this represents the displacement map composed of noise | |
| # with a hole punch that represents the area where the leaves are | |
| outputs[:wind].set w: 1280, h: 720, background_color: [128, 128, 128, 255] | |
| # we draw the noise texture twice, once at the current offset and | |
| # once at the offset minus the width of the texture | |
| outputs[:wind].primitives << { | |
| x: 0 + wind_offset, y: 0, w: 1280, h: 1280, | |
| path: "sprites/noise.png", | |
| a: 255 * @wind_intensity | |
| } | |
| outputs[:wind].primitives << { | |
| x: -1280 + wind_offset, y: 0, w: 1280, h: 1280, | |
| path: "sprites/noise.png", | |
| a: 255 * @wind_intensity | |
| } | |
| # then we draw the hole punch over the noise so that | |
| # only the leaves move and the tree remains static | |
| outputs[:wind].primitives << { | |
| x: 640, y: 360, w: 512, h: 512, | |
| anchor_x: 0.5, anchor_y: 0.5, | |
| path: "sprites/leaves-area.png", | |
| } | |
| # for the top level outputs, we set the shader | |
| # and pass in the wind texture as a uniform to the shader | |
| outputs.shader = { | |
| path: "shaders/leaves.fragment.hlsl", | |
| textures: [:wind] | |
| } | |
| # render the scene | |
| outputs.background_color = [30, 30, 30] | |
| outputs.primitives << { | |
| x: 640, y: 360, w: 512, h: 512, | |
| anchor_x: 0.5, anchor_y: 0.5, | |
| path: "sprites/tree.png", | |
| } | |
| # if you want to see what the displacement map looks like, | |
| # you can uncomment this line to render it to the screen | |
| # outputs.primitives << { | |
| # x: 0, y: 0, w: 1280, h: 720, path: :wind | |
| # } | |
| end | |
| end | |
| DR.reset |