Jump to content
Sign in to follow this  
  • entry
  • comments
  • views

My new love : ShaderToy



(since shadertoy doesn't allow more than a couple of lines in the description and I don't want to put all the stuff into the comment section there, I abuse the blog here)

For everybody new - or not so new - to shaders, hear this: 

Browse and use ShaderToy

Not only is it just bloody amazing what you find there, it's veeeeeery educational. 
And easy to use. No hassle with setting up the GPU pipeline yourself - you only need a WebGL capable browser (most are). The interactive compiler displays errors right after the faulty code lines.
Minor nuisance for me was the sometimes "restrictive" behaviour of GLSL (coming from HLSL), but that's not deal breaking.

After experimenting with signed distance functions in 3D with my SlimDX/HLSL stuff I was curious about 2D. So I found this (thank you Marteen):



Very nice. Basic shapes with contours and the usual combiners. Improved with lighting and shadows. Expanding on this, experimenting with polygons and stars, I wanted to put it to the test with something less abstract. Anybody remember Spirograph ? The math around this (pun intended) is already endless. I didn't even know about roulettes before.

But let's start simple. There's a very old discovery from a Persian astronomer: Tusi-Couple.

Here a short protocol of the progress:

  • Needed individual colouring for the shapes (Marteen's sample combines all shapes to one SDF). Experimenting with arbitrary blending, too (blend function).

  • Animate the inner circle/wheel within the the outer. Just basic trigonometry. To make it more clear I colored both circles "Wheel of Fortune"-style (see radial function).

  • Choose some point on the inner wheel, mark it with a point. I chose a star shape for this.
  • Track the ellipse path. Since I got no clue how to derive that yet, I simply trial-and-errored.
  • Only got a filled ellipse (or rather: used a transformed circle). Found a real ellipse and used that to generate an outline (ellipse and ellipseLine functions)
  • The ellipse line produced some artifacts at the main axis. Needed some tweaking. Still not perfect, goes havoc in the degenerate case. Now use lineDist in that case.
  • Hmmmm, cogs would be nice. Splitting the polygon function into circleMod (to get normalized angle part) and using polyShape for laying cyclic functions around a circle. The current implementation using a simple sinus is actually NOT a clean SDF. It works well enough though - and I expect a correct implementation to be quite challenging.
  • Added spokes and bars to give even more of a mechanical/gear feeling. Steampunk rules.
  • Challenge: Derive ellipse path automatically. I feared the worst. Ellipses are usually a bitch - algebraically. But in this case I found that one can exploit the simplicity of the Tusi-couple and derive the major/minor axis directly (see final if-clause within sceneDist function. Not yet commented)
  • Add some light and make the thing scale with the viewport correctly (shadertoy has fullscreen capability).
  • TODO: Choose 2nd point with mouse. This should be possible with additional input/buffer logic of the shadertoy setup. Haven't dug into it just yet. For now one can change the point at the start of the shader code, though (relativePos constant).



If you're interested in SDFs I recommend this as a starting point: Distance functions. Quílez has more to offer, of course. He is also quite active on shadertoy. Rewriting classic games for instance. Wow.

PS: Oh my, there are even sound shaders : https://www.shadertoy.com/view/MtGSWc


Recommended Comments

There are no comments to display.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
  • Advertisement
  • Blog Entries

  • Similar Content

    • By triplewoofer
      Hello friends!
      I've been working on some pretty simplistic pixel art lately, so I put together a picture of the parts of a tile set I'm making. In the picture, you can see grass (one patch with a lighter shade), a stone path, and some cliffs/hills. I've uploaded it to the post.
      I'm hoping to get a little bit of feedback on it - is it too simplistic that it doesn't do a good job of portraying what it's supposed to be? Is there anything you would recommend changing to make it look a little more realistic?
      Thanks so much, have a great rest of your day!

    • By sausagejohnson
      Last week, support was added to Orx for gamepad controller mapping as well as half-axes, analog thresholds and stick/button/trigger controls remapping.
      This is made possible by utilizing the SDL Game Controller Database initiative in order to standardize controller sticks and buttons.
      What this means for games is that no matter what type of controller you plug in, JOY_LX_1 means the X axis on the Left Stick of the first controller. This is much better than the previous JOY_X_1 which meant the same thing, but no guarantee which stick on your controller this would be. This greatly removes the need for creating a re-mapper screen to your games (though still good for convenience).
      An example of use would look like the following. Firstly the config:
      [MainInput] JOY_LX_1 = LeftRight Then in code:
      if (orxInput_IsActive("LeftRight")) {     orxFLOAT x = orxInput_GetValue("LeftRight");     //do something } There are a number of joystick tutorials that cover the new features.
    • By BlackSpoon
      Hi guys, let me introduce my new project - Just Smash It! It's all about destruction! Break your way smashing objects with aimed shots!
      * Realistic physics of destruction
      * Smooth game flow
      * Pleasant graphic and sound design
      * Infinite mode after passing the basic set of levels
      * Small size, great time-killer!
      Play Market: https://play.google.com/store/apps/details?id=com.blackspoongames.smashworld
      Feedback are welcome!
    • By Seer
      I have programmed an implementation of the Separating Axis Theorem to handle collisions between 2D convex polygons. It is written in Processing and can be viewed on Github here. There are a couple of issues with it that I would like some help in resolving.
      In the construction of Polygon objects, you specify the width and height of the polygon and the initial rotation offset by which the vertices will be placed around the polygon. If the rotation offset is 0, the first vertex is placed directly to the right of the object. If higher or lower, the first vertex is placed clockwise or counter-clockwise, respectively, around the circumference of the object by the rotation amount. The rest of the vertices follow by a consistent offset of TWO_PI / number of vertices. While this places the vertices at the correct angle around the polygon, the problem is that if the rotation is anything other than 0, the width and height of the polygon are no longer the values specified. They are reduced because the vertices are placed around the polygon using the sin and cos functions, which often return values other than 1 or -1. Of course, when the half width and half height are multiplied by a sin or cos value other than 1 or -1, they are reduced. This is my issue. How can I place an arbitrary number of vertices at an arbitrary rotation around the polygon, while maintaining both the intended shape specified by the number of vertices (triangle, hexagon, octagon), and the intended width and height of the polygon as specified by the parameter values in the constructor?
      The Polygon code:
      class Polygon { PVector position; PShape shape; int w, h, halfW, halfH; color c; ArrayList<PVector> vertexOffsets; Polygon(PVector position, int numVertices, int w, int h, float rotation) { this.position = position; this.w = w; this.h = h; this.halfW = w / 2; this.halfH = h / 2; this.c = color(255); vertexOffsets = new ArrayList<PVector>(); if(numVertices < 3) numVertices = 3; shape = createShape(); shape.beginShape(); shape.fill(255); shape.stroke(255); for(int i = 0; i < numVertices; ++i) { PVector vertex = new PVector(position.x + cos(rotation) * halfW, position.y + sin(rotation) * halfH); shape.vertex(vertex.x, vertex.y); rotation += TWO_PI / numVertices; PVector vertexOffset = vertex.sub(position); vertexOffsets.add(vertexOffset); } shape.endShape(CLOSE); } void move(float x, float y) { position.set(x, y); for(int i = 0; i < shape.getVertexCount(); ++i) { PVector vertexOffset = vertexOffsets.get(i); shape.setVertex(i, position.x + vertexOffset.x, position.y + vertexOffset.y); } } void rotate(float angle) { for(int i = 0; i < shape.getVertexCount(); ++i) { PVector vertexOffset = vertexOffsets.get(i); vertexOffset.rotate(angle); shape.setVertex(i, position.x + vertexOffset.x, position.y + vertexOffset.y); } } void setColour(color c) { this.c = c; } void render() { shape.setFill(c); shape(shape); } }  
      My other issue is that when two polygons with three vertices each collide, they are not always moved out of collision smoothly by the Minimum Translation Vector returned by the SAT algorithm. The polygon moved out of collision by the MTV does not rest against the other polygon as it should, it instead jumps back a small distance. I find this very strange as I have been unable to replicate this behaviour when resolving collisions between polygons of other vertex quantities and I cannot find the flaw in the implementation, though it must be there. What could be causing this incorrect collision resolution, which from my testing appears to only occur between polygons of three vertices?
      Any help you can provide on these issues would be greatly appreciated. Thank you.
    • By ggenije
      Important: I am trying to realize in scrtach which is performance very low due to it's "virutal level" scrtach->flashplayer->java...
      Also i'm new to this forum so i'm sorry if I missed group (like last time)
      Like a title is saying:
      I have project ,and I get negative feedback on it because some people need 30 min to complete it (what is the planned time)
      but problem is that some people need EVEN 5 hours…(game is incremental/idle/upgrade type so it's important to keep same time ...)
      Of course people with slower computer will have less fps so game will be slower for them,
      so I have created TimeDelta system for each frame to calculate something to do per second
      for example
        Update(){move(TimeDelta*speed)}  so that mean it will be moving speed number of pixels(or units) per second so it will be same for almost each user.

      But problem is next:
      I have to change ySpeed by jumpPower (#PlayerJump in my project)
      when any jump button is pressed
      then in each frame decrease ySpeed by gravity it is(-10 * TimeDelta)
      but when someone have lower fps it will have higher TimeDelta and will fall faster but with same jump it turns out to jump significantly lower that changes core of game
      BUT even worse if fps suddenly in moment of jump then timeDelta would be 1 so player will jump much much MUCH higher , then fall much slower because timeDelta changed in meanwhile…(and the point of my game is about upgrading jump not complete game in first fps drop)


      Then I got an idea to fix TimeDelta (like in unity for rigibody) so it will be rounded like
      if calculated TimeDelta is 0.01834 it will be 0.02 fixed
      if weaker computer is using it the TImeDelta will be 0.143 so runded to 0.14 and so on…

      I did not manage to realize it… i tried to calculate it before main initialization of game objects
      but I'm afraid to fps will drop in moment that is calculating so it will be much diffirent…
      I was trying with empty loop(400)(in scrtach even this is taking time) to calculate it but i'm not sure is it right

      So is there good way to realize this fixed TimeDelta
      I only have timer function to use and time difference between frames

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!