├── .gitignore ├── Atari NTSC Shader ├── README.md └── shaders │ ├── final.fsh │ └── final.vsh ├── Diffuse Lighting & Godrays ├── README.md └── shaders │ ├── composite.fsh │ ├── composite.vsh │ ├── composite1.fsh │ ├── composite1.vsh │ ├── distort.glsl │ ├── final.fsh │ ├── final.vsh │ ├── gbuffers_entities.fsh │ ├── gbuffers_entities.vsh │ ├── gbuffers_hand.fsh │ ├── gbuffers_hand.vsh │ ├── gbuffers_terrain.fsh │ ├── gbuffers_terrain.vsh │ ├── shadow.fsh │ ├── shadow.vsh │ └── textures │ ├── noise.png │ └── noise.png.mcmeta ├── Gameboy Shader ├── README.md └── shaders │ ├── final.fsh │ └── final.vsh ├── Greyscale Shader └── shaders │ ├── README.md │ ├── final.fsh │ └── final.vsh ├── NES Shader ├── README.md └── shaders │ ├── final.fsh │ └── final.vsh ├── README.md └── World Curvature Shader ├── README.md └── shaders ├── gbuffers_entities.fsh ├── gbuffers_entities.vsh ├── gbuffers_terrain.fsh ├── gbuffers_terrain.vsh ├── shaders.properties └── world_curvature.glsl /.gitignore: -------------------------------------------------------------------------------- 1 | BSL* 2 | BSL*.txt 3 | -------------------------------------------------------------------------------- /Atari NTSC Shader/README.md: -------------------------------------------------------------------------------- 1 | # Atari NTSC Shader 2 | 3 | This shader overrides the final pass to make the game look like an old Atari 2600 screen, witht the NTSC format. It accomplishes this by doing 3 things: 4 | 5 | 1. The shader limits the color output to the 128 colors, from the Atari NTSC color format, just like the old Atari screens. 6 | * This is done by using the distance formula on each fragment color against each color in the palette. 7 | * Color codes were pulled from this [List of Video Game Console Palettes](https://en.wikipedia.org/wiki/list_of_video_game_console_palettes#NTSC) Wikipedia page. 8 | 3. The shader pixelates the screen so pixels are 4x the size, in order to emulate the low-resolution Gameboy screen and to make the dithering effect more apparent. 9 | -------------------------------------------------------------------------------- /Atari NTSC Shader/shaders/final.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | uniform sampler2D colortex0; // Optifine's internal shader output (reimplementation of default MC shaders in Optifine's shader pipeline). 6 | 7 | uniform float viewWidth; 8 | uniform float viewHeight; 9 | 10 | // ATARI 2600 NTSC format's 128 colors. 11 | vec3[] ATARI_COLORS = { 12 | vec3(0, 0, 0) / vec3(255), 13 | vec3(108, 108, 108) / vec3(255), 14 | vec3(144, 144, 144) / vec3(255), 15 | vec3(176, 176, 176) / vec3(255), 16 | vec3(200, 200, 200) / vec3(255), 17 | vec3(220, 220, 220) / vec3(255), 18 | vec3(236, 236, 236) / vec3(255), 19 | vec3(255, 255, 255) / vec3(255), 20 | vec3(68, 68, 0) / vec3(255), 21 | vec3(112, 40, 0) / vec3(255), 22 | vec3(132, 24, 0) / vec3(255), 23 | vec3(136, 0, 0) / vec3(255), 24 | vec3(120, 0, 92) / vec3(255), 25 | vec3(72, 0, 120) / vec3(255), 26 | vec3(20, 0, 132) / vec3(255), 27 | vec3(0, 0, 136) / vec3(255), 28 | vec3(0, 24, 124) / vec3(255), 29 | vec3(0, 44, 92) / vec3(255), 30 | vec3(0, 64, 44) / vec3(255), 31 | vec3(0, 60, 0) / vec3(255), 32 | vec3(20, 56, 0) / vec3(255), 33 | vec3(44, 48, 0) / vec3(255), 34 | vec3(68, 40, 0) / vec3(255), 35 | vec3(64, 64, 64) / vec3(255), 36 | vec3(100, 100, 16) / vec3(255), 37 | vec3(132, 68, 20) / vec3(255), 38 | vec3(152, 52, 24) / vec3(255), 39 | vec3(156, 32, 32) / vec3(255), 40 | vec3(140, 32, 116) / vec3(255), 41 | vec3(96, 32, 144) / vec3(255), 42 | vec3(48, 32, 152) / vec3(255), 43 | vec3(28, 32, 156) / vec3(255), 44 | vec3(28, 56, 144) / vec3(255), 45 | vec3(28, 76, 120) / vec3(255), 46 | vec3(28, 92, 72) / vec3(255), 47 | vec3(32, 92, 32) / vec3(255), 48 | vec3(52, 92, 28) / vec3(255), 49 | vec3(76, 80, 28) / vec3(255), 50 | vec3(100, 72, 24) / vec3(255), 51 | vec3(132, 132, 36) / vec3(255), 52 | vec3(152, 92, 40) / vec3(255), 53 | vec3(172, 80, 48) / vec3(255), 54 | vec3(176, 60, 60) / vec3(255), 55 | vec3(160, 60, 136) / vec3(255), 56 | vec3(120, 60, 164) / vec3(255), 57 | vec3(76, 60, 172) / vec3(255), 58 | vec3(56, 64, 176) / vec3(255), 59 | vec3(56, 84, 168) / vec3(255), 60 | vec3(56, 104, 144) / vec3(255), 61 | vec3(56, 124, 100) / vec3(255), 62 | vec3(64, 124, 64) / vec3(255), 63 | vec3(80, 124, 56) / vec3(255), 64 | vec3(104, 112, 52) / vec3(255), 65 | vec3(132, 104, 48) / vec3(255), 66 | vec3(160, 160, 52) / vec3(255), 67 | vec3(172, 120, 60) / vec3(255), 68 | vec3(192, 104, 72) / vec3(255), 69 | vec3(192, 88, 88) / vec3(255), 70 | vec3(176, 88, 156) / vec3(255), 71 | vec3(140, 88, 184) / vec3(255), 72 | vec3(104, 88, 192) / vec3(255), 73 | vec3(80, 92, 192) / vec3(255), 74 | vec3(80, 112, 188) / vec3(255), 75 | vec3(80, 132, 172) / vec3(255), 76 | vec3(80, 156, 128) / vec3(255), 77 | vec3(92, 156, 92) / vec3(255), 78 | vec3(108, 152, 80) / vec3(255), 79 | vec3(132, 140, 76) / vec3(255), 80 | vec3(160, 132, 68) / vec3(255), 81 | vec3(184, 184, 64) / vec3(255), 82 | vec3(188, 140, 76) / vec3(255), 83 | vec3(208, 128, 92) / vec3(255), 84 | vec3(208, 112, 112) / vec3(255), 85 | vec3(192, 112, 176) / vec3(255), 86 | vec3(160, 112, 204) / vec3(255), 87 | vec3(124, 112, 208) / vec3(255), 88 | vec3(104, 116, 208) / vec3(255), 89 | vec3(104, 136, 204) / vec3(255), 90 | vec3(104, 156, 192) / vec3(255), 91 | vec3(104, 180, 148) / vec3(255), 92 | vec3(116, 180, 116) / vec3(255), 93 | vec3(132, 180, 104) / vec3(255), 94 | vec3(156, 168, 100) / vec3(255), 95 | vec3(184, 156, 88) / vec3(255), 96 | vec3(208, 208, 80) / vec3(255), 97 | vec3(204, 160, 92) / vec3(255), 98 | vec3(224, 148, 112) / vec3(255), 99 | vec3(224, 135, 135) / vec3(255), 100 | vec3(208, 132, 192) / vec3(255), 101 | vec3(180, 132, 220) / vec3(255), 102 | vec3(148, 136, 224) / vec3(255), 103 | vec3(124, 140, 224) / vec3(255), 104 | vec3(124, 156, 220) / vec3(255), 105 | vec3(124, 180, 212) / vec3(255), 106 | vec3(124, 208, 172) / vec3(255), 107 | vec3(140, 208, 140) / vec3(255), 108 | vec3(156, 204, 124) / vec3(255), 109 | vec3(180, 192, 120) / vec3(255), 110 | vec3(208, 180, 108) / vec3(255), 111 | vec3(232, 232, 92) / vec3(255), 112 | vec3(220, 180, 104) / vec3(255), 113 | vec3(236, 168, 128) / vec3(255), 114 | vec3(236, 160, 160) / vec3(255), 115 | vec3(220, 156, 208) / vec3(255), 116 | vec3(196, 156, 236) / vec3(255), 117 | vec3(168, 160, 236) / vec3(255), 118 | vec3(144, 164, 236) / vec3(255), 119 | vec3(144, 180, 236) / vec3(255), 120 | vec3(144, 204, 232) / vec3(255), 121 | vec3(144, 228, 192) / vec3(255), 122 | vec3(164, 228, 164) / vec3(255), 123 | vec3(180, 228, 144) / vec3(255), 124 | vec3(204, 212, 136) / vec3(255), 125 | vec3(232, 204, 124) / vec3(255), 126 | vec3(252, 252, 104) / vec3(255), 127 | vec3(252, 188, 148) / vec3(255), 128 | vec3(252, 180, 180) / vec3(255), 129 | vec3(236, 176, 224) / vec3(255), 130 | vec3(212, 176, 252) / vec3(255), 131 | vec3(188, 180, 252) / vec3(255), 132 | vec3(164, 184, 252) / vec3(255), 133 | vec3(164, 200, 252) / vec3(255), 134 | vec3(164, 224, 252) / vec3(255), 135 | vec3(164, 252, 212) / vec3(255), 136 | vec3(184, 252, 184) / vec3(255), 137 | vec3(200, 252, 164) / vec3(255), 138 | vec3(224, 236, 156) / vec3(255), 139 | vec3(252, 224, 140) / vec3(255) 140 | }; 141 | 142 | // Pixelation scale (1 is normal, 2 is double, 4 is quadruple, etc.). 143 | const int PIXEL_SCALE = 4; 144 | 145 | // Take an input color and output the closest NES color, 146 | // essentially limiting screen colors to the 54 NES palette colors. 147 | vec3 closestColor(vec3 color) { 148 | vec3 ClosestColor = ATARI_COLORS[0]; 149 | float ShortestDistance = 1000.0; 150 | for (int i = 0; i < 128; i++) { 151 | float Distance = distance(color, ATARI_COLORS[i]); 152 | //float Distance = length(dot(color - ATARI_COLORS[i], color - ATARI_COLORS[i])); // Identical to above (same performance too). 153 | if (Distance < ShortestDistance) { 154 | ShortestDistance = Distance; 155 | ClosestColor = ATARI_COLORS[i]; 156 | } 157 | } 158 | return ClosestColor; 159 | } 160 | 161 | void main() { 162 | // Pixelate the screen by a4 so pixels look larger (makes dithering more noticeable and the screen more like an old pixelated gameboy screen). 163 | vec2 PixelatedTexCoords = vec2(TexCoords.x, TexCoords.y); 164 | // The following few lines are a long way of modulating, since GLSL v2.1 has problems with mod() or % when floats are involved. 165 | // Convert texture coordinates to screen pixel coordinates, and floor them (just in case). 166 | int PX = int(PixelatedTexCoords.x * viewWidth / PIXEL_SCALE); 167 | int PY = int(PixelatedTexCoords.y * viewHeight / PIXEL_SCALE); 168 | // Convert pixel coordinates back up to texture coordinates (essentially modulating). 169 | PixelatedTexCoords.x = PX / viewWidth * PIXEL_SCALE; 170 | PixelatedTexCoords.y = PY / viewHeight * PIXEL_SCALE; 171 | 172 | // Sample the color. 173 | vec3 Color = texture2D(colortex0, PixelatedTexCoords).rgb; 174 | 175 | // Pick the closest color in the NES color palette. 176 | Color = closestColor(Color); 177 | 178 | // Output the green color. 179 | gl_FragColor = vec4(Color, 1.0); 180 | } -------------------------------------------------------------------------------- /Atari NTSC Shader/shaders/final.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | void main() { 6 | gl_Position = ftransform(); // Essentially gl_ModelViewProjectionMatrix * gl_Vertex. 7 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate to vec2. 8 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/README.md: -------------------------------------------------------------------------------- 1 | # Diffuse Lighting 2 | 3 | * Add diffuse lighting (brighten or darken textures) based on the sun's position. 4 | * Add shadows cast based on the sun's position. 5 | * Refine and blur the shadows so they look better (no hard edges and no longer blocky). 6 | * Add godrays when you look in the direction of the sun 7 | 8 | This is accomplished using the following shader passes: 9 | 10 | * `gbuffers_terrain`, `gbuffers_entities`, and `gbuffers_hand`, which handles the default block, entity, and player-hand rendering and ambient occlusion, before lighting and stuff is applied. 11 | * `shadow`, which simply passes the shadow texture. 12 | * `composite`, which does the majority of the lighting and diffuse calculations, and pulls from the previous shader passes to draw shadows as well. 13 | * `final`, which gamma corrects the color before finally outputting to the screen. 14 | * `distort`, which simply holds a function for distorting shadow vertices, which is used in two separate shaders. -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/composite.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | #include "distort.glsl" 3 | 4 | varying vec2 TexCoords; 5 | 6 | // Direction of the sun (not normalized). 7 | uniform vec3 sunPosition; 8 | 9 | // The color textures which we write to or read from: 10 | uniform sampler2D colortex0; // Color. 11 | uniform sampler2D colortex1; // Normal. 12 | uniform sampler2D colortex2; // Lighting (Red channel is block light like torches, blue channel is sky light affected by the day-night cycle). 13 | uniform sampler2D depthtex0; // Depth from player's perspective (used for shadows). 14 | uniform sampler2D shadowtex0; // Shadow (transparent blocks are opaque). 15 | uniform sampler2D shadowtex1; // Shadow (transparent blocks are actually transparent). 16 | uniform sampler2D shadowcolor0; // Shadow color (for colored and transparent shadows like glass or water). 17 | uniform sampler2D noisetex; // Noise texture. 18 | 19 | // Optifine uniforms for refining and blurring the shadows. 20 | uniform mat4 gbufferProjectionInverse; 21 | uniform mat4 gbufferModelViewInverse; 22 | uniform mat4 shadowModelView; 23 | uniform mat4 shadowProjection; 24 | 25 | // These are comments, but they actually run (idk why Minecraft shaders code with comments sometimes but it's a think apparently). 26 | // Anyway, these declare the color texture formats for Color, Normal, and Lighting. 27 | /* 28 | const int colortex0Format = RGBA16F; 29 | const int colortex1Format = RGB16; 30 | const int colortex2Format = RGB16; 31 | */ 32 | 33 | const float sunPathRotation = -40.0; // The angle of the sun for casting light and shadows. 34 | const int shadowMapResolution = 1024; // The resolution we'd like to use for shadows (higher looks better but is more costly). 35 | const int noiseTextureResolution = 128; // Default value is 64. 36 | 37 | // Ambient lighting value. 38 | const float Ambient = 0.025; 39 | const float AmbientModifier = 0.125; 40 | 41 | // Colors of the torch and sky light. 42 | // The sky color should change depending on time of day, but is ignored for now for simplicity's sake. 43 | const vec3 TorchColor = vec3(1.0, 0.25, 0.08); 44 | const vec3 SkyColor = vec3(0.05, 0.15, 0.3); 45 | 46 | // Tweak torch lighting values, 47 | // (almost exactly like gamma correction since without this the values are linear and look bad). 48 | float AdjustLightmapTorch(in float torch) { 49 | // Unsure why these values are what they are, as the tutorial didn't explain them. 50 | // Must be some magic numbers like 2.2 is for gamma. 51 | const float K = 2.0; 52 | const float P = 5.06; 53 | return K * pow(torch, P); 54 | } 55 | 56 | // Tweak sky lighting values, 57 | // (almost exactly like gamma correction since without this the values are linear and look bad). 58 | float AdjustLightmapSky(in float sky) { 59 | float SkySquared = pow(sky, 2); 60 | return pow(SkySquared, 2); 61 | } 62 | 63 | // Tweak all lighting (torch and sky) values, 64 | // (almost exactly like gamma correction since without this the values are linear and look bad). 65 | vec2 AdjustLightmap(in vec2 Lightmap) { 66 | vec2 NewLightMap; 67 | NewLightMap.x = AdjustLightmapTorch(Lightmap.x); 68 | NewLightMap.y = AdjustLightmapSky(Lightmap.y); 69 | return NewLightMap; 70 | } 71 | 72 | // Input is the unadjusted lightmap coordinates, as this does the adjustments for you. 73 | vec3 GetLightmapColor(in vec2 Lightmap) { 74 | // First adjust the lightmap similar to gamma correction (linear looks bad basically). 75 | Lightmap = AdjustLightmap(Lightmap); 76 | 77 | // Multiply each part of the light map with it's color. 78 | vec3 TorchLighting = Lightmap.x * TorchColor; 79 | vec3 SkyLighting = Lightmap.y * SkyColor; 80 | 81 | // Add the lighting togther to get the total contribution of the lightmap the final color. 82 | vec3 LightmapLighting = TorchLighting + SkyLighting; 83 | return LightmapLighting; 84 | } 85 | 86 | // Get the visibility level of the shadow (i.e. opaque shadows or transparent like with glass). 87 | float Visibility(in sampler2D ShadowMap, in vec3 SampleCoords) { 88 | // -0.001 to fix weird artifacts. 89 | return step(SampleCoords.z - 0.001, texture2D(ShadowMap, SampleCoords.xy).r); 90 | } 91 | 92 | // Check the fully-opaque shadow map and the one that supports transparency, 93 | // then combine them to get shadows with transparency if necessary. 94 | vec3 TransparentShadow(in vec3 SampleCoords){ 95 | float ShadowVisibility0 = Visibility(shadowtex0, SampleCoords); // Opaque shadow map. 96 | float ShadowVisibility1 = Visibility(shadowtex1, SampleCoords); // Transparency shadow map. 97 | vec4 ShadowColor0 = texture2D(shadowcolor0, SampleCoords.xy); // Shadow color (i.e. colored glass). 98 | vec3 TransmittedColor = ShadowColor0.rgb * (1.0 - ShadowColor0.a); // Perform a blend operation with the sun color. 99 | return mix(TransmittedColor * ShadowVisibility1, vec3(1.0), ShadowVisibility0); // Finally, combine all the shadow information together. 100 | } 101 | 102 | // Some constants for GetShadow() for shadow sample resolution. 103 | #define SHADOW_SAMPLES 2 104 | const int ShadowSamplesPerSize = 2 * SHADOW_SAMPLES + 1; 105 | const int TotalSamples = ShadowSamplesPerSize * ShadowSamplesPerSize; 106 | 107 | 108 | // Get the shadow based on depth (this handles conversion between spaces and transformations and stuff). 109 | vec3 GetShadow(float depth) { 110 | // Do some space and projection conversions for the shadows. 111 | vec3 ClipSpace = vec3(TexCoords, depth) * 2.0 - 1.0; 112 | vec4 ViewW = gbufferProjectionInverse * vec4(ClipSpace, 1.0); 113 | vec3 View = ViewW.xyz / ViewW.w; 114 | vec4 World = gbufferModelViewInverse * vec4(View, 1.0); 115 | vec4 ShadowSpace = shadowProjection * shadowModelView * World; 116 | ShadowSpace.xy = DistortPosition(ShadowSpace.xy); 117 | vec3 SampleCoords = ShadowSpace.xyz * 0.5 + 0.5; 118 | 119 | // Handle adding noise to the shadow to fix level/line artifacts. 120 | float RandomAngle = texture2D(noisetex, TexCoords * 20.0).r * 100.0; 121 | float cosTheta = cos(RandomAngle); 122 | float sinTheta = sin(RandomAngle); 123 | mat2 Rotation = mat2(cosTheta, -sinTheta, sinTheta, cosTheta) / shadowMapResolution; // We can move our division by the shadow map resolution here for a small speedup 124 | vec3 ShadowAccum = vec3(0.0); 125 | 126 | // Loop through shadow samples and apply the blurring and noise effects. 127 | for(int x = -SHADOW_SAMPLES; x <= SHADOW_SAMPLES; x++){ 128 | for(int y = -SHADOW_SAMPLES; y <= SHADOW_SAMPLES; y++){ 129 | vec2 Offset = Rotation * vec2(x, y); 130 | vec3 CurrentSampleCoordinate = vec3(SampleCoords.xy + Offset, SampleCoords.z); 131 | ShadowAccum += TransparentShadow(CurrentSampleCoordinate); 132 | } 133 | } 134 | ShadowAccum /= TotalSamples; 135 | return ShadowAccum; 136 | } 137 | 138 | void main() { 139 | // Account for gamma correction, since block textures are already gamma encoded. 140 | vec3 Albedo = pow(texture2D(colortex0, TexCoords).rgb, vec3(2.2)); 141 | float Depth = texture2D(depthtex0, TexCoords).r; 142 | 143 | // Sky depth is always 1.0, so end early if it's a sky fragment to skip block calculations. 144 | if (Depth == 1.0) { 145 | gl_FragData[0] = vec4(Albedo, 1.0); 146 | return; 147 | } 148 | 149 | // Get the normal. 150 | vec3 Normal = normalize(texture2D(colortex1, TexCoords).rgb * 2.0 - 1.0); 151 | 152 | // Get the lightmap. 153 | vec2 Lightmap = texture2D(colortex2, TexCoords).rg; // R is torch light and G is sky light. 154 | vec3 LightmapColor = GetLightmapColor(Lightmap); 155 | 156 | // Compute cosine-theta between the normal and sun directions. 157 | float NdotL = max(dot(Normal, normalize(sunPosition)), 0.0); 158 | 159 | // Base ambient light on sky light. 160 | float AdjustedAmbient = Ambient + AmbientModifier * texture2D(colortex2, TexCoords).b; 161 | 162 | // Do the lighting calculations to get the final diffuse color. 163 | vec3 Diffuse = Albedo * (LightmapColor + NdotL * GetShadow(Depth) + AdjustedAmbient); 164 | 165 | // Declare that we want to use draw buffer 0 with a comment, because of course Minecarft has comments that actually do something lol. 166 | /* DRAWBUFFERS:0 */ 167 | // Finally write the diffuse color. 168 | gl_FragData[0] = vec4(Diffuse, 1.0); 169 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/composite.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | void main() { 6 | gl_Position = ftransform(); 7 | TexCoords = gl_MultiTexCoord0.st; 8 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/composite1.fsh: -------------------------------------------------------------------------------- 1 | #version 130 2 | 3 | varying vec2 screenCoord; 4 | varying vec3 screenRay; 5 | varying float LdotV; 6 | 7 | // Default noise resolution, needs to exist for Optifine to detect and use our noise texture 8 | const int noiseTextureResolution = 256; 9 | 10 | uniform sampler2D gcolor; 11 | uniform sampler2D noisetex; 12 | uniform sampler2D depthtex1; 13 | 14 | // Projection matrix 15 | // Converts view space to clip space 16 | uniform mat4 gbufferProjection; 17 | 18 | // Shadow light position in view space 19 | uniform vec3 shadowLightPosition; 20 | 21 | // Sky mask detector, with brightness input 22 | float skyMask(in vec2 uv, in float brightness){ 23 | // Detects sky by checking if it's equal to 1.0 and return brightness 24 | // Switch to depthtex0 if you want godrays to not go "through" transparent objects 25 | if(textureLod(depthtex1, uv, 0).x == 1.0) return brightness; 26 | // Otherwise return 0.0 27 | return 0.0; 28 | } 29 | 30 | 31 | 32 | void main(){ 33 | // Screen texel coords 34 | ivec2 screenTexelCoord = ivec2(gl_FragCoord.xy); 35 | // Sample main scene color 36 | vec3 sceneCol = texelFetch(gcolor, screenTexelCoord, 0).rgb; 37 | // Sample blue noise 38 | float blueNoise = texelFetch(noisetex, screenTexelCoord & 255, 0).x; 39 | 40 | 41 | // The amount of steps/samples used 42 | // More means more quality and more slower 43 | const int stepSize = 16; 44 | // Reciprocate of step size (1.0 / stepSize) 45 | const float rcpStepSize = 1.0 / float(stepSize); 46 | 47 | // Godray length 48 | const float rayLength = 1; 49 | // Godray strength 50 | const float rayStrength = rcpStepSize / 5; 51 | // Light color 52 | const vec3 lightColor = vec3(1.0, 1.0, 0.75); 53 | 54 | // The end position 55 | // Basically the rayDir converted to screen space, subtracted from screen coord, and divided by step size and multiplied by ray length 56 | vec2 endPos = (screenCoord - screenRay.xy) * rcpStepSize * rayLength; 57 | // The start position 58 | // We apply dithering by multiplying end pos with blue noise and add it to our start pos 59 | vec2 startPos = screenCoord - endPos * blueNoise; 60 | 61 | // We sum and average the final result here 62 | float godRays = 0.0; 63 | 64 | for(int i = 0; i < stepSize; i++){ 65 | // Sample sky mask 66 | godRays += skyMask(startPos, rayStrength); 67 | // We trace in the direction of endPos 68 | // We do this each loop 69 | startPos -= endPos; 70 | } 71 | 72 | // Multiply by light color and add to scene color 73 | sceneCol += godRays * lightColor * LdotV; 74 | 75 | /* DRAWBUFFERS:0 */ 76 | // Output final results to main buffer 77 | // This returns the colors and the alpha of the rays 78 | gl_FragData[0] = vec4(sceneCol, 1); 79 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/composite1.vsh: -------------------------------------------------------------------------------- 1 | #version 130 2 | 3 | varying vec2 screenCoord; 4 | varying vec3 screenRay; 5 | varying float LdotV; 6 | 7 | 8 | // Shadow light position in view space 9 | uniform vec3 shadowLightPosition; 10 | // Converts view space to clip space 11 | uniform mat4 gbufferProjection; 12 | 13 | vec3 toScreen(vec3 pos){ 14 | vec3 data = vec3(gbufferProjection[0].x, gbufferProjection[1].y, gbufferProjection[2].z) * pos + gbufferProjection[3].xyz; 15 | return (data.xyz / -pos.z) * 0.5 + 0.5; 16 | } 17 | 18 | void main(){ 19 | screenCoord = (gl_TextureMatrix[0] * gl_MultiTexCoord0).xy; 20 | // The ray direction (or light direction) 21 | // Because it's already in view space, we need not to do anything fancy yet and just normalize 22 | screenRay = toScreen(normalize(shadowLightPosition)); 23 | LdotV = -normalize(shadowLightPosition).z; 24 | gl_Position = ftransform(); 25 | 26 | 27 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/distort.glsl: -------------------------------------------------------------------------------- 1 | // Used to distort shadows for noise/blurring. 2 | vec2 DistortPosition(in vec2 position){ 3 | float CenterDistance = length(position); 4 | float DistortionFactor = mix(1.0f, CenterDistance, 0.9f); 5 | return position / DistortionFactor; 6 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/final.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | uniform sampler2D colortex0; // Color. 6 | 7 | void main() { 8 | // Sample and apply gamma correction 9 | vec3 Color = pow(texture2D(colortex0, TexCoords).rgb, vec3(1.0 / 2.2)); 10 | gl_FragColor = vec4(Color, 1.0); 11 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/final.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | void main() { 6 | gl_Position = ftransform(); // Essentially gl_ModelViewProjectionMatrix * gl_Vertex. 7 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate. 8 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/gbuffers_entities.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | varying vec3 Normal; 5 | varying vec4 BiomeColor; // Water and foliage is greyscale and then colored based on the biome it is. 6 | varying vec2 LightmapCoords; 7 | 8 | uniform sampler2D texture; // The block mesh texture (block meshes are combined into chunks). 9 | 10 | void main() { 11 | // Sample from texture atlas, then multiply by biome color, 12 | // (since vegatation, water, etc. are greyscale and then multiplied to be different shades of green basedon the biome). 13 | vec4 Albedo = texture2D(texture, TexCoords) * BiomeColor; 14 | 15 | // Declare access to draw buffers 0, 1, and 2 16 | // using a comment because of course Minecraft would code with comments. 17 | // Then draw to them. 18 | /* DRAWBUFFERS:012 */ 19 | gl_FragData[0] = Albedo; 20 | gl_FragData[1] = vec4(Normal * 0.5 + 0.5, 1.0); 21 | gl_FragData[2] = vec4(LightmapCoords, 0.0, 1.0); 22 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/gbuffers_entities.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | varying vec3 Normal; 5 | varying vec4 BiomeColor; // Water and foliage is greyscale and then colored based on the biome it is. 6 | varying vec2 LightmapCoords; 7 | 8 | void main() { 9 | gl_Position = ftransform(); // Essentially gl_ModelViewProjectionMatrix * gl_Vertex. 10 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate. 11 | 12 | // gl_Normal is built-in attribute for world-space normal vector. 13 | // Transform normal from world-space to view-space. 14 | Normal = gl_NormalMatrix * gl_Normal; 15 | BiomeColor = gl_Color; 16 | 17 | // Use the texture matrix instead of dividing by 15, to maintain campataility for each version of Minecraft. 18 | LightmapCoords = mat2(gl_TextureMatrix[1]) * gl_MultiTexCoord1.st; 19 | // Transform them into [0, 1] range. 20 | LightmapCoords = (LightmapCoords * 33.05 / 32.0) - (1.05 / 32.0); // Unsure what these magic numbers are, as the tutorial didn't explain them. 21 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/gbuffers_hand.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | varying vec3 Normal; 5 | varying vec4 BiomeColor; // Water and foliage is greyscale and then colored based on the biome it is. 6 | varying vec2 LightmapCoords; 7 | 8 | uniform sampler2D texture; // The block mesh texture (block meshes are combined into chunks). 9 | 10 | void main() { 11 | // Sample from texture atlas, then multiply by biome color, 12 | // (since vegatation, water, etc. are greyscale and then multiplied to be different shades of green basedon the biome). 13 | vec4 Albedo = texture2D(texture, TexCoords) * BiomeColor; 14 | 15 | // Declare access to draw buffers 0, 1, and 2 16 | // using a comment because of course Minecraft would code with comments. 17 | // Then draw to them. 18 | /* DRAWBUFFERS:012 */ 19 | gl_FragData[0] = Albedo; 20 | gl_FragData[1] = vec4(Normal * 0.5 + 0.5, 1.0); 21 | gl_FragData[2] = vec4(LightmapCoords, 0.0, 1.0); 22 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/gbuffers_hand.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | varying vec3 Normal; 5 | varying vec4 BiomeColor; // Water and foliage is greyscale and then colored based on the biome it is. 6 | varying vec2 LightmapCoords; 7 | 8 | void main() { 9 | gl_Position = ftransform(); // Essentially gl_ModelViewProjectionMatrix * gl_Vertex. 10 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate. 11 | 12 | // gl_Normal is built-in attribute for world-space normal vector. 13 | // Transform normal from world-space to view-space. 14 | Normal = gl_NormalMatrix * gl_Normal; 15 | BiomeColor = gl_Color; 16 | 17 | // Use the texture matrix instead of dividing by 15, to maintain campataility for each version of Minecraft. 18 | LightmapCoords = mat2(gl_TextureMatrix[1]) * gl_MultiTexCoord1.st; 19 | // Transform them into [0, 1] range. 20 | LightmapCoords = (LightmapCoords * 33.05 / 32.0) - (1.05 / 32.0); // Unsure what these magic numbers are, as the tutorial didn't explain them. 21 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/gbuffers_terrain.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | varying vec3 Normal; 5 | varying vec4 BiomeColor; // Water and foliage is greyscale and then colored based on the biome it is. 6 | varying vec2 LightmapCoords; 7 | 8 | uniform sampler2D texture; // The block mesh texture (block meshes are combined into chunks). 9 | 10 | void main() { 11 | // Sample from texture atlas, then multiply by biome color, 12 | // (since vegatation, water, etc. are greyscale and then multiplied to be different shades of green basedon the biome). 13 | vec4 Albedo = texture2D(texture, TexCoords) * BiomeColor; 14 | 15 | // Declare access to draw buffers 0, 1, and 2 16 | // using a comment because of course Minecraft would code with comments. 17 | // Then draw to them. 18 | /* DRAWBUFFERS:012 */ 19 | gl_FragData[0] = Albedo; 20 | gl_FragData[1] = vec4(Normal * 0.5 + 0.5, 1.0); 21 | gl_FragData[2] = vec4(LightmapCoords, 0.0, 1.0); 22 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/gbuffers_terrain.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | varying vec3 Normal; 5 | varying vec4 BiomeColor; // Water and foliage is greyscale and then colored based on the biome it is. 6 | varying vec2 LightmapCoords; 7 | 8 | void main() { 9 | gl_Position = ftransform(); // Essentially gl_ModelViewProjectionMatrix * gl_Vertex. 10 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate. 11 | 12 | // gl_Normal is built-in attribute for world-space normal vector. 13 | // Transform normal from world-space to view-space. 14 | Normal = gl_NormalMatrix * gl_Normal; 15 | BiomeColor = gl_Color; 16 | 17 | // Use the texture matrix instead of dividing by 15, to maintain campataility for each version of Minecraft. 18 | LightmapCoords = mat2(gl_TextureMatrix[1]) * gl_MultiTexCoord1.st; 19 | // Transform them into [0, 1] range. 20 | LightmapCoords = (LightmapCoords * 33.05 / 32.0) - (1.05 / 32.0); // Unsure what these magic numbers are, as the tutorial didn't explain them. 21 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/shadow.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | varying vec4 Color; 5 | 6 | uniform sampler2D texture; 7 | 8 | void main() { 9 | gl_FragData[0] = texture2D(texture, TexCoords) * Color; 10 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/shadow.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | #include "distort.glsl" 4 | 5 | varying vec2 TexCoords; 6 | varying vec4 Color; 7 | 8 | void main(){ 9 | gl_Position = ftransform(); 10 | gl_Position.xy = DistortPosition(gl_Position.xy); // Distort the shadow position (for noise/blurring purposes). 11 | TexCoords = gl_MultiTexCoord0.st; 12 | Color = gl_Color; 13 | } -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/textures/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandint2011/mc-shader-exploration/6dfd1c69204db839a9fd21ef56c83920cc28246a/Diffuse Lighting & Godrays/shaders/textures/noise.png -------------------------------------------------------------------------------- /Diffuse Lighting & Godrays/shaders/textures/noise.png.mcmeta: -------------------------------------------------------------------------------- 1 | { 2 | "texture": 3 | { 4 | "blur": true, 5 | "clamp": false 6 | } 7 | } -------------------------------------------------------------------------------- /Gameboy Shader/README.md: -------------------------------------------------------------------------------- 1 | # Gameboy Shader 2 | 3 | This shader overrides the final pass to make the game look like an old Gameboy screen. It accomplishes this by doing 3 things: 4 | 5 | 1. The shader limits the color output to 4 colors, each a shade of green, just like the old Gameboy screens. 6 | * Color codes were pulled from the [Gameboy Wikipedia](https://en.wikipedia.org/wiki/Game_Boy) page. 7 | 2. The shader technically computes 7 colors. There are the 4 solid colors, and 3 intermediate colors that are [dithered](https://en.wikipedia.org/wiki/Dither) between the two neighborind colors. 8 | 3. The shader pixelates the screen so pixels are 4x the size, in order to emulate the low-resolution Gameboy screen and to make the dithering effect more apparent. 9 | -------------------------------------------------------------------------------- /Gameboy Shader/shaders/final.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | uniform sampler2D colortex0; // Optifine's internal shader output (reimplementation of default MC shaders in Optifine's shader pipeline). 6 | 7 | uniform float viewWidth; 8 | uniform float viewHeight; 9 | 10 | // Gameboy's 4 green color values. 11 | // Haven't learned how to add custom uniforms yet, so they're hardcoded. 12 | const vec3 GAMEBOY_0 = vec3(15, 56, 15) / vec3(255); 13 | const vec3 GAMEBOY_1 = vec3(48, 98, 48) / vec3(255); 14 | const vec3 GAMEBOY_2 = vec3(139, 172, 15) / vec3(255); 15 | const vec3 GAMEBOY_3 = vec3(155, 188, 15) / vec3(255); 16 | 17 | // Pixelation scale (1 is normal, 2 is double, 4 is quadruple, etc.). 18 | const int PIXEL_SCALE = 4; 19 | 20 | // When doing dithering between 2 colors, this decides which one to pick. 21 | vec3 dither(int x, int y, vec3 color1, vec3 color2) { 22 | bool DoDither = (x/PIXEL_SCALE % 2 == 0 && y/PIXEL_SCALE % 2 != 0) || (y/PIXEL_SCALE % 2 == 0 && x/PIXEL_SCALE % 2 != 0); 23 | if (DoDither) { 24 | return color1; 25 | } 26 | return color2; 27 | } 28 | 29 | void main() { 30 | // Pixelate the screen by a4 so pixels look larger (makes dithering more noticeable and the screen more like an old pixelated gameboy screen). 31 | vec2 PixelatedTexCoords = vec2(TexCoords.x, TexCoords.y); 32 | // The following few lines are a long way of modulating, since GLSL v2.1 has problems with mod() or % when floats are involved. 33 | // Convert texture coordinates to screen pixel coordinates, and floor them (just in case). 34 | int PX = int(PixelatedTexCoords.x * viewWidth / PIXEL_SCALE); 35 | int PY = int(PixelatedTexCoords.y * viewHeight / PIXEL_SCALE); 36 | // Convert pixel coordinates back up to texture coordinates (essentially modulating). 37 | PixelatedTexCoords.x = PX / viewWidth * PIXEL_SCALE; 38 | PixelatedTexCoords.y = PY / viewHeight * PIXEL_SCALE; 39 | 40 | // Sample the color. 41 | vec3 Color = texture2D(colortex0, PixelatedTexCoords).rgb; 42 | 43 | // Convert to grayscale. 44 | Color = vec3(dot(Color, vec3(0.333f))); 45 | 46 | // Get the pixel coordinate (for dithering). Bottom-left is (0,0). 47 | // This doesn't use pixelated texture coordinates, because it causes artifacts, so it's handled in the doDither() function to compensate. 48 | vec2 Pixel = vec2(TexCoords.x * viewWidth, TexCoords.y * viewHeight); 49 | int PixelX = int(floor(Pixel.x)); 50 | int PixelY = int(floor(Pixel.y)); 51 | 52 | // Pick from 4 green colors or 3 intermediate dither colors, based on color value. 53 | int ColorIndex = int(floor(Color.g * 7.0)); // 0-6. 54 | vec3 Green; 55 | // Green 0. 56 | if (ColorIndex == 0) { 57 | Green = GAMEBOY_0; 58 | // Green 0-1 (dither). 59 | } else if (ColorIndex == 1) { 60 | Green = dither(PixelX, PixelY, GAMEBOY_0, GAMEBOY_1); 61 | // Green 1. 62 | } else if (ColorIndex == 2) { 63 | Green = GAMEBOY_1; 64 | // Green 1-2 (dither). 65 | } else if (ColorIndex == 3) { 66 | Green = dither(PixelX, PixelY, GAMEBOY_1, GAMEBOY_2); 67 | // Green 2. 68 | } else if (ColorIndex == 4) { 69 | Green = GAMEBOY_2; 70 | // Green 2-3 (dither). 71 | } else if (ColorIndex == 5) { 72 | Green = dither(PixelX, PixelY, GAMEBOY_2, GAMEBOY_3); 73 | // Green 3. 74 | } else { 75 | Green = GAMEBOY_3; 76 | } 77 | 78 | // Output the green color. 79 | gl_FragColor = vec4(Green, 1.0f); 80 | } -------------------------------------------------------------------------------- /Gameboy Shader/shaders/final.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | void main() { 6 | gl_Position = ftransform(); // Essentially gl_ModelViewProjectionMatrix * gl_Vertex. 7 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate to vec2. 8 | } -------------------------------------------------------------------------------- /Greyscale Shader/shaders/README.md: -------------------------------------------------------------------------------- 1 | # Greyscale Shader 2 | 3 | This shader simply overrides the final pass to convert the color to greyscale. -------------------------------------------------------------------------------- /Greyscale Shader/shaders/final.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | uniform sampler2D colortex0; // Optifine's internal shader output (reimplementation of default MC shaders in Optifine's shader pipeline). 6 | 7 | void main() { 8 | // Sample the color. 9 | vec3 Color = texture2D(colortex0, TexCoords).rgb; 10 | 11 | // Convert to grayscale. 12 | Color = vec3(dot(Color, vec3(0.333f))); 13 | 14 | // Output the color. 15 | gl_FragColor = vec4(Color, 1.0f); 16 | } -------------------------------------------------------------------------------- /Greyscale Shader/shaders/final.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | void main() { 6 | gl_Position = ftransform(); // Essentially gl_ModelViewProjectionMatrix * gl_Vertex. 7 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate. 8 | } -------------------------------------------------------------------------------- /NES Shader/README.md: -------------------------------------------------------------------------------- 1 | # NES Shader 2 | 3 | This shader overrides the final pass to make the game look like an old NES screen. It accomplishes this by doing 3 things: 4 | 5 | 1. The shader limits the color output to the 54 colors, from the NES color palette, just like the old NES screens. 6 | * This is done by using the distance formula on each fragment color against each color in the palette. 7 | * Color codes were pulled from this [List of Video Game Console Palettes](https://en.wikipedia.org/wiki/list_of_video_game_console_palettes#NES) Wikipedia page. 8 | 3. The shader pixelates the screen so pixels are 4x the size, in order to emulate the low-resolution Gameboy screen and to make the dithering effect more apparent. 9 | -------------------------------------------------------------------------------- /NES Shader/shaders/final.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | uniform sampler2D colortex0; // Optifine's internal shader output (reimplementation of default MC shaders in Optifine's shader pipeline). 6 | 7 | uniform float viewWidth; 8 | uniform float viewHeight; 9 | 10 | // NES's 54 colors (technically the palette had 64, but there were 2 identical whites and 10 identical blacks for some reason). 11 | vec3[] NES_COLORS = { 12 | // White to grey to black. 13 | vec3(254, 254, 254) / vec3(255), 14 | vec3(184, 184, 184) / vec3(255), 15 | vec3(174, 174, 174) / vec3(255), 16 | vec3(102, 102, 102) / vec3(255), 17 | vec3(79, 79, 79) / vec3(255), 18 | vec3(0, 0, 0) / vec3(255), 19 | // Red (light to dark). 20 | vec3(254, 205, 198) / vec3(255), 21 | vec3(254, 130, 112) / vec3(255), 22 | vec3(181, 50, 32) / vec3(255), 23 | vec3(108, 7, 0) / vec3(255), 24 | // Orange (light to dark). 25 | vec3(247, 217, 166) / vec3(255), 26 | vec3(235, 159, 33) / vec3(255), 27 | vec3(153, 79, 0) / vec3(255), 28 | vec3(87, 29, 0) / vec3(255), 29 | // Yellow (light to dark). 30 | vec3(229, 230, 149) / vec3(255), 31 | vec3(189, 191, 0) / vec3(255), 32 | vec3(108, 110, 0) / vec3(255), 33 | vec3(52, 53, 0) / vec3(255), 34 | // Lime (light to dark). 35 | vec3(208, 240, 151) / vec3(255), 36 | vec3(137, 217, 0) / vec3(255), 37 | vec3(56, 135, 0) / vec3(255), 38 | vec3(12, 73, 0) / vec3(255), 39 | // Green (light to dark). 40 | vec3(190, 245, 171) / vec3(255), 41 | vec3(93, 229, 48) / vec3(255), 42 | vec3(13, 148, 0) / vec3(255), 43 | vec3(0, 82, 0) / vec3(255), 44 | // Teal (light to dark). 45 | vec3(180, 243, 205) / vec3(255), 46 | vec3(69, 225, 130) / vec3(255), 47 | vec3(0, 144, 50) / vec3(255), 48 | vec3(0, 79, 8) / vec3(255), 49 | // Cyan (light to dark). 50 | vec3(181, 236, 243) / vec3(255), 51 | vec3(72, 206, 223) / vec3(255), 52 | vec3(0, 124, 142) / vec3(255), 53 | vec3(0, 64, 78) / vec3(255), 54 | // Blue (light to dark). 55 | vec3(193, 224, 254) / vec3(255), 56 | vec3(100, 176, 254) / vec3(255), 57 | vec3(21, 95, 218) / vec3(255), 58 | vec3(0, 42, 136) / vec3(255), 59 | // Indigo (light to dark). 60 | vec3(212, 211, 254) / vec3(255), 61 | vec3(147, 144, 254) / vec3(255), 62 | vec3(66, 64, 254) / vec3(255), 63 | vec3(20, 18, 168) / vec3(255), 64 | // Purple (light to dark). 65 | vec3(233, 200, 254) / vec3(255), 66 | vec3(199, 119, 254) / vec3(255), 67 | vec3(118, 39, 255) / vec3(255), 68 | vec3(59, 0, 164) / vec3(255), 69 | // Magenta (light to dark). 70 | vec3(251, 195, 254) / vec3(255), 71 | vec3(243, 106, 254) / vec3(255), 72 | vec3(161, 27, 205) / vec3(255), 73 | vec3(92, 0, 126) / vec3(255), 74 | // Pink (light to dark). 75 | vec3(254, 197, 235) / vec3(255), 76 | vec3(254, 110, 205) / vec3(255), 77 | vec3(184, 30, 124) / vec3(255), 78 | vec3(110, 0, 64) / vec3(255) 79 | }; 80 | 81 | // Pixelation scale (1 is normal, 2 is double, 4 is quadruple, etc.). 82 | const int PIXEL_SCALE = 4; 83 | 84 | // Take an input color and output the closest NES color, 85 | // essentially limiting screen colors to the 54 NES palette colors. 86 | vec3 closestColor(vec3 color) { 87 | vec3 ClosestColor = NES_COLORS[0]; 88 | float ShortestDistance = 1000.0; 89 | for (int i = 0; i < 54; i++) { 90 | float Distance = distance(color, NES_COLORS[i]); 91 | //float Distance = length(dot(color - NES_COLORS[i], color - NES_COLORS[i])); // Identical to above (same performance too). 92 | if (Distance < ShortestDistance) { 93 | ShortestDistance = Distance; 94 | ClosestColor = NES_COLORS[i]; 95 | } 96 | } 97 | return ClosestColor; 98 | } 99 | 100 | void main() { 101 | // Pixelate the screen by a4 so pixels look larger (makes dithering more noticeable and the screen more like an old pixelated gameboy screen). 102 | vec2 PixelatedTexCoords = vec2(TexCoords.x, TexCoords.y); 103 | // The following few lines are a long way of modulating, since GLSL v2.1 has problems with mod() or % when floats are involved. 104 | // Convert texture coordinates to screen pixel coordinates, and floor them (just in case). 105 | int PX = int(PixelatedTexCoords.x * viewWidth / PIXEL_SCALE); 106 | int PY = int(PixelatedTexCoords.y * viewHeight / PIXEL_SCALE); 107 | // Convert pixel coordinates back up to texture coordinates (essentially modulating). 108 | PixelatedTexCoords.x = PX / viewWidth * PIXEL_SCALE; 109 | PixelatedTexCoords.y = PY / viewHeight * PIXEL_SCALE; 110 | 111 | // Sample the color. 112 | vec3 Color = texture2D(colortex0, PixelatedTexCoords).rgb; 113 | 114 | // Pick the closest color in the NES color palette. 115 | Color = closestColor(Color); 116 | 117 | // Output the green color. 118 | gl_FragColor = vec4(Color, 1.0); 119 | } -------------------------------------------------------------------------------- /NES Shader/shaders/final.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | 5 | void main() { 6 | gl_Position = ftransform(); // Essentially gl_ModelViewProjectionMatrix * gl_Vertex. 7 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate to vec2. 8 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MC Shader Exploration 2 | 3 | This repository holds some shaderpacks we made for for Minecraft. We followed this [tutorial](https://github.com/saada2006/MinecraftShaderProgramming) to learn how to write shaders, and then used what we learned to write more complicated shaders. 4 | 5 | There are additional README files in each shader's folder with more details on their implementation. 6 | 7 | ## Links 8 | 9 | * Based on this [tutorial](https://github.com/saada2006/MinecraftShaderProgramming). 10 | * Using [Minecraft Java Edition](https://www.minecraft.net/download) (no need to install this, though). 11 | * Using the third party Minecraft launcher, [MultiMC](https://multimc.org/#Download). 12 | * This is used because Windows broke Minecraft such that it can't run if your Windows Microsoft account doesn't match your Minecraft Microsoft account. 13 | * Using the [Optifine](https://optifine.net/downloads) mod for Minecraft (which adds shader support and extra graphical settings/options). 14 | 15 | ### Development 16 | 17 | * [Optifine Shaders Documentation](https://optifine.readthedocs.io/shaders_dev.html). 18 | 19 | ## Installations & Setup 20 | 21 | ### Downloads 22 | 23 | Download the following installers and files. 24 | 25 | 1. Download and install [MultiMC](https://multimc.org/#Download). 26 | 1. Download and install [Java 17](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html). 27 | 1. Download [Optine](https://optifine.net/downloads) for version `1.19.2`. 28 | 29 | ### Install Steps 30 | 31 | Follow these steps to install and setup Minecraft, MultiMC, and Optifine, to support shaders. 32 | 33 | 1. In the MultiMC _Settings_, under the _Java_ tab: 34 | 1. Set the _Minimum memory allocation_ to `512 MiB` and the _Maximum memory allocation_ to `4096 MiB`, to give Minecraft more RAM since shaders require more processing power than default Minecraft. 35 | 1. Under the _Java Runtime_ section, click _Auto-Detect_ and select the Java 17 version. 36 | 1. In MultiMC, click _Add Instance_ to create a Minecraft instance for version `1.19.2`. 37 | 1. In MultiMC, click on the _1.19.2_ instance and go to _Edit Instance_: 38 | 1. In the _Version_ tab, click _Install Forge_ and hit _OK_. 39 | 1. In the _Loader Mods_ tab, click _Add_ and select the Optifine `.jar` file downloaded earlier. 40 | 41 | ## Usage 42 | 43 | ### Using Shaders 44 | 45 | Launch the modified Minecraft 1.1.92 instance through MultiMC, after following the installation steps above. 46 | 47 | Create or open up a world and hit ESCAPE and go to _Options_ > _Video Settings..._ > _Shaders..._. Select the shader you'd like to play around with. I recommend switching the world from _Survival Mode_ to _Creative Mode_, so you can explore the shaders without worying about dying. 48 | 49 | There will be READMEs inside each shader folder, explaining in further detail what the shader does. 50 | 51 | ### Adding Shaders to Minecraft 52 | 53 | Shaders are added as folders or `.zip` files by clicking on the _1.19.2_ instance in MultiMC and goint to _Edit Instance_ > _Shader Packs_ > _Add_ and selecting one of the shaders from this repository. 54 | 55 | Feel free to download [BSL Shaders](https://www.bslshaders.com/download/) if you'd like an example of a fully developed shader that's used by the community. 56 | 57 | When making changes to a shader, you'll need to switch the selected shader in Minecraft to `OFF` and back, to tell Minecraft to reload the shader. 58 | -------------------------------------------------------------------------------- /World Curvature Shader/README.md: -------------------------------------------------------------------------------- 1 | # World Curvature Shader 2 | 3 | Add a vertex shader to give the impression that the world isn't flat and actually has curvature like the Earth. The shader currently applies to both entities and terrain. -------------------------------------------------------------------------------- /World Curvature Shader/shaders/gbuffers_entities.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | varying vec3 Normal; 5 | 6 | uniform sampler2D texture; // The block mesh texture (block meshes are combined into chunks). 7 | 8 | void main() { 9 | // Sample from texture atlas, then multiply by biome color, 10 | // (since vegatation, water, etc. are greyscale and then multiplied to be different shades of green basedon the biome). 11 | vec4 Albedo = texture2D(texture, TexCoords); 12 | 13 | // Declare access to draw buffers 0 and 1, 14 | // using a comment because of course Minecraft would code with comments. 15 | // Then draw to them. 16 | /* DRAWBUFFERS:01 */ 17 | gl_FragData[0] = Albedo; 18 | gl_FragData[1] = vec4(Normal * 0.5 + 0.5, 1.0); 19 | } -------------------------------------------------------------------------------- /World Curvature Shader/shaders/gbuffers_entities.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | #include "world_curvature.glsl" 3 | 4 | varying vec2 TexCoords; 5 | varying vec3 Normal; 6 | 7 | uniform mat4 gbufferModelView, gbufferModelViewInverse; // Used to undo and redo MVP matrices for the purpose of world curvature calculations. 8 | 9 | void main() { 10 | // Apply world curvature and set the vertex position. 11 | vec4 position = gbufferModelViewInverse * gl_ModelViewMatrix * gl_Vertex; 12 | position.y -= worldCurvature(position); 13 | gl_Position = gl_ProjectionMatrix * gbufferModelView * position; 14 | 15 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate. 16 | 17 | // gl_Normal is built-in attribute for world-space normal vector. 18 | // Transform normal from world-space to view-space. 19 | Normal = gl_NormalMatrix * gl_Normal; 20 | } -------------------------------------------------------------------------------- /World Curvature Shader/shaders/gbuffers_terrain.fsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | 3 | varying vec2 TexCoords; 4 | varying vec3 Normal; 5 | varying vec4 BiomeColor; // Water and foliage is greyscale and then colored based on the biome it is. 6 | 7 | uniform sampler2D texture; // The block mesh texture (block meshes are combined into chunks). 8 | 9 | void main() { 10 | // Sample from texture atlas, then multiply by biome color, 11 | // (since vegatation, water, etc. are greyscale and then multiplied to be different shades of green basedon the biome). 12 | vec4 Albedo = texture2D(texture, TexCoords) * BiomeColor; 13 | 14 | // Declare access to draw buffers 0 and 1, 15 | // using a comment because of course Minecraft would code with comments. 16 | // Then draw to them. 17 | /* DRAWBUFFERS:01 */ 18 | gl_FragData[0] = Albedo; 19 | gl_FragData[1] = vec4(Normal * 0.5 + 0.5, 1.0); 20 | } -------------------------------------------------------------------------------- /World Curvature Shader/shaders/gbuffers_terrain.vsh: -------------------------------------------------------------------------------- 1 | #version 120 2 | #include "world_curvature.glsl" 3 | 4 | varying vec2 TexCoords; 5 | varying vec3 Normal; 6 | varying vec4 BiomeColor; // Water and foliage is greyscale and then colored based on the biome it is. 7 | 8 | uniform mat4 gbufferModelView, gbufferModelViewInverse; // Used to undo and redo MVP matrices for the purpose of world curvature calculations. 9 | 10 | void main() { 11 | // Apply world curvature and set the vertex position. 12 | vec4 position = gbufferModelViewInverse * gl_ModelViewMatrix * gl_Vertex; 13 | position.y -= worldCurvature(position); 14 | gl_Position = gl_ProjectionMatrix * gbufferModelView * position; 15 | 16 | TexCoords = gl_MultiTexCoord0.st; // Vec4 texture coordinate. 17 | 18 | // gl_Normal is built-in attribute for world-space normal vector. 19 | // Transform normal from world-space to view-space. 20 | Normal = gl_NormalMatrix * gl_Normal; 21 | BiomeColor = gl_Color; 22 | } -------------------------------------------------------------------------------- /World Curvature Shader/shaders/shaders.properties: -------------------------------------------------------------------------------- 1 | # Disable unloading terrain when you look up at the sky, it doesn't unload when you have negative world curvature. 2 | frustum.culling=false -------------------------------------------------------------------------------- /World Curvature Shader/shaders/world_curvature.glsl: -------------------------------------------------------------------------------- 1 | const float WORLD_CURVATURE_SIZE = 256; 2 | 3 | float worldCurvature(vec4 position) 4 | { 5 | return dot(position.xz, position.xz) / WORLD_CURVATURE_SIZE; // World curvature formula. 6 | } --------------------------------------------------------------------------------