00:00
00:00
3p0ch
If you like hard games try my Daxolissian System series

plasmid @3p0ch

Scientist

Read the manual & try stuff

So Cal

Joined on 2/13/10

Level:
11
Exp Points:
1,314 / 1,350
Exp Rank:
43,381
Vote Power:
5.35 votes
Rank:
Safety Patrol
Global Rank:
30,412
Blams:
36
Saves:
277
B/P Bonus:
6%
Whistle:
Normal
Medals:
3,950
Supporter:
1y 3m 13d

How2 put a shader in your preloader

Posted by 3p0ch - January 22nd, 2022


 @OmarShehata mentioned shaders in this thread and for some reason I thought web browsers couldn't use them, but he has a whole tutorial series on it. It turns out shader file sizes are generally tiny enough to go into a preloader screen and could make it look nice and fancy with shader effects, so I learned how to make a shader and put it in the preloader for ur a pixel and here's how.


First download GLSLCanvas by Patricio Gonzalez Vivo from github. You'll just need to get the /dist/GlslCanvas.min.js file and put it in the directory where your HTML5 export is created (where your game's index.html file will be). Or you can do like she says and link to rawgit but I prefer having all the code in my project's distribution.


If you're using something other than Godot then you can glance over the next part to get a sense of how to incorporate a shader into your loading screen but you'll need to tweak it for the html file created by your specific engine or framework. After the part about setting up the html file I'll talk about making the actual shader file and that will be relevant no matter what you're using. Be aware that most game engines will create a new index.html file every time they export and overwrite the old one -- Godot and Unity let you make an HTML template that will be used every time you export so you should modify that template to include the shader, but if you don't have the option of making an HTML template and have to just modify the final index.html file then you might want to also save it under a different file name after you add the shader so you don't accidentally wipe it out if you tweak the game and rebuild the HTML5.


For Godot: if you haven't already set up a custom HTML template, you can get the default one from Godot's website. Put it somewhere in your project's directory (res://) using your computer's file browser (it won't import if you try to add it to the project's file tree from within Godot), then in Godot go to Project – Export and make the Custom Html Shell be that file. Open the template html file in your favorite editor, and where the <body> section starts it has a line where it creates a canvas and you should add the shader just after it like so.

<body>
  <canvas id='canvas'>
    HTML5 canvas appears to be unsupported in the current browser.<br />
    Please try updating or use a different browser.
  </canvas>
  <script type="text/javascript" src="GlslCanvas.min.js"></script>
  <canvas id='shader' class="glslCanvas" data-fragment-url="shader.frag" width=1024 height=600 </canvas>

The <script> line loads the GlslCanvas.min.js file you downloaded earlier (and remembered to put in your HTML5 build directory, right?). The code for your shader will go in the shader.frag file, and you should set the width and height to be your game's viewport size. You can remove the shader when the game starts by adding this shader.remove() line near the end of the html file. (The shader.destroy() function that comes with GLSLCanvas confused the Godot preloader so just use shader.remove().)

        }).then(() => {
          shader.remove();
          setStatusMode('hidden');
          initializing = false;
        }, displayFailureNotice);
      }
    })();
  //]]></script>
</body>
</html>

And lastly to force the shader's canvas to be positioned correctly in the viewport, add the position, top, and left lines to the CSS near the top of the html file

#canvas {
  display: block;
  margin: 0;
  color: white;
  position: fixed;
  top: 0;
  left: 0;
}

Then pop the shader.frag file into your build directory (you can use my code below for testing), make a new HTML5 build of your project so it incorporates the new .html template, and zip it up and upload.


For actually writing the shader code, I learned a lot from https://thebookofshaders.com. I like Visual Studio Code and recommend it; if you write your shader in it, these two VS Code extensions are very useful (you can click the Extensions button on the far left bar and search for them, or they'll come up as options if you save a file with a .frag extension): Shader languages support for VS Code and glsl-canvas. Once you have those installed and activated, you can edit the source code for my shader in Visual Studio Code and press Ctrl+Shift+P and use Show glslCanvas to see the shader in action and confirm that everything's working. When you're writing your own shader that'll also show in real time how the code you're editing will be rendered. Here's the code for the shader from the ur a pixel loading screen, and if you've read the first few sections at thebookofshaders (up to the point where I thought "now I know enough to make what I want, the rest is tl dr") then you can probably follow how I approached the coding. (It might be tempting to put the final blocks of code adding each flying square into a for() loop instead of manually adding all the squares, but I've read that some GPUs have horrible handling of loops so better to avoid them.)

#ifdef GL_ES
precision mediump float;
#endif
#define PI 3.1415926535
uniform vec2 u_resolution;
uniform float u_time;

// Scales a vec2 square size where the "radius" is sq_size in the
// smaller of u_resolution's x or y dimensions
vec2 square_ize(float sq_size) {
  vec2 final_square = vec2(sq_size);
  if (u_resolution.x > u_resolution.y) {
    final_square.x = sq_size * u_resolution.y / u_resolution.x;
  } else {
    final_square.y = sq_size * u_resolution.x / u_resolution.y;
  }
  return final_square;
}

void main() {
  vec2 scaled_position = gl_FragCoord.xy / u_resolution.xy;
  vec3 final_color = vec3(0.0);

  // Determine all of the flying pixels' position, size, and intensity
  vec2 red_sq_pos = vec2(
    fract(0.3 + u_time),
    0.3 * (1.0 + sin(u_time))
  );
  vec2 red_sq_size = square_ize(0.05 + 0.05 * abs(cos(u_time)));
  float red_sq_intensity = 0.2;

  vec2 green_sq_pos = vec2(
    fract(u_time * 1.5),
    0.7 + 0.3 * sin(u_time + 5.0) - 0.2 * fract(u_time * 1.5)
  );
  vec2 green_sq_size = square_ize(0.05 + 0.05 * green_sq_pos.x);
  float green_sq_intensity = 0.2;

  vec2 blue_sq_pos = vec2(
    pow(fract(u_time), 2.0),
    0.4 + 0.3 * cos(u_time) + 0.2 * fract(u_time)
  );
  vec2 blue_sq_size = square_ize(0.075 - 0.025 * blue_sq_pos.x);
  float blue_sq_intensity = 0.2;

  vec2 cyan_sq_pos = vec2(
    sqrt(fract(u_time * 1.7)),
    0.7 + 0.3 * -sin(u_time) - 0.3 * fract(u_time * 1.7)
  );
  vec2 cyan_sq_size = square_ize(0.1 - 0.1 * abs(cyan_sq_pos.x - 0.5));
  float cyan_sq_intensity = 0.2;

  vec2 yellow_sq_pos = vec2(
    0.5 - 8.0 * pow(0.5 - fract(0.8 * u_time), 3.0),
    0.5 + 0.4 * cos(3.5 * u_time)
  );
  vec2 yellow_sq_size = square_ize(0.05 + 0.05 * abs(sin(2.0 * u_time)));
  float yellow_sq_intensity = 0.2;

  vec2 mag_sq_pos = vec2(
    fract(0.6 * u_time + 0.2 * sin(5.0 * u_time)),
    0.5 + 0.2 * cos(7.5 * u_time) + 0.2 * sin(4.0 * u_time)
  );
  vec2 mag_sq_size = square_ize(0.02 + abs(0.08 * sin(u_time * 0.3)));
  float mag_sq_intensity = 0.2;

  // Set overall background
  final_color.r += 0.2 * scaled_position.x * (1.0 + sin(u_time));
  final_color.r += 0.2 * (1.0 - scaled_position.y) * (1.0 + cos(u_time));
  final_color.b += 0.15 * (1.0 - scaled_position.x) * (1.0 + sin(1.3 * u_time));
  final_color.g += 0.2 * clamp(scaled_position.y - scaled_position.x, 0.0, 1.0) * (1.0 + cos(0.3 * u_time));

  // Add red square
  if ((abs(scaled_position - red_sq_pos).x < red_sq_size.x) && 
      (abs(scaled_position - red_sq_pos).y < red_sq_size.y)) {
    final_color.r += red_sq_intensity;
  }

  // Add green square
  if ((abs(scaled_position - green_sq_pos).x < green_sq_size.x) && 
      (abs(scaled_position - green_sq_pos).y < green_sq_size.y)) {
    final_color.g += green_sq_intensity;
  }

  // Add blue square
  if ((abs(scaled_position - blue_sq_pos).x < blue_sq_size.x) && 
      (abs(scaled_position - blue_sq_pos).y < blue_sq_size.y)) {
    final_color.b += blue_sq_intensity;
  }

  // Add cyan square
  if ((abs(scaled_position - cyan_sq_pos).x < cyan_sq_size.x) && 
      (abs(scaled_position - cyan_sq_pos).y < cyan_sq_size.y)) {
    final_color.gb += blue_sq_intensity;
  }

  // Add yellow square
  if ((abs(scaled_position - yellow_sq_pos).x < yellow_sq_size.x) && 
      (abs(scaled_position - yellow_sq_pos).y < yellow_sq_size.y)) {
    final_color.rg += blue_sq_intensity;
  }

  // Add magenta square
  if ((abs(scaled_position - mag_sq_pos).x < mag_sq_size.x) && 
      (abs(scaled_position - mag_sq_pos).y < mag_sq_size.y)) {
    final_color.rb += blue_sq_intensity;
  }

  gl_FragColor = vec4(final_color, 0.5);
}

Tags:

4

Comments

Comments ain't a thing here.