Snippet How to use Blendmode to replace shaders

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Blendmodes are powerful, and often you can use this inbuilt power to save other resources. This also avoids techniques such as stencilbuffers, and it adds the possibility to mask using soft 0-255 level alpha.

Here's how you can use it to mask graphics.
Cerberus:
Import Mojo2

Function Main()
    New Game
    Return 0
End  

Class Game Extends App

    Field canvas:Canvas, sprite:Image[8]

    Method OnCreate ()
        canvas = New Canvas() ; SetSwapInterval 1 ; SetUpdateRate 0
        sprite[0] = New Image(64,64,.0,.0,0)
        Return 0
    End
   
    Method OnRender : Int()
   
        ' Draw the background
        canvas.Clear
        canvas.SetColor 0,0,1 ; canvas.DrawRect 0,0,640,480
          canvas.SetColor 1,1,1 ; canvas.DrawLine 0,0,180,180 ; canvas.DrawLine 180-0,180-10,180,180 ; canvas.DrawLine 180-10,180-0,180,180
           canvas.SetColor 1,0,0 ; canvas.DrawRect Millisecs()/10 Mod 640,220,20,20
           ' ------------------------------------------------------------------------------
        ' Mask (draw inside a 64x64 sprite)
        canvas.SetRenderTarget sprite[0]    ' Set sprite as active canvas...
           canvas.Clear 0,0,0,0                ' ...and clear it
        canvas.SetBlendMode BlendMode.Alpha ; canvas.SetColor 0,1,0,1 ; canvas.DrawOval MouseX()-225,MouseY()-225,50,50 ' Draw something
        canvas.SetBlendMode BlendMode.Multiply2 ; canvas.SetColor 0,0,0,0 ; canvas.DrawOval 20,20,10,10                      ' Draw something, this will mask a hole in the above
        canvas.SetBlendMode BlendMode.Alpha ; canvas.SetColor 1,1,1,1 ' We need to reset canvas properties even if we changed them while it was directed to sprite
        canvas.SetRenderTarget Null ' Set canvas to be main canvas once again
         ' ------------------------------------------------------------------------------
       
         canvas.DrawImage sprite[0],200,200 ' Now draw that sprite on the canvas, this will be the foreground.
       
          canvas.Flush
        Return 0      
    End
End
 

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
Interesting... never really understood how to use SetBlendMode before. sure this will be helpful. tnks(y)(y)
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Glad you like it.

I'm investigating a lot of other things as well using the standard blendmodes
for instance opaque2 seem to be perfect to create (together with SetColor with some clever math) what is called
"order independent transparency".
 

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
Do you know a simple way to make my colored button become grayscale?
I want to turn the disable button to dark gray the easy way without using another image
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Shader is one possibility of course, I wrote this quickly for you.
I include the sourcecode as a zip.
 

Attachments

  • simple.zip
    14.8 KB · Views: 5

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Code:
uniform sampler2D ColorTexture;

void shader(){
    vec2 uv=(b3d_ClipPosition.st/b3d_ClipPosition.w)*0.5+0.5;
    vec4 c = texture2D(ColorTexture, uv);

    // Biological average
    float gray = ( (c.r*0.299) + (c.g*0.587) + (c.b*0.114) ) / 3.0;
    vec4 fragColor = vec4(gray,gray,gray, c.a);

    b3d_FragColor = fragColor ;
}
Code:
Import mojo2
Function Main()
    New MyApp
End

Class MyApp Extends App

    Field src : Image,dst : Image,canvas : Canvas,effect : ShaderEffect

    Method OnCreate()
        canvas = New Canvas ; SetUpdateRate 0
        src = Image.Load("graphics.png",0,0,0)
        dst = New Image(src.Width,src.Height,0,0)
        effect = New ShaderEffect
    End

    Method OnRender()
        canvas.Clear
        effect.Render src,dst
        canvas.DrawImage src,0,0
        canvas.DrawImage dst,0,64
        canvas.Flush
    End
End

Class myShader Extends Shader
    Global _i:myShader
    Method New()
        Build(LoadString("shader.glsl"))
    End
    Method OnInitMaterial:Void(material:Material)
        material.SetTexture "ColorTexture",Texture.White()
    End
    Function Instance:myShader()
        If Not _i _i=New myShader
        Return _i
    End
End

Class ShaderEffect
    Global _c:Canvas
    Field _m:Material
    Method New()
        If Not _c _c=New Canvas
        _m=New Material( myShader.Instance() )
    End
    Method Render:Void(src:Image,dst:Image)
        _m.SetTexture "ColorTexture",src.Material.ColorTexture
        _c.Clear 0,0,0,0
        _c.SetRenderTarget dst
        _c.SetViewport 0,0,dst.Width,dst.Height
        _c.SetProjection2d 0,dst.Width,0,dst.Height
        _c.DrawRect 0,0,dst.Width,dst.Height,_m
        _c.Flush
    End
End
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
As you can see, the bad thing about shaders is that you need to have another image of the exact same size as the one you want to draw.

(dst = New Image(src.Width,src.Height,0,0 here)

But of course that's not a usually a problem with todays memory. You can just use a sprite sheet of 256x256 or whatever size you want and clone the image. Speedwise shaders are amazing so it's all about being okay with the extra destination image (you can only read from ONE texture and write to ONE texture in shaders, you can never read AND write to the same).

Note that you don't have to run the shader live in case you don't want to.
It's just a process that reads pixels and writes pixels. It's not that you don't have time to run it every frame, they are cheap. But
running a million of them might be slow so it's good to know that you dont' have to.

This shows how you can also process only once, and be happy:

Code:
    Method OnRender()
        canvas.Clear
        If MouseDown(0) Then effect.Render src,dst
        canvas.DrawImage src,0,0
        canvas.DrawImage dst,0,64
        canvas.Flush
    End
 
Last edited:

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
I wrote this quickly for you
Thank you. It working great.

It takes quite a lot of steps to accomplish that. But I understand the freedom that comes with it.

By the way, looking at your code.
Code:
_c.DrawRect 0,0,dst.Width,dst.Height,_m
I never knew we could do other than flat color to DrawRect(). Using material...interesting. (y):).
I wish someone could improve our docs. The Mojo2 docs is definitely not for beginners.
dov.jpg
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
That command is the most important command graphical-wise in Cerberus

DrawRect, it is actually slightly faster than drawimage (just a 2% or so). but that's not the point you use it for sprite sheets (texture atlas you used to call it). So start using it :) It's a great habit even for simpler images.

And you never waste any shader power on the whole sheet bec it only process what you actually draw. You can draw 1x1 pixel out of a 4096x4096 sheet al day long.

I don't have too much traffic until 1st May now so, but I hope this is enough to get you going. Love your work with the GUI!
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Regarding the docs I agree but I know they work hard on fixing that so I think when that is done things will be so much better.

There's 1000's of commands listed, but even on a professional level so to speak you only use 10 commands or so.
The docs can frighten, it did to me at least and It begs for alot of questions all the time.
When it actually is all very simple.

Hardware efficiency meets simple syntax if you do it right!
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
It's actually quiet short and sweet if you put away the standard shader code in an imported module, so what I usually do is something like this.


StructuredCode.png
 

Attachments

  • Gray.zip
    15.9 KB · Views: 6

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
Thank you. That is short and clear.
 

magic

Active member
3rd Party Module Dev
3rd Party Tool Dev
Joined
Mar 5, 2018
Messages
215
I know they work hard on fixing that so I think when that is done things will be so much better.
Agreed! It is difficult already to maintain something that is free. Even if people contribute the code, still team needs to check the code etc. It is really time-consuming. So I respect that and thank you.

Mojo 2 things that make me wonder..
  • What is Material in general, and its role?
  • What is the difference between Material & Texture?
And many other things like Lighting and ShadowShader, etc., are confusing. I suspect it is not specific to CerberusX but common practice in graphic languages nowaday. So that info is probably some other place on the net. I found some info like Shader and so on, But really.. it's quite difficult for me to connect back to CX. And yes some are quite easy to figure out.
 

Jimmy

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,105
Lightning and Shadow I think are just some simple shaders that they had the idea to include.
They made their own version of a fixed pipeline using shader, I'm not sure. I guess they wanted *some* kind of lightning included, it feels very ad lib but I'm still impressed.
But ya It feels like one of those features that you either don't understand or you will roll your own routines anyway.

The difference between Material and Texture and Images are still a questionmark to me. I settled to forget everything about textures and materials. Images = Textures = Materials in my world.
I had a hard time to differentiate between images and canvases even at the beginning.
 

Phil7

Administrator
CX Code Contributor
3rd Party Tool Dev
Joined
Jun 26, 2017
Messages
681
The difference between Material and Texture and Images are still a questionmark to me. I settled to forget everything about textures and materials. Images = Textures = Materials in my world.
In simple cases you can see them as equivalent as they are used to draw a graphic on the screen. But I try to give a simplified explanation of the differences.
- The texture is the graphic data itself. Its basically the red green blue and alpha values of all pixels in a picture
- The material uses the graphic data of the texture and adds some effects (tinting, lighting, shadows ...) to it using a small program called shader.
- The image is the geometrical frame so to speak to show the material (graphic data with added effects). Most often it is a rectangle made of two triangles that can be transformed in multiple ways.
To get back to the beginning: As long as you take the (rectangular) graphic data, avoid any special effects except connecting the graphic data to the geometry of the image and don't mess around with that geometry you end up with texture, material and image all being visually the same.
 
Top Bottom