Playing with shaders

About Monkey 2 Forums Monkey 2 Development Playing with shaders

This topic contains 26 replies, has 8 voices, and was last updated by  peterigz 2 years, 2 months ago.

Viewing 15 posts - 1 through 15 (of 27 total)
  • Author
    Posts
  • #6392

    peterigz
    Participant

    Gave myself a quick crash course in shaders and applied it a bit in monkey2 for fun. If you want the attached to run then you’ll have to make a few minor additions to mojo code so maybe not for the faint hearted but if you fancy having a play then this is what you do: (the modified files are attached as well, but just so you know what changed)

    By default, the mojo vertexbuffer contains position, 2 texcoords and color, but I needed to pass a variable to the shader that I could use to create animated shaders. So to do that:

    mojo.graphics.vertex.monkey2: add and extra field (time:float) to the vertex2 struct:

    then in mojo/graphics/canvas.monkey2 theres 4 different “AddVertex” methods, in each one add:

    So basically we’ll be passing the time which we can use to create a varying number to animate with.

    Then in mojo/graphics/vertexbuffer.monkey2 you need to change the Pitch property to return 32 (the new size of the vertex2 struct) and add a new attrib pointer in the Bind() method:

    Then finally in mojo/graphics/shader.monkey2 you need to add the new attrib location:

    So then in your shader you can create your “attribute float mx2_Time;” which will get the time value that’s set in AddVertex. Look at noise.glsl I added more comments in there.

    It’s a messy hack but fun to play with 🙂 If you want to see what effect this creates without downloading and trying for yourself I took the shaders “Quasicrystal” and “Noise” from here: http://pixelshaders.com/examples/

    It’d be nice if there was an easier way of doing this, but I can see there’s lots of things that would need to be taken into consideration, maybe we can come up with something?

    #6395

    Mark Sibly
    Keymaster

    Nice work, and very similiar to what I did to get a little 3d engine going, ie: modify the Vertex struct and rewrite some shaders!

    Do you really need ‘time’ to be a vertex attribute here though? It’s likely to be the same for most (all if your fast enough) vertices, in which case it should really be a ‘uniform’.

    This is where the ‘UniformBlock’ thing comes in – have a look in Cavas for how shader _uniforms are set, and at UniformBlock.Init() for how uniform names are bound. You could bind mx2_Time in UniformBlock.Init() and set mx2_Time somewhere in canvas.

    #6396

    peterigz
    Participant

    Thanks Mark, I looked at uniformblock but was struggling to make sense of how it all fits together so went the easier (to me) route with the vertex buffer just to see if I can make it work, still not sure what I’m doing!

    Will take a closer look at it now I’m a bit clearer 🙂

    #6401

    Ethernaut
    Participant

    This is really cool!
    I still can’t wrap my head around GL shaders, though… the syntax is fine, but I can never understand how the stuff happening in the shader gets passed to the graphics card… like, are there pre-determined variables that do pre-determined things the driver expects that I’m supposed to use?

    #6402

    cocon
    Participant

    Nice approach, this gives me lots of ideas.

    From one hand I would like to see this type of functionality given out of the box in mojo. This way the majority of users would simply to download pre-made shaders made by the community and use them asap.

    Imagine instead of having a blue shape for your water, to have a real crystal clear water. This would be super cool.

     

    Another approach to this solution would be:
    ‘ usage example
    canvas.UseShader(myCustomShader)
    canvas.DrawRect …
    canvas.StopUsingShader()
    On canvas.monkey2 (line 1229) you would have:
    Field _shader:Shader ‘ the original shader
    Field _shaderCustom:Shader ‘ the custom shader
    Field _useCustomShader:Bool ‘ the flag to control the custom shader usage

    In Method AddDrawOp (line 1409) you would have:
    If _useCustomShader _drawOp.shader=_shaderCustom Else _drawOp.shader=shader

     

    Another guarantee for safety is that there should be a validation mechanism that would ensure that the most essential shader attributes and uniforms (starting by the prefix mx2_) are there, this would prevent any errors.

     

    P.S. Also in this example you posted peterigz, the “time” could become a uniform, check here my GLES code to see how the uniforms are used. The “matrix” that is used as the camera:
    http://monkey2.monkey-x.com/forums/topic/monkey2-opengl-experiments/

    #6407

    codifies
    Participant

    @ethernaut – don’t know if this will help but shader output is(edit isn’t!!) “passed” to the graphics card, its actually *running* on the GPU itself, there used to be a bunch of “built in” variables, but in GLES2.0 there is just vertex and fragment output gl_Position and gl_FragColor (in later versions you just define any old variable as “out”)

    I found this book most useful http://www.opengles-book.com/es2/ (yipes that was more than 6 years ago!!!)

    #6417

    cocon
    Participant

    In general terms all of the graphics theory is based on software renderers, OpenGL allows you to have this renderer but in the difference that it exists as hardware and you are given an API to access it and use it.

    #6425

    Mark Sibly
    Keymaster

    I can never understand how the stuff happening in the shader gets passed to the graphics card…

    Your shader programs are actually executed on the GPU.

    GPU still renders triangles, but it calls your vertex shader to get the position of each triangle vertex. Vertex shader does this by writing to the built-in gl_Position var. The inputs to the vertex shader program are the vertex buffer data (ie: local position, texcoords, normal etc) and the vertex shader needs to somehow transform the position value to clip space (one model->view->projection matrix multiply is often enough) and write the other to varyings (see below) for interpolation.

    GPU then draws a triangle, scanline by scanline just the way you would in software, only it calls your fragment shader to evaluate the color to actually render each pixel (aka fragment) to the draw buffer. Fragment shader does this by writing to the built-in gl_FragColor var. The inputs to the fragment shader are ‘varying’ values that you have previously set up in the vertex shader – things like vertex color, texcoords etc. The GPU interpolates these for you while it generates the triangle.

    #6426

    Mark Sibly
    Keymaster

    From one hand I would like to see this type of functionality given out of the box in mojo.

    Same here, but time=money etc. I’d already spent a month or 2 on 2d and couldn’t really justify spending more time on the graphics ‘subsystem’, esp. when I had no ‘alternate’ use case for it, such as mojo3d! Plus people were waiting on better IDE, reflection, mobile, website, docs etc etc.

    #6428

    cocon
    Participant

    Let’s hope that things will go smooth.

    #6474

    peterigz
    Participant

    I tried out uniform as Mark/Cocon suggested and it’s much easier. Had a little play and made it easier to add your own uniforms by adding a new command:

    Which lets you define your own uniform (this should match what you put in your shader), and lets you define a callback which will be called every time the canvas is rendered. For example the demo program now looks like:

    Which is reasonably neat. You could extend “UserUniform” Class to put your own fields in there to help pass whichever specific variables you need to as the UserUniform instance is passed into the callback function as well. I’ve attached the modified files again, only Canvas and UniformBlock needed changing this time.

    Attachments:
    1. Shaders-1.zip
    #6483

    Diffrenzy
    Keymaster

    Looks great peterigz

    Would you be able to tacle a shader that does antialiasing, as Mark suggests here : http://monkey2.monkey-x.com/forums/topic/poor-mans-antialias/#post-6472

    It is too specialized for me at the moment, and would be a great addition to MX2.

    #6493

    peterigz
    Participant

    I think that’s a bit beyond me! The smaa shader looks good, but it looks a bit advanced to implement, I’m pretty new to shaders.

    Which brings me onto another question: If we wanted to apply a shader to the whole screen after it’s rendered everything else where would you look in mojo?  I can see where it does the lighting and shadow rendor passes so I’m guessing after that somewhere.

    #6495

    codifies
    Participant

    One technique is to render the whole game to a texture and then use that texture to render a whole screen sized poly using your sfx shader, you need decent hardware

    It should also noted that while graphics effects do add to presentation they do nothing for game play or balance or any of the other important aspects of a crackimg game, ive played some fantastic games that look quite plain – worth thinking about….

    #6582

    Diffrenzy
    Keymaster

    @peterigz : Ok, maybe someone else will take up the challenge, or Mark will include it when he makes the 3D Module.

Viewing 15 posts - 1 through 15 (of 27 total)

You must be logged in to reply to this topic.