Dev Log: Shader Experiments

Dev Log: Shader Experiments
Since my break to work on the remaining bits of Otter I haven't really fallen back into the groove on working on my big game project yet. Yesterday I dedicated the day to playing around with shaders since I'm really interested in using them for all kinds of cool visual effects.


This is what I ended up coming up with at the end of the day. First I was playing around with gradient maps for recoloring an image, and then I started to mess with displacement to make cool waves in the image. Finally I wanted to experiment with having a render texture that could be passed to the shader for dynamic effects.

Basically how this little program works is that there is the static image with a shader loaded. Then there's a Surface object that can be painted on with the mouse. The shader uses the texture from that Surface to affect the image in different ways.

Here's the full C# source:
using Otter;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ShaderTesting {
class Program {
static void Main(string[] args) {
var image = new Image("pic.jpg");
var game = new Game("ShaderZ", image.Width, image.Height);

game.FirstScene = new TestScene();


class TestScene : Scene {

Image image = new Image("pic.jpg");
Image circle = new Image("circle.png");
Surface distortion;

public TestScene() {
distortion = new Surface(image.Width, image.Height);
circle.Blend = BlendMode.Add;
circle.Alpha = 0.1f;
distortion.Visible = false;
distortion.AutoClear = false;

public override void Update() {

if (Timer % 30 == 0) {
try {
image.Shader = new Shader("../../shader.frag");
catch(Exception e) {
Console.WriteLine("Shader error:");
image.Shader.SetParameter("gradient", new Texture("gradient.png"));
if (Input.MouseButtonPressed(MouseButton.Right)) {
image.Shader.SetParameter("time", Timer);
image.Shader.SetParameter("distortion", distortion.Texture);
image.Shader.SetParameter("offset", Util.SinScale(Timer, 0, 1));

if (Input.MouseButtonDown(MouseButton.Left)) {
Draw.Graphic(circle, MouseX, image.Height - MouseY);

public override void Render() {

Draw.Circle(MouseX - 15, MouseY - 15, 30, Color.None, Color.Red, 2);

And the GLSL shader source:
sampler2D texture;
sampler2D gradient;
sampler2D distortion;
uniform float offset;
uniform float time;
uniform float mixfactor;

void main() {
vec2 pos = gl_TexCoord[0];
vec2 distortColor = texture2D(distortion, pos);
pos.x += distortColor.r * (sin(time * 0.1 + pos.x * 10) * 0.05);
pos.y -= distortColor.g * (cos(time * 0.1 + pos.y * 10) * 0.05);
vec4 color = texture2D(texture, pos);

float gray = (color.r + color.g + color.b) / 3;

vec4 gradientColor = texture2D(gradient, vec2(gray, offset));

gl_FragColor = mix(color, gradientColor, distortColor.r + distortColor.g);

You can download everything here. Note that you'll have to give it a reference to Otter to compile and run it yourself.


R Brack
R Brack
Are you meant to be creating a new shader and texture every 30 (seconds? milliseconds?) That seems a bit rough to me.
Posted June 10th 2014 9:57 PM
It's actually every half second (60 fps.) It's so I can edit the shader, save, and see my changes almost instantly instead of having to rebuild the application. I don't notice any performance issues.
Posted June 11th 2014 1:25 AM
new comment!

Post your comment!