What is GLSL?
GLSL (OpenGL Shading Language) is a high-level shading language used for writing shaders within OpenGL. It is utilized to create visual effects on the Graphics Processing Unit (GPU), such as dynamic shadows, lighting, and reflections. GLSL allows developers to directly control the vertex and fragment (pixel) processing stages of the graphics rendering pipeline. By using GLSL, developers can write custom Vertex Shaders, Fragment Shaders, and Compute Shaders, among others, to control the rendering process of 3D graphics. Vertex Shaders process data for each vertex, such as position, color, and texture coordinates, while Fragment Shaders handle the color and material properties of pixels forming the shapes from those vertices. GLSL shader code runs directly on the GPU, offering high performance and flexibility, enabling developers to create complex and high-quality graphical effects.
Why support GLSL in Gandi IDE?
The Quake plugin made by Shawn has been used frequently in Gandi projects and received unanimous praise. Shawn has also been updating the plugin in his spare time. However, some users have complained that Quake does not meet their needs. Therefore, we updated the Quake plugin to allow everyone to write their custom shader code and achieve the desired effects.
Use Case: Implementing Mosaic Effect with GLSL Code
Example Code
#version 300 es
#ifdef GL_ES
precision mediump float; // Set default precision for float types
#endif
// *** WARNING: DO NOT CHANGE THE CODE ABOVE *** //
// For more information on using shaders in Gandi IDE, please visit: https://getgandi.com/blog/glsl-in-gandi-ide
// *** CONFIGURATION *** //
// The following line sets the step value for the 'time' variable, default is 1.
// In a browser typically running at 60 fps, 'time' is incremented by 'step' each frame (i.e., time += step).
//#step:1
// *** DEFAULT VARIABLES *** //
uniform bool byp; // Bypass flag, used to enable or disable the shader effect
in vec2 vUv; // Texture coordinates passed to the fragment shader
out vec4 fragColor; // Output fragment color
// When the following line is defined, the current screen content is passed as a texture to the variable 'tDiffuse'.
// Commenting out or changing the name of 'tDiffuse' will automatically disable this feature.
uniform sampler2D tDiffuse;
// Uncomment to enable the timer. The step set above will only take effect if the timer is started. This example project does not require a timer.
uniform float time;
// *** START WRITING YOUR CODE HERE *** //
// External input for the size of each tile in the mosaic effect
uniform float tileSize;
// External input for the number of texture samples per tile
uniform float textureSamplesCount;
// External input for the thickness of the border
uniform float borderSize;
// Color flashing power
uniform float flashPower;
// Color flashing frequency
uniform float flashFreq;
uniform float effectAlpha;
vec3 palette( float t ) {
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.263,0.416,0.557);
return a + b*cos( 6.28318*(c*t+d) );
}
void main() {
if (!byp) {
// Calculate effective tile size and sample count, use defaults if necessary
float effectiveTileSize = tileSize > 0.0 ? tileSize : 20.0;
float effectiveSamplesCount = textureSamplesCount > 0.0 ? textureSamplesCount : 4.0;
// Calculate the size of the texture and the number of tiles
vec2 sampleSize = vec2(textureSize(tDiffuse, 0));
vec2 tileNumber = floor(vUv * sampleSize / effectiveTileSize);
// Initialize accumulator to sum color values for averaging
vec4 accumulator = vec4(0.0);
for (float y = 0.0; y < effectiveSamplesCount; ++y) {
for (float x = 0.0; x < effectiveSamplesCount; ++x) {
// Calculate offset for each sample within the tile
vec2 offset = vec2(x, y) / effectiveSamplesCount - 0.5;
// Determine texture coordinates for each sample
vec2 textureCoordinates = (tileNumber + offset) * effectiveTileSize / sampleSize;
// Accumulate color values for each sample
accumulator += texture(tDiffuse, textureCoordinates);
}
}
// Compute accumulated color value averaged by the number of samples to achieve mosaic effect
fragColor = accumulator / (effectiveSamplesCount * effectiveSamplesCount);
fragColor.rgb *= flashPower*((sin(time*flashFreq/100.0)+1.0)/4.0)+1.0;
// Calculate and apply border effect
if (borderSize > 0.0) {
// Determine pixel's position relative to its tile
vec2 pixelNumber = floor(vUv * sampleSize - (tileNumber * effectiveTileSize));
// Adjust pixel number to account for border size
pixelNumber = mod(pixelNumber + borderSize, effectiveTileSize);
// Check if pixel is within border area
float pixelBorder = step(min(pixelNumber.x, pixelNumber.y), borderSize) * step(borderSize * 2.0 + 1.0, effectiveTileSize);
// Apply border effect by modifying fragment color
fragColor *= pow(fragColor, vec4(pixelBorder));
}
// Draw some special effects
vec3 finalColor = vec3(0.0);
float time2 = time / 10.0;
vec2 uv = vUv * 1.5;
uv.x *= 1.66;
uv.x += 0.5;
uv.y += 0.5;
for (float i = 0.0; i < 4.0; i++) {
uv = fract(uv * 1.5) - 0.5;
float d = length(uv) * exp(-length(vUv));
vec3 col = palette(length(vUv) + i*.4 + time2*.4);
d = sin(d*8. + time2)/8.;
d = abs(d);
d = pow(0.01 / d, 1.2);
finalColor += col * d;
}
fragColor += vec4(finalColor, 1.0) * vec4(effectAlpha);
} else {
// If bypass is enabled, use the original texture color
fragColor = texture(tDiffuse, vUv);
}
}
How to Run GLSL in Gandi IDE?
Demo Video
Sample Demo
Demos have been open-sourced, feel free to check out the source code, modify, and take it away.
Learning Resources Related to GLSL
- Using GPT to assist in writing shaders: Gandi IDE Shader Helper
- https://thebookofshaders.com/
- https://www.shadertoy.com/