[READ-ONLY] Mirror of https://github.com/excaliburjs/sample-material. Excalibur Material & PostProcessor Shader Samples excaliburjs.com/sample-material/
excalibur excaliburjs glsl sample shaders
0

Configure Feed

Select the types of activity you want to include in your feed.

maybe done?

Erik Onarheim (Jan 19, 2025, 5:46 PM -0600) 0ab4bb72 2c22fa0b

+352 -428
+1
index.html
··· 12 12 <h1>Excalibur Shader Samples</h1> 13 13 <ul> 14 14 <li><a href="src/fire/index.html">Fire 🔥</a></li> 15 + <li><a href="src/outline/index.html">Outline 🌈</a></li> 15 16 <li><a href="src/grid/index.html">Grid 🪟</a></li> 16 17 <li><a href="src/star/index.html">Star ✨</a></li> 17 18 <li><a href="src/water/index.html">Water 💧</a></li>
+9 -2
src/files.d.ts
··· 1 - declare module "*.png"; 2 - declare module "*.glsl"; 1 + declare module '*.png' { 2 + const value: string; 3 + export default value; 4 + } 5 + 6 + declare module "*.glsl" { 7 + const value: string; 8 + export default value; 9 + }
+2 -1
src/fire/fire.ts
··· 7 7 const game = new Engine({ 8 8 width: 800, 9 9 height: 800, 10 - displayMode: DisplayMode.FitScreen 10 + displayMode: DisplayMode.FitScreen, 11 + suppressPlayButton: true 11 12 }); 12 13 13 14 const fireShader = glsl`#version 300 es
+1 -7
src/nebula/nebulal.ts
··· 11 11 in vec2 v_uv; 12 12 out vec4 fragColor; 13 13 14 - struct PointLight { 15 - vec2 pos; 16 - vec3 col; 17 - float intensity; 18 - }; 19 - 20 14 float palette( in float a, in float b, in float c, in float d, in float x ) { 21 15 return a + b * cos(6.28318 * (c * x + d)); 22 16 } 23 - 17 + 24 18 // 2D Noise from IQ 25 19 float Noise2D( in vec2 x ) 26 20 {
+13 -4
src/outline/outline.ts
··· 1 + import { Actor, Color, DisplayMode, Engine, ImageSource, Loader, Sprite } from 'excalibur'; 2 + import swordImg from './sword.png?url'; 3 + const sword = new ImageSource(swordImg); 4 + const loader = new Loader([sword]); 1 5 2 - const sword = new ex.ImageSource('https://cdn.rawgit.com/excaliburjs/Excalibur/7dd48128/assets/sword.png', false, ex.ImageFiltering.Pixel); 3 - const loader = new ex.Loader([sword]); 6 + const game = new Engine({ 7 + width: 800, 8 + height: 800, 9 + displayMode: DisplayMode.FitScreen, 10 + backgroundColor: Color.Black, 11 + suppressPlayButton: true 12 + }); 4 13 5 14 const outline = `#version 300 es 6 15 precision mediump float; ··· 49 58 }); 50 59 51 60 52 - const actor = new ex.Actor({ x: 100, y: 100, width: 50, height: 50 }); 61 + const actor = new Actor({ x: 100, y: 100, width: 50, height: 50 }); 53 62 actor.onInitialize = () => { 54 - var sprite = new ex.Sprite({ 63 + var sprite = new Sprite({ 55 64 image: sword, 56 65 destSize: { 57 66 width: 300,
src/outline/sword.png

This is a binary file and will not be displayed.

+253
src/star/other-star.glsl
··· 1 + #version 300 es 2 + precision highp float; 3 + 4 + in vec2 v_uv; 5 + 6 + uniform vec2 u_graphic_resolution; 7 + uniform float u_time_ms; 8 + float u_time = 0.; 9 + uniform vec4 u_color; 10 + uniform bool u_highlight; 11 + uniform float u_opacity; 12 + out vec4 fragColor; 13 + 14 + vec3 mod289(vec3 x) 15 + { 16 + return x - floor(x / 289.0) * 289.0; 17 + } 18 + 19 + vec4 mod289(vec4 x) 20 + { 21 + return x - floor(x / 289.0) * 289.0; 22 + } 23 + 24 + vec4 taylorInvSqrt(vec4 r) 25 + { 26 + return 1.79284291400159 - r * 0.85373472095314; 27 + } 28 + 29 + vec4 permute(vec4 x) 30 + { 31 + return mod289((x * 34.0 + 1.0) * x); 32 + } 33 + 34 + 35 + float inverseLerp(float v, float minValue, float maxValue) { 36 + return (v - minValue) / (maxValue - minValue); 37 + } 38 + 39 + float remap(float v, float inMin, float inMax, float outMin, float outMax) { 40 + float t = inverseLerp(v, inMin, inMax); 41 + return mix(outMin, outMax, t); 42 + } 43 + 44 + 45 + vec2 hash(vec2 p) // replace this by something better 46 + { 47 + p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3))); 48 + return -1.0 + 2.0 * fract(sin(p) * 43758.5453123); 49 + } 50 + 51 + vec4 snoise(vec3 v) 52 + { 53 + const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); 54 + 55 + // First corner 56 + vec3 i = floor(v + dot(v, vec3(C.y))); 57 + vec3 x0 = v - i + dot(i, vec3(C.x)); 58 + 59 + // Other corners 60 + vec3 g = step(x0.yzx, x0.xyz); 61 + vec3 l = 1.0 - g; 62 + vec3 i1 = min(g.xyz, l.zxy); 63 + vec3 i2 = max(g.xyz, l.zxy); 64 + 65 + vec3 x1 = x0 - i1 + C.x; 66 + vec3 x2 = x0 - i2 + C.y; 67 + vec3 x3 = x0 - 0.5; 68 + 69 + // Permutations 70 + i = mod289(i); // Avoid truncation effects in permutation 71 + vec4 p = 72 + permute(permute(permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) 73 + + i.y + vec4(0.0, i1.y, i2.y, 1.0)) 74 + + i.x + vec4(0.0, i1.x, i2.x, 1.0)); 75 + 76 + // Gradients: 7x7 points over a square, mapped onto an octahedron. 77 + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) 78 + vec4 j = p - 49.0 * floor(p / 49.0); // mod(p,7*7) 79 + 80 + vec4 x_ = floor(j / 7.0); 81 + vec4 y_ = floor(j - 7.0 * x_); 82 + 83 + vec4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0; 84 + vec4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0; 85 + 86 + vec4 h = 1.0 - abs(x) - abs(y); 87 + 88 + vec4 b0 = vec4(x.xy, y.xy); 89 + vec4 b1 = vec4(x.zw, y.zw); 90 + 91 + vec4 s0 = floor(b0) * 2.0 + 1.0; 92 + vec4 s1 = floor(b1) * 2.0 + 1.0; 93 + vec4 sh = -step(h, vec4(0.0)); 94 + 95 + vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; 96 + vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; 97 + 98 + vec3 g0 = vec3(a0.xy, h.x); 99 + vec3 g1 = vec3(a0.zw, h.y); 100 + vec3 g2 = vec3(a1.xy, h.z); 101 + vec3 g3 = vec3(a1.zw, h.w); 102 + 103 + // Normalize gradients 104 + vec4 norm = taylorInvSqrt(vec4(dot(g0, g0), dot(g1, g1), dot(g2, g2), dot(g3, g3))); 105 + g0 *= norm.x; 106 + g1 *= norm.y; 107 + g2 *= norm.z; 108 + g3 *= norm.w; 109 + 110 + // Compute noise and gradient at P 111 + vec4 m = max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); 112 + vec4 m2 = m * m; 113 + vec4 m3 = m2 * m; 114 + vec4 m4 = m2 * m2; 115 + vec3 grad = 116 + -6.0 * m3.x * x0 * dot(x0, g0) + m4.x * g0 + 117 + -6.0 * m3.y * x1 * dot(x1, g1) + m4.y * g1 + 118 + -6.0 * m3.z * x2 * dot(x2, g2) + m4.z * g2 + 119 + -6.0 * m3.w * x3 * dot(x3, g3) + m4.w * g3; 120 + vec4 px = vec4(dot(x0, g0), dot(x1, g1), dot(x2, g2), dot(x3, g3)); 121 + return 42.0 * vec4(grad, dot(m4, px)); 122 + } 123 + 124 + 125 + float fbm(vec3 p, int octaves, float persistence, float lacunarity, float exponentiation) { 126 + float amplitude = 0.5; 127 + float frequency = 1.0; 128 + float total = 0.0; 129 + float normalization = 0.0; 130 + 131 + for (int i = 0; i < 1000; ++i) { 132 + float noiseValue = snoise(p * frequency).w; 133 + total += noiseValue * amplitude; 134 + total += sin(u_time) * .015; 135 + normalization += amplitude; 136 + amplitude *= persistence; 137 + frequency *= lacunarity; 138 + if (i == (octaves - 1)) { 139 + break; 140 + } 141 + } 142 + 143 + total /= normalization; 144 + total = total * 0.5 + 0.5; 145 + total = pow(total, exponentiation); 146 + 147 + return total; 148 + } 149 + 150 + 151 + float sdfCircle(vec2 p, float r) { 152 + return length(p) - r; 153 + } 154 + 155 + 156 + float map(vec3 pos) { 157 + return fbm(pos, 6, 0.5, 2.0, 4.0); 158 + } 159 + 160 + vec3 calcNormal(vec3 pos, vec3 n) { 161 + vec2 e = vec2(0.0001, 0.0); 162 + return normalize( 163 + n + -500.0 * vec3( 164 + map(pos + e.xyy) - map(pos - e.xyy), 165 + map(pos + e.yxy) - map(pos - e.yxy), 166 + map(pos + e.yyx) - map(pos - e.yyx) 167 + ) 168 + ); 169 + } 170 + 171 + float simpleLimbDarkening(float cosTheta) 172 + { 173 + float ul = 0.45; //u lambda //.85 174 + float vl = 0.2; //v lambda //.2 175 + 176 + float sundisk = cosTheta; 177 + float limbfilt = 1.0 - ul - vl + ul * cos(asin(sundisk)) + vl * pow(cos(asin(sundisk)), 0.1); 178 + return limbfilt; 179 + } 180 + 181 + mat3 rotateY(float radians) { 182 + float s = sin(radians); 183 + float c = cos(radians); 184 + return mat3( 185 + c, 0.0, s, 186 + 0.0, 1.0, 0.0, 187 + -s, 0.0, c); 188 + } 189 + 190 + 191 + vec3 drawStar(vec2 pixelCoords, vec3 colour, float starSize, float d){ 192 + vec3 starColor = vec3(colour); 193 + float x = pixelCoords.x / starSize; 194 + float y = pixelCoords.y / starSize; 195 + float z = sqrt(1.0 - x * x - y * y); 196 + mat3 starRotation = rotateY(u_time * 0.25); 197 + 198 + vec3 viewNormal = vec3(x, y, z); 199 + vec3 wsPosition = starRotation * viewNormal; 200 + vec3 wsNormal = starRotation * normalize(wsPosition); 201 + vec3 noiseCoord = wsPosition * 2.0; 202 + float noiseSample = fbm(noiseCoord, 4, 0.5, 2.0, 4.0);// was 6 octaves 203 + starColor = vec3(noiseSample); 204 + float wrap = 0.05; 205 + 206 + //Colouring 207 + vec3 primaryStarColor = mix(colour, clamp(colour * 1.75, 0.0, 1.0), smoothstep(0.01, 0.2, noiseSample)); 208 + vec3 darkenedColor = mix(clamp(primaryStarColor * 0.9, 0.0, 1.0), clamp(primaryStarColor * 0.5, 0.0, 1.0), smoothstep(0.005, 0.1, noiseSample)); 209 + 210 + starColor = mix(darkenedColor, primaryStarColor, smoothstep(0.02, 0.03, noiseSample)); 211 + 212 + //Lighting 213 + vec3 wsLightDir = normalize(vec3(0.5, 1.0, 0.5)); 214 + vec3 wsSurfaceNormal = calcNormal(noiseCoord, wsNormal); 215 + float dp = max( 216 + 0.0, (dot(wsLightDir, wsSurfaceNormal) + wrap) / (1.0 + wrap)); 217 + 218 + //Darkening 219 + float sky = max(0.0, dot(vec2(x, y), vec2(x, y))); 220 + vec3 col = vec3(starColor); 221 + col = vec3(simpleLimbDarkening(sky)); 222 + starColor *= col; 223 + 224 + //colour = mix(colour, starColor, smoothstep(0.0, -1.0, d)); 225 + colour = mix(colour, starColor, smoothstep(0.1, 0.15, 1. - d)); 226 + 227 + return vec3(colour); 228 + } 229 + 230 + 231 + void main() { 232 + u_time = u_time_ms / 1000.; 233 + vec2 pixelCoords = (v_uv - 0.5) * u_graphic_resolution; 234 + float starSize = 175.0; 235 + float d = sdfCircle(pixelCoords, starSize); 236 + float distanceFalloff = 1.0 / (d / 1000.0); 237 + distanceFalloff *= 0.0525; 238 + distanceFalloff = pow(distanceFalloff, 0.9); 239 + 240 + if (d <= 0.0) { 241 + 242 + fragColor = vec4(drawStar(pixelCoords, u_color.rgb, starSize, d) * u_opacity, step(0.0, -d - 1.0)); 243 + fragColor.a = u_opacity * fragColor.a; 244 + 245 + } else if (d <= starSize * 3.0 && u_highlight) { 246 + vec3 newCol = u_color.rgb * distanceFalloff; 247 + //(0.6*distanceFalloff) 248 + float alpha = u_opacity * smoothstep(0.2, 1.0, (0.6 * distanceFalloff)); 249 + fragColor = vec4(newCol, alpha); 250 + fragColor.rgb = fragColor.rgb * fragColor.a * u_opacity; 251 + 252 + } 253 + }
-254
src/star/other-star.ts
··· 1 - 2 - export const starFrag = `#version 300 es 3 - precision highp float; 4 - 5 - in vec2 v_uv; 6 - 7 - uniform vec2 U_resolution; 8 - uniform float U_time; 9 - uniform vec3 U_color; 10 - uniform bool U_highlight; 11 - out vec4 fragColor; 12 - uniform float u_opacity; 13 - 14 - vec3 mod289(vec3 x) 15 - { 16 - return x - floor(x / 289.0) * 289.0; 17 - } 18 - 19 - vec4 mod289(vec4 x) 20 - { 21 - return x - floor(x / 289.0) * 289.0; 22 - } 23 - 24 - vec4 taylorInvSqrt(vec4 r) 25 - { 26 - return 1.79284291400159 - r * 0.85373472095314; 27 - } 28 - 29 - vec4 permute(vec4 x) 30 - { 31 - return mod289((x * 34.0 + 1.0) * x); 32 - } 33 - 34 - 35 - float inverseLerp(float v, float minValue, float maxValue) { 36 - return (v - minValue) / (maxValue - minValue); 37 - } 38 - 39 - float remap(float v, float inMin, float inMax, float outMin, float outMax) { 40 - float t = inverseLerp(v, inMin, inMax); 41 - return mix(outMin, outMax, t); 42 - } 43 - 44 - 45 - vec2 hash( vec2 p ) // replace this by something better 46 - { 47 - p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) ); 48 - return -1.0 + 2.0*fract(sin(p)*43758.5453123); 49 - } 50 - 51 - vec4 snoise(vec3 v) 52 - { 53 - const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); 54 - 55 - // First corner 56 - vec3 i = floor(v + dot(v, vec3(C.y))); 57 - vec3 x0 = v - i + dot(i, vec3(C.x)); 58 - 59 - // Other corners 60 - vec3 g = step(x0.yzx, x0.xyz); 61 - vec3 l = 1.0 - g; 62 - vec3 i1 = min(g.xyz, l.zxy); 63 - vec3 i2 = max(g.xyz, l.zxy); 64 - 65 - vec3 x1 = x0 - i1 + C.x; 66 - vec3 x2 = x0 - i2 + C.y; 67 - vec3 x3 = x0 - 0.5; 68 - 69 - // Permutations 70 - i = mod289(i); // Avoid truncation effects in permutation 71 - vec4 p = 72 - permute(permute(permute(i.z + vec4(0.0, i1.z, i2.z, 1.0)) 73 - + i.y + vec4(0.0, i1.y, i2.y, 1.0)) 74 - + i.x + vec4(0.0, i1.x, i2.x, 1.0)); 75 - 76 - // Gradients: 7x7 points over a square, mapped onto an octahedron. 77 - // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) 78 - vec4 j = p - 49.0 * floor(p / 49.0); // mod(p,7*7) 79 - 80 - vec4 x_ = floor(j / 7.0); 81 - vec4 y_ = floor(j - 7.0 * x_); 82 - 83 - vec4 x = (x_ * 2.0 + 0.5) / 7.0 - 1.0; 84 - vec4 y = (y_ * 2.0 + 0.5) / 7.0 - 1.0; 85 - 86 - vec4 h = 1.0 - abs(x) - abs(y); 87 - 88 - vec4 b0 = vec4(x.xy, y.xy); 89 - vec4 b1 = vec4(x.zw, y.zw); 90 - 91 - vec4 s0 = floor(b0) * 2.0 + 1.0; 92 - vec4 s1 = floor(b1) * 2.0 + 1.0; 93 - vec4 sh = -step(h, vec4(0.0)); 94 - 95 - vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy; 96 - vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww; 97 - 98 - vec3 g0 = vec3(a0.xy, h.x); 99 - vec3 g1 = vec3(a0.zw, h.y); 100 - vec3 g2 = vec3(a1.xy, h.z); 101 - vec3 g3 = vec3(a1.zw, h.w); 102 - 103 - // Normalize gradients 104 - vec4 norm = taylorInvSqrt(vec4(dot(g0, g0), dot(g1, g1), dot(g2, g2), dot(g3, g3))); 105 - g0 *= norm.x; 106 - g1 *= norm.y; 107 - g2 *= norm.z; 108 - g3 *= norm.w; 109 - 110 - // Compute noise and gradient at P 111 - vec4 m = max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); 112 - vec4 m2 = m * m; 113 - vec4 m3 = m2 * m; 114 - vec4 m4 = m2 * m2; 115 - vec3 grad = 116 - -6.0 * m3.x * x0 * dot(x0, g0) + m4.x * g0 + 117 - -6.0 * m3.y * x1 * dot(x1, g1) + m4.y * g1 + 118 - -6.0 * m3.z * x2 * dot(x2, g2) + m4.z * g2 + 119 - -6.0 * m3.w * x3 * dot(x3, g3) + m4.w * g3; 120 - vec4 px = vec4(dot(x0, g0), dot(x1, g1), dot(x2, g2), dot(x3, g3)); 121 - return 42.0 * vec4(grad, dot(m4, px)); 122 - } 123 - 124 - 125 - float fbm(vec3 p, int octaves, float persistence, float lacunarity, float exponentiation) { 126 - float amplitude = 0.5; 127 - float frequency = 1.0; 128 - float total = 0.0; 129 - float normalization = 0.0; 130 - 131 - for (int i = 0; i < 1000; ++i) { 132 - float noiseValue = snoise(p * frequency).w; 133 - total += noiseValue * amplitude; 134 - total += sin(U_time)*.015; 135 - normalization += amplitude; 136 - amplitude *= persistence; 137 - frequency *= lacunarity; 138 - if(i==(octaves-1)){ 139 - break; 140 - } 141 - } 142 - 143 - total /= normalization; 144 - total = total * 0.5 + 0.5; 145 - total = pow(total, exponentiation); 146 - 147 - return total; 148 - } 149 - 150 - 151 - float sdfCircle(vec2 p, float r) { 152 - return length(p) - r; 153 - } 154 - 155 - 156 - float map(vec3 pos) { 157 - return fbm(pos, 6, 0.5, 2.0, 4.0); 158 - } 159 - 160 - vec3 calcNormal(vec3 pos, vec3 n) { 161 - vec2 e = vec2(0.0001, 0.0); 162 - return normalize( 163 - n + -500.0 * vec3( 164 - map(pos + e.xyy) - map(pos - e.xyy), 165 - map(pos + e.yxy) - map(pos - e.yxy), 166 - map(pos + e.yyx) - map(pos - e.yyx) 167 - ) 168 - ); 169 - } 170 - 171 - float simpleLimbDarkening(float cosTheta) 172 - { 173 - float ul = 0.45; //u lambda //.85 174 - float vl = 0.2; //v lambda //.2 175 - 176 - float sundisk = cosTheta; 177 - float limbfilt = 1.0 - ul - vl + ul*cos(asin(sundisk)) + vl*pow(cos(asin(sundisk)),0.1); 178 - return limbfilt; 179 - } 180 - 181 - mat3 rotateY(float radians) { 182 - float s = sin(radians); 183 - float c = cos(radians); 184 - return mat3( 185 - c, 0.0, s, 186 - 0.0, 1.0, 0.0, 187 - -s, 0.0, c); 188 - } 189 - 190 - 191 - vec3 drawStar(vec2 pixelCoords, vec3 colour, float starSize, float d){ 192 - vec3 starColor = vec3(colour); 193 - float x = pixelCoords.x/starSize; 194 - float y = pixelCoords.y/starSize; 195 - float z = sqrt(1.0 - x * x - y * y); 196 - mat3 starRotation = rotateY(U_time * 0.25); 197 - 198 - vec3 viewNormal = vec3(x, y, z); 199 - vec3 wsPosition = starRotation * viewNormal; 200 - vec3 wsNormal = starRotation* normalize(wsPosition); 201 - vec3 noiseCoord = wsPosition * 2.0; 202 - float noiseSample = fbm(noiseCoord, 4, 0.5, 2.0, 4.0);// was 6 octaves 203 - starColor = vec3(noiseSample); 204 - float wrap = 0.05; 205 - 206 - //Colouring 207 - vec3 primaryStarColor = mix(colour, clamp(colour * 1.75, 0.0, 1.0), smoothstep(0.01,0.2,noiseSample)); 208 - vec3 darkenedColor = mix( clamp(primaryStarColor * 0.9, 0.0, 1.0),clamp(primaryStarColor * 0.5, 0.0, 1.0),smoothstep(0.005,0.1,noiseSample)); 209 - 210 - starColor = mix(darkenedColor, primaryStarColor, smoothstep(0.02, 0.03, noiseSample)); 211 - 212 - //Lighting 213 - vec3 wsLightDir = normalize(vec3(0.5, 1.0, 0.5)); 214 - vec3 wsSurfaceNormal = calcNormal(noiseCoord, wsNormal); 215 - float dp = max( 216 - 0.0, (dot(wsLightDir, wsSurfaceNormal) + wrap) / (1.0 + wrap)); 217 - 218 - //Darkening 219 - float sky = max(0.0, dot(vec2(x,y),vec2(x,y))); 220 - vec3 col = vec3(starColor); 221 - col = vec3(simpleLimbDarkening(sky)); 222 - starColor *= col; 223 - 224 - //colour = mix(colour, starColor, smoothstep(0.0, -1.0, d)); 225 - colour = mix(colour, starColor, smoothstep( 0.1, 0.15, 1. - d)); 226 - 227 - return vec3(colour); 228 - } 229 - 230 - 231 - 232 - void main() { 233 - vec2 pixelCoords = (v_uv - 0.5) * U_resolution; 234 - float starSize = 175.0; 235 - float d = sdfCircle(pixelCoords,starSize); 236 - float distanceFalloff = 1.0/(d/1000.0); 237 - distanceFalloff*=0.0525; 238 - distanceFalloff = pow(distanceFalloff,0.9); 239 - 240 - if(d<=0.0){ 241 - 242 - fragColor = vec4(drawStar(pixelCoords, U_color, starSize, d)*u_opacity, step(0.0,-d-1.0)); 243 - fragColor.a = u_opacity * fragColor.a; 244 - 245 - } else if (d <= starSize*3.0 && U_highlight) { 246 - vec3 newCol = vec3(U_color)*distanceFalloff; 247 - //(0.6*distanceFalloff) 248 - float alpha = u_opacity * smoothstep(0.2,1.0, (0.6*distanceFalloff)); 249 - fragColor = vec4(newCol, alpha); 250 - fragColor.rgb = fragColor.rgb * fragColor.a*u_opacity; 251 - 252 - } 253 - 254 - }`;
+13 -3
src/star/star.ts
··· 2 2 import * as ex from 'excalibur'; 3 3 import { PerlinDrawer2D, PerlinGenerator } from '@excaliburjs/plugin-perlin'; 4 4 import { glsl } from '../glsl'; 5 + //import otherStar from './other-star.glsl?raw'; // ?raw pragma to get string source of the shader 5 6 6 7 const game = new ex.Engine({ 7 8 width: 800, ··· 80 81 const noiseImage = drawer.image(800, 800); 81 82 await noiseImage.decode(); 82 83 // Show the generated noise 83 - document.body.appendChild(noiseImage); 84 + //document.body.appendChild(noiseImage); 84 85 game.input.pointers.on('down', (evt) => { 85 86 game.add(generateStar(evt.worldPos, noiseImage)) 86 87 }); 87 - 88 - 88 + //const startStar = new ex.Actor({ 89 + // pos: ex.vec(400, 400), 90 + // radius: 200, 91 + // color: ex.Color.Red, 92 + // collisionType: ex.CollisionType.Active 93 + //}); 94 + //startStar.graphics.material = game.graphicsContext.createMaterial({ 95 + // fragmentSource: otherStar 96 + //}); 97 + //game.add(startStar); 98 + // 89 99 const floor = new ex.Actor({ 90 100 pos: ex.vec(0, 600), 91 101 anchor: ex.vec(0, 0),
+1 -1
src/water/index.html
··· 4 4 <head> 5 5 <meta charset="UTF-8"> 6 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 - <title>Document</title> 7 + <title>Water Reflection Using Screen Texture</title> 8 8 <link rel="stylesheet" href="../style.css"> 9 9 </head> 10 10
src/water/noise.avif

This is a binary file and will not be displayed.

src/water/stars.png

This is a binary file and will not be displayed.

src/water/sword.png

This is a binary file and will not be displayed.

+59 -156
src/water/water.ts
··· 1 1 2 2 // identity tagged template literal lights up glsl-literal vscode plugin 3 3 4 - import { Actor, Color, CoordPlane, DisplayMode, Engine, ImageFiltering, ImageSource, Loader, ScreenElement, Sprite, vec } from "excalibur"; 5 - import { glsl } from "./glsl"; 4 + import { Actor, Color, CoordPlane, DisplayMode, Engine, ImageFiltering, ImageSource, ImageWrapping, Loader, ScreenElement, Sprite, TiledSprite, vec } from "excalibur"; 5 + import { glsl } from "../glsl"; 6 + import swordImg from "./sword.png?url"; 7 + import starImg from './stars.png?url'; 6 8 7 - var game = new Engine({ 8 - canvasElementId: 'game', 9 - width: 512, 10 - height: 512, 11 - displayMode: DisplayMode.FitScreenAndFill, 12 - backgroundColor: Color.Black, 13 - antialiasing: true 9 + const game = new Engine({ 10 + width: 800, 11 + height: 800, 12 + displayMode: DisplayMode.FitScreenAndFill, 13 + backgroundColor: Color.Black, 14 + suppressPlayButton: true, 15 + antialiasing: true 14 16 }); 15 17 16 - var tex = new ImageSource('https://cdn.rawgit.com/excaliburjs/Excalibur/7dd48128/assets/sword.png', false, ImageFiltering.Pixel); 17 - var heartImage = new ImageSource('./heart.png', false, ImageFiltering.Pixel); 18 - var background = new ImageSource('./stars.png', false, ImageFiltering.Blended); 19 - 20 - var loader = new Loader([tex, heartImage, background]); 21 - 22 - var outline = glsl`#version 300 es 23 - precision mediump float; 24 - 25 - uniform float u_time_ms; 26 - uniform sampler2D u_graphic; 27 - 28 - in vec2 v_uv; 29 - in vec2 v_screenuv; 30 - out vec4 fragColor; 31 - 32 - vec3 hsv2rgb(vec3 c){ 33 - vec4 K=vec4(1.,2./3.,1./3.,3.); 34 - return c.z*mix(K.xxx,clamp(abs(fract(c.x+K.xyz)*6.-K.w)-K.x, 0., 1.),c.y); 35 - } 36 - 37 - void main() { 38 - const float TAU = 6.28318530; 39 - const float steps = 4.0; // up/down/left/right pixels 40 - float radius = 2.0; 41 - float time_sec = u_time_ms / 1000.; 42 - 43 - vec3 outlineColorHSL = vec3(sin(time_sec/2.0) * 1., 1., 1.); 44 - vec2 aspect = 1.0 / vec2(textureSize(u_graphic, 0)); 45 - 46 - for (float i = 0.0; i < TAU; i += TAU / steps) { 47 - // Sample image in a circular pattern 48 - vec2 offset = vec2(sin(i), cos(i)) * aspect * radius; 49 - vec4 col = texture(u_graphic, v_uv + offset); 50 - 51 - // Mix outline with background 52 - float alpha = smoothstep(0.5, 0.7, col.a); 53 - fragColor = mix(fragColor, vec4(hsv2rgb(outlineColorHSL), 1.0), alpha); // apply outline 54 - } 55 - 56 - // Overlay original texture 57 - vec4 mat = texture(u_graphic, v_uv); 58 - float factor = smoothstep(0.5, 0.7, mat.a); 59 - fragColor = mix(fragColor, mat, factor); 60 - } 61 - `; 62 - 63 - var fragmentSource = glsl`#version 300 es 64 - precision mediump float; 65 - 66 - // UV coord 67 - in vec2 v_uv; 68 - 69 - uniform sampler2D u_graphic; 70 - 71 - uniform vec2 u_resolution; 72 - 73 - uniform float u_time_ms; 74 - 75 - uniform vec2 iMouse; 76 - 77 - uniform vec2 u_size; 78 - 79 - uniform vec4 u_color; 18 + const tex = new ImageSource(swordImg, false, ImageFiltering.Pixel); 19 + const background = new ImageSource(starImg, { 20 + filtering: ImageFiltering.Blended, 21 + wrapping: ImageWrapping.Repeat 22 + }); 80 23 81 - uniform float u_opacity; 24 + const loader = new Loader([tex, background]); 82 25 83 - out vec4 fragColor; 84 - 85 - void main() { 86 - vec4 color = u_color; 87 - float time_sec = u_time_ms / 1000.; 88 - float effectRadius = .5; 89 - float effectAngle = mod(time_sec/2., 2.) * 3.14159; 90 - 91 - vec2 size = u_size.xy; 92 - vec2 center = iMouse.xy / u_size.xy; 93 - vec2 uv = v_uv.xy - center; 94 - 95 - float len = length(uv * vec2(size.x / size.y, 1.)); 96 - float angle = atan(uv.y, uv.x) + effectAngle * smoothstep(effectRadius, 0., len); 97 - float radius = length(uv); 98 - vec2 newUv = vec2(radius * cos(angle), radius * sin(angle)) + center; 99 - color = texture(u_graphic, newUv); 100 - color.rgb = color.rgb * u_opacity; 101 - color.a = color.a * u_opacity; 102 - 103 - fragColor = color * u_color; 104 - } 105 - `; 106 - 107 - var swirlMaterial = game.graphicsContext.createMaterial({ 108 - name: 'swirl', 109 - fragmentSource 110 - }); 111 - 112 - var click = vec(0, 0); 26 + let click = vec(0, 0); 113 27 114 28 game.input.pointers.primary.on('down', (evt) => { 115 - click = evt.worldPos; // might need to change if you have a camera 29 + click = evt.worldPos; // might need to change if you have a camera 116 30 }); 117 31 118 - var outlineMaterial = game.graphicsContext.createMaterial({ 119 - name: 'outline', 120 - fragmentSource: outline 121 - }); 122 32 123 - var actor = new Actor({ x: 100, y: 100, width: 50, height: 50 }); 33 + const actor = new Actor({ x: 100, y: 100, width: 50, height: 50 }); 124 34 actor.onInitialize = () => { 125 - var sprite = new Sprite({ 126 - image: tex, 127 - destSize: { 128 - width: 300, 129 - height: 300 130 - } 131 - }); 132 - actor.graphics.add(sprite); 133 - }; 134 - actor.graphics.material = outlineMaterial; 135 - 136 - var heartActor = new Actor({ x: 200, y: 200 }); 137 - heartActor.onInitialize = () => { 138 - var sprite = heartImage.toSprite(); 139 - sprite.scale = vec(4, 4); 140 - heartActor.graphics.add(sprite); 141 - heartActor.graphics.material = outlineMaterial; 35 + const sprite = new Sprite({ 36 + image: tex, 37 + destSize: { 38 + width: 300, 39 + height: 300 40 + } 41 + }); 42 + actor.graphics.add(sprite); 142 43 }; 143 44 144 - game.add(heartActor); 145 45 146 46 game.input.pointers.primary.on('move', (evt) => { 147 - heartActor.pos = evt.worldPos; 148 - swirlMaterial.update((shader) => { 149 - shader.trySetUniformFloatVector('iMouse', evt.worldPos); 150 - }); 47 + actor.pos = evt.worldPos; 151 48 }); 152 49 153 - var backgroundActor = new ScreenElement({ x: 0, y: 0, width: 512, height: 512, z: -1 }); 50 + const backgroundActor = new ScreenElement({ 51 + x: game.screen.unsafeArea.left, 52 + y: game.screen.unsafeArea.top, 53 + width: 800, 54 + height: 800, 55 + z: -1 56 + }); 154 57 155 58 backgroundActor.onInitialize = () => { 156 - backgroundActor.graphics.add(background.toSprite()); 157 - backgroundActor.graphics.material = swirlMaterial; 59 + const bgSprite = new TiledSprite({ 60 + image: background, 61 + width: 1000, 62 + height: 1000 63 + }); 64 + backgroundActor.graphics.add(bgSprite); 158 65 }; 159 66 160 - // material without graphic!? 161 - var waterFrag = glsl`#version 300 es 67 + const waterFrag = glsl`#version 300 es 162 68 precision mediump float; 163 69 164 70 #define NUM_NOISE_OCTAVES 20 ··· 269 175 const noise = new ImageSource('./noise.avif', false, ImageFiltering.Pixel); 270 176 loader.addResource(noise); 271 177 272 - var waterMaterial = game.graphicsContext.createMaterial({ 273 - name: 'water', 274 - fragmentSource: waterFrag, 275 - color: Color.fromRGB(55, 0, 200, 0.6), 276 - images: { 277 - u_noise: noise 278 - } 178 + const waterMaterial = game.graphicsContext.createMaterial({ 179 + name: 'water', 180 + fragmentSource: waterFrag, 181 + color: Color.fromRGB(55, 0, 200, 0.6), 182 + images: { 183 + u_noise: noise 184 + } 279 185 }); 280 - var reflection = new Actor({ 281 - x: 0, 282 - y: game.screen.resolution.height / 2, 283 - anchor: vec(0, 0), 284 - width: 512, 285 - height: game.screen.resolution.height / 2, 286 - coordPlane: CoordPlane.Screen, 287 - color: Color.Red 186 + const reflection = new Actor({ 187 + x: game.screen.unsafeArea.left, 188 + y: game.screen.resolution.height / 2, 189 + anchor: vec(0, 0), 190 + width: 1000, 191 + height: 600, 192 + coordPlane: CoordPlane.Screen, 193 + color: Color.Red 288 194 }); 289 195 290 196 reflection.graphics.material = waterMaterial; ··· 294 200 game.add(backgroundActor); 295 201 game.add(reflection); 296 202 297 - game.start(loader).then(async () => { 298 - // const image = await game.screenshot(true); 299 - // document.body.appendChild(image); 300 - }); 203 + game.start(loader);