About Godot, GLSL and WebGL, shaders used in the mini-game

The article is mainly about GLSL shaders, and how I used them in this mini-demo game.





The article is divided into the following order:








1. Links and description



You can download the Win / Linux version from the link to itch.io







The source code for the entire game is available on github or gitlab .







Game process:



Minimal, this is not a full game. (no sound in the game)







The goal of the game is to hold out the maximum number of rounds. Rounds begin when the HP spheres are zero and there are no robots in the game.







When destroying figures, bonuses appear, once per round , give the speed of the shot animation, damage (only in the main sphere), and the height of the jump, in color blue, red / green, yellow. Bots also give a bonus but randomly. Player character restores + 1HP each new round.










2. The logic of the game, and the resources used



Resources used:







Blender was used only to reduce the number of polygons on models, and to create broken pieces of models.







The futari-addon module is used . (I'll write about him below)







In the game, two models have animations.

Player character movements I made in Godot, the original model

The second model is sphere-bot which has high-quality animations.







All used ready - made third-party models of objects are listed here .







Game logic and Godot features:



Game logic is not made in the best way, I will list the points that are done normally.







Only one Viewport is used for a 3D scene, and several Viewports (low resolution) in which there are orthogonal cameras for 2D Viewports (also low resolution) in which Multipass / Feedback shaders are processed, more about them below.







All textures have mipmap , and even work in the browser. There are additional graphics settings (Esc - Settings) . For example, you can make any resolution for the game , up to 32x32



pixels, for example, I set 320x240



resolution in the settings, running the game in a browser, and turned on the maximum anti-aliasing MSAA is what happened







All light sources work in real time , there are 16 of them in total.







The floor and the fence are the simplest particles that duplicate the same model many times, the code is trivial .







The particle rotation matrix (pieces of the floor) in my shaders is just a short entry from this formula:







 mat4 rotationAxisAngle( vec3 v, float angle ) { float s = sin( angle ); float c = cos( angle ); float ic = 1.0 - c; return mat4( vx*vx*ic + c, vy*vx*ic - s*vz, vz*vx*ic + s*vy, 0.0, vx*vy*ic + s*vz, vy*vy*ic + c, vz*vy*ic - s*vx, 0.0, vx*vz*ic - s*vy, vy*vz*ic + s*vx, vz*vz*ic + c, 0.0, 0.0, 0.0, 0.0, 1.0 ); }
      
      





for example, v=vec3(0.0,0.0,1.0)



is the rotation along the z



axis, and angle=PI/2.



substitute them and get the desired turn.







Animation of destructible blocks is considered a real-time physics engine





Physics in Godot is quite limited, and it starts to significantly reduce FPS even with a dozen active objects, so all collisions between destroyed pieces are disabled, others are set, levels for physics are set, there is also a limit on the number of simultaneous destruction, and the maximum number of bots at the same time (six).







The physics of inertia and the interaction of the player’s character with dynamic objects. It is turned off by default in Godot, I wrote a minimal interaction, the code in the files:







bot_hit.gd _integrate_forces function and all that is called to it is adversary-bot movements

player_l.gd firstly, the function move_and_slide



disables infinite inertia, and the function process_collision



repels objects.







Preload (preload) at the beginning of the game is used to avoid lag when the object first appears, this helps however when you turn on the Shadows (and some other options), the lags will appear again on the first appearance of the object. Also, this does not help in the browser due to the peculiarities of browsers working with shaders.







Several duplicate objects in one, and several GIProbe, the shapes and parameters of light sources are all intended , made to bypass the limitations of OpenGL or the restrictions in Godot.










3. Used shaders



Environment panorama:



This game uses a static panorama, the picture is obtained from this shader (c1 c2 colors, ldir position)







 vec3 sky(vec3 d, vec3 c1, vec3 c2) { vec3 ldir = normalize(vec3(0.,0.,-1.)); vec3 col = mix(c1*100., c2*100., min(abs(dy)*2. + .5, 1.)) / 255.*.5; col *= (1. + vec3(1., .7, .3) / sqrt(length(d - ldir))*2.); //sun return clamp(col,vec3(0.),vec3(1.)); }
      
      





to get a panorama, remove the comment from line 57 panorama_uv(fragCoord,ro,rd);



and put a comment on line 58







Dynamic panoramas for Godot in past demos (YouTube and there are links to the code) panorama of clouds .

And the panorama of the day / night cycle with the movement of clouds was used in this demo:









another day / night panorama for example, on shadertoy I did not use it anywhere







If you need to convert CubeMap into a panorama of the environment for Godot , I made a simple web converter .







Very simple shaders:



Particle shaders statically determine their position for animation or not. For example spawn.shader)









For an additional glow around objects , not only balls, this is one line of gglow.shader (numbers can be changed as needed)







 float intensity = pow(0.122 + max(dot(NORMAL, normalize(VIEW)),0.), 010.85);
      
      











Displaying text-numbers in 3D , as I understand it in Godot, there is no means for this (without creating an additional FBO (viewport)) so a simple shader printing numbers from a texture (so that it is mipmapping ), the shader code







UI Elements:



Making the custom form of UI panels the easiest for me is on shaders, maybe this is not right at all . The correct way is shown here as an example (in the section on UI).

In this game, the simplest menu background animation , and the HP indicator . Above, in the link to the video of the day / night panorama, it is also done, there are stripes on the sides and all the animation on the shader.







About futari-addon module:



It works almost the same as this shader for 2D particles in video (see from 1:41).







A 2D-SDF map of all polygons is built on the video once at the start and the resulting texture is simply sent to the particles, the particles themselves build normal in the current position and change the movement.







futari-addon does almost the same thing, only instead of a 2D texture map, the coordinates of 3D spheres and planes are transmitted that are processed by condition in the particle shader, so you can freely change their position and other parameters.







Plus, the wind (in my 2D example, adding wind is very simple, as another texture with + - values ​​to the speed, and the particles simply add the speed value from this map in its position).







The futari-addon module is very good , used it instead of creating its own particle system.







Shield Effect:



Particles to which the coordinates of the impact on the sphere and the position of the player, and the extinction are transmitted using the transform feedback buffer. Shader code in en_m.shader file









Bot Shield:





Shader as a three-dimensional noise sheild.shader essentially everything works thanks to the flow



function

The background is determined by gl_FrontFacing



, and painted over darker and greener, not blue.

Response to a punch - the shock event timer is simply transmitted.












Shaders reading their last frame, or Feedback / Multipass shaders:



Almost all effects are made using this logic.

One of the shaders from the game .

As a source, I set an orthogonal camera that shoots objects in a certain group at a short distance (without processing the entire scene)

.







Ice Field Effect:



The shader is indicated above, in the project file is ice_feedback.shader , and a fragment shader for the plane that creates the illusion of depth of the floor using a simple depth loop:







 while(current_depth < depth){ ofs -= delta; depth = textureLod(texture_depth, ofs,0.0).r; current_depth += layer_depth; }
      
      







Particle Field Effect:



The shader is the same , the y



coordinate (height) of the particles according to the brightness of the color of the frame buffer from the shader, the color also according to the color brightness ( I did not save the particle shader separately, it is in the project in the object floor/visible_/floor3/grass/grass



).









Dynamic flag animation:



Godot has SoftBody for animating the fabric, but it's a CPU, so I haven't used it. I used a ready-made code link to the original . This flag is pushed from three balls on the side and the character’s head is the fourth ball.

The logic of the multipass shader, as in the example above, with only three axes, the multipass code of the shader is (1) flag.shader , the shader that draws the flag just shows the texture and changes the geometry of the plane (2) flag.shader .









Appearance of figures:



Shapes do not have UV, therefore triplanar-texture-mapping for texture mapping , and cutting along triangles ( vertex ), all code in cchess.shader









Animation of a hitbox (red frame) that causes damage to the player’s character, and a trace from the frame (particles are obvious):





It uses only the already specified shader gglow.shader .

PS Made the same animation in one shader , link to shadertoy







For particles, only two textures are used, a circle and a square.










4. About Godot, and its features



Godot is very good and simple (not for a beginner). I really liked Godot for its features.







There are a lot of bugs, the Godot documentation is incomplete and sometimes misleading due to errors and not indicating critical points (not obvious to me) to understand which Godot had to reread all the source code many times (the code is not large and well written).

This is just my impression, it may be wrong, I do not want to mislead anyone.







I emphasize that even very critical bugs in Godot can be circumvented in Godot itself through GDScript, with minimal effort. What is undoubtedly a big plus







I also note that Godot is in no way protected from the peculiarities of external factors, such as WASM in browsers, ANGLE restrictions, strong limitations of browsers themselves, and of course, dozens of bugs in video card drivers, all this has to be bypassed manually.







Lags - there is a big problem with management, it is 100% on the Godot side, I did not fix it. (control wedges during compilation of FPS shaders and lags (for example, in a browser)), also other lags related to the features of 3D rendering in Godot, I made a detour of some of them, but they still exist / may be.










5. WebGL2 only works on Linux



Do not start the game from the link if you have Windows. Link to WebGL2 / WASM version.







Only works on Chrome 76+ and Firefox (Linux).







A bugreport (link) was sent about Windows, if this is a browser bug, then Google reacts after 2 months. But apparently this is a bug in ANGLE, and this is wontfix almost certainly.

The bugreport is already closed, and ANGLE will not be edited either. So on Windows, the browser will not work.







In the course of this project, one bug in Chrome was fixed due to which transform-feedback and my last demo (above video with a day / night panorama) , which had not worked before, started working.










6. Multiplayer



Added multiplayer, exclusively for test purposes (and sample multiplayer in Godot). Source code and binary versions next to the main version on the github and itch (links at the beginning).









As Godot 3.2 comes out, I will add WebRTC for the test too.








All Articles