- Joined
- Jan 2, 2020
- Messages
- 1,414
This simple shader shows how you can add more life to your game without effort.
Hopefully it gives you more insight in how a shader works, to get you more comfortable experimenting with shaders for yourself.
Swaygrass.cx
s
shader.glsl
Hopefully it gives you more insight in how a shader works, to get you more comfortable experimenting with shaders for yourself.
Swaygrass.cx
Cerberus:
Import mojo2
Function Main()
New MyApp
End
Class MyApp Extends App
Field sourceImage : Image
Field targetImage : Image
Field canvas : Canvas
Field effect : ShaderEffect
Field value : Float
Field timer:Float = 0
Method OnCreate()
sourceImage = Image.Load("grass.png",0,0,0)
targetImage = New Image(sourceImage.Width,sourceImage.Height)
effect = New ShaderEffect
canvas = New Canvas
SetUpdateRate 0
End
Method OnUpdate:Int()
timer = Millisecs()/100.0
' timer = (MouseX())/10.0 ' Test using mouse
Return 0
End
Method OnRender()
canvas.Clear 0, 0.5, 1, 1
effect.SetValue value
value = value + 0.01
effect.SetValue timer ' Pass the varible timer to shader
effect.Render sourceImage, sourceImage,targetImage
canvas.DrawRect 0,480-256, 256*1,256*1,targetImage,0,0,256,256 ' Even non-symmetrical tiling like this hides the seams quiet well.
canvas.DrawRect 256,480-245, 256*1,256*1,targetImage,0,0,256,256 ' For perfect results, you could use fullsize-textures,
canvas.DrawRect 512,480-256, 256*1,256*1,targetImage,0,0,256,256 ' and skip the tiling or use symmetrical textures.
canvas.Flush
End
End
Class myShader Extends Shader
Method New()
Build(LoadString("shader.glsl"))
End
Method OnInitMaterial:Void(material:Material)
material.SetTexture "ColorTexture",Texture.White()
material.SetScalar "Timer",1
End
Function Instance:myShader()
If Not _instance _instance=New myShader
Return _instance
End
Private
Global _instance:myShader
End
Class ShaderEffect
Private
Global _canvas:Canvas
Field _material:Material
Method New()
If Not _canvas _canvas=New Canvas
_material=New Material( myShader.Instance() )
End
Method SetValue:Void( value:Float )
_material.SetScalar "Timer",value ' Timer should be 0-1
End
Method Render:Void(source:Image,source2:Image,target:Image)
_material.SetTexture "ColorTexture",source.Material.ColorTexture
_canvas.Clear 0, 0, 0, 0
_canvas.SetRenderTarget target
_canvas.SetViewport 0,0,target.Width,target.Height
_canvas.SetProjection2d 0,target.Width,0,target.Height
_canvas.DrawRect 0,0,target.Width,target.Height,_material
_canvas.Flush
End
End
shader.glsl
Code:
uniform sampler2D ColorTexture;
uniform float Timer;
#define rand(U) fract(sin(dot(U ,vec2(12.9898,78.233))) * 43758.5453)
void shader(){
// -------------------------------------------------------------------------------------------------
// Get coordinate
vec2 uv=(b3d_ClipPosition.st/b3d_ClipPosition.w)*0.5+0.5 ;
vec2 p = vec2(floor(uv.x*256.0), floor(uv.y*256.0)) ;
// Swaying grass
const float speed = 0.085 ;
const float bending = 0.08 ;
float height = 1.0 - uv.y ;
float op = pow(height,2.5) ;
op = op * (sin(Timer * speed) * bending) ;
// Read pixel
// vec4 color = texture2D(ColorTexture, vec2(uv.x + op, uv.y)).rgba ; // no pixel-wrap
vec4 color = texture2D(ColorTexture, fract(vec2(uv.x + op, uv.y))).rgba ; // pixel-wrap using fract
// Write pixel
b3d_FragColor = color ;
// -------------------------------------------------------------------------------------------------
}