├── input.js ├── README.md ├── index.css ├── index.html ├── LICENSE ├── pillar.js ├── pillar2.js ├── bridge.js ├── player.js ├── gamerendering.js ├── main.js └── gamelibs.js /input.js: -------------------------------------------------------------------------------- 1 | let keyPressed = []; 2 | 3 | onkeydown = (e) => { 4 | keyPressed[e.key] = true; 5 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # btstu 2 | 3 | try to run it with chrome?? I haven't tried it with other browsers but i know it works on chrome on my mac. 4 | 5 | https://cartersemrad.github.io/btstu/ 6 | -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | body{ 2 | margin: 0px; 3 | padding: 0px; 4 | } 5 | 6 | canvas{ 7 | width: 100%; 8 | height: 100%; 9 | position: absolute; 10 | top: 0%; 11 | left: 0%; 12 | } -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | that ship was the love of my life 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 CarterSemrad 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pillar.js: -------------------------------------------------------------------------------- 1 | function Pillar(){ 2 | this.posUniName = "pillarpos"; 3 | this.pos = [0,0,0]; 4 | 5 | this.deIdentifier = "pillarde"; 6 | 7 | this.initUnis = () => { 8 | renderer.addUniform(this.posUniName, "vec3", this.pos); 9 | } 10 | 11 | this.graphicsDE = `float pillarde(vec3 p){ 12 | if(length(p.xz) > 7.){ 13 | return length(p.xz)-5.; 14 | } 15 | 16 | vec3 objectu_sizez11z = vec3(0.4,3.,0.4); 17 | float objectstatement0 = length((mod(twist(p,0.06000000000000005), vec3(0., 2., 0.)) - vec3(0., 2., 0.)/2.) - vec3(0., 0., 0.)) - -3.3; 18 | float objectstatement1 = sdBox((mod(twist(p,0.06000000000000005), vec3(0., 2., 0.)) - vec3(0., 2., 0.)/2.)-vec3(-2., -0.02, 0.), vec3(0.5, 1.1800000000000006, 0.5)); 19 | float objectstatement2 = sdBox((mod(twist(p,0.06000000000000005), vec3(0., 2., 0.)) - vec3(0., 2., 0.)/2.)-vec3(2., 0., 0.), vec3(0.35999999999999993, 1.3000000000000007, 0.5)); 20 | float objectstatement3 = sdBox((mod(twist(p,0.06000000000000005), vec3(0., 2., 0.)) - vec3(0., 2., 0.)/2.)-vec3(0., 0., 2.), vec3(0.41999999999999993, 1.1800000000000006, 0.5)); 21 | float objectstatement4 = sdBox((mod(twist(p,0.06000000000000005), vec3(0., 2., 0.)) - vec3(0., 2., 0.)/2.)-vec3(0., 0., -2.), objectu_sizez11z); 22 | float objectunion0 = max(smin(smin(smin(smin(objectstatement0, objectstatement1, 0.2), objectstatement2, 0.2), objectstatement3, 0.2), objectstatement4, 0.2), -9999.0); 23 | return objectunion0; 24 | }`; 25 | } -------------------------------------------------------------------------------- /pillar2.js: -------------------------------------------------------------------------------- 1 | function Pillar2(){ 2 | this.posUniName = "pillar2pos"; 3 | this.pos = [0,0,0]; 4 | 5 | this.deIdentifier = "pillar2de"; 6 | 7 | this.initUnis = () => { 8 | renderer.addUniform(this.posUniName, "vec3", this.pos); 9 | } 10 | 11 | this.graphicsDE = `float pillar2de(vec3 p){ 12 | if(length(p.xz) > 7.){ 13 | return length(p.xz) - 5.; 14 | } 15 | vec3 objectu_sizez5z = vec3(3., 0.4, .4); 16 | float objectstatement0 = length((mod(twist(p,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.) - vec3(0., 0., 0.)) - -3.3; 17 | float objectstatement1 = sdBox((mod(twist(p,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.)-vec3(-2., -0.02, 0.), objectu_sizez5z); 18 | float objectstatement2 = sdBox((mod(twist(p,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.)-vec3(2., 0., 0.), vec3(0.35999999999999993, 1.3000000000000007, 0.5)); 19 | float objectstatement3 = sdBox((mod(twist(p,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.)-vec3(0., 0., 2.), vec3(0.41999999999999993, 1.740000000000001, 0.3999999999999999)); 20 | float objectstatement4 = sdBox((mod(twist(p,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.)-vec3(0., 0., -2.), vec3(0.45999999999999996, 2.1600000000000015, 0.43999999999999995)); 21 | float objectunion0 = max(smin(smin(smin(smin(objectstatement0, objectstatement1, 0.2), objectstatement2, 0.2), objectstatement3, 0.2), objectstatement4, 0.2), -9999.0); 22 | return objectunion0; 23 | }`; 24 | } -------------------------------------------------------------------------------- /bridge.js: -------------------------------------------------------------------------------- 1 | function Bridge(){ 2 | this.posUniName = "bridgepos"; 3 | this.pos = [0,0,0]; 4 | 5 | this.deIdentifier = "bridgede"; 6 | 7 | this.initUnis = () => { 8 | renderer.addUniform(this.posUniName, "vec3", this.pos); 9 | } 10 | 11 | this.graphicsDE = `float bridgede(vec3 p){ 12 | if(length(p.yz) > 15.){ 13 | return length(p.yz) - 10.; 14 | } 15 | 16 | vec3 objectu_positionz18z = vec3(0.,.7,-4.4); 17 | 18 | float objectstatement0 = length((mod(p, vec3(4.620000000000022, 0., 0.)) - vec3(4.620000000000022, 0., 0.)/2.) - vec3(0., 0., 0.)) - -3.280000000000003; 19 | float objectstatement1 = sdBox((mod(p, vec3(4.620000000000022, 0., 0.)) - vec3(4.620000000000022, 0., 0.)/2.)-vec3(0., 0., 0.), vec3(5.399999999999992, 0.5, 4.400000000000001)); 20 | float objectstatement2 = sdBox((mod(p, vec3(4.620000000000022, 0., 0.)) - vec3(4.620000000000022, 0., 0.)/2.)-vec3(-0.7101762348101999, 0.16033200924318505, -3.1072626569818413), vec3(1.0400000000000005, 0.5, 0.6600000000000001)); 21 | float objectstatement3 = sdBox((mod(p, vec3(4.620000000000022, 0., 0.)) - vec3(4.620000000000022, 0., 0.)/2.)-vec3(-0.9099252306409606, 0.16053760227478173, -0.7118880851909671), vec3(0.5, 0.5, 1.0800000000000007)); 22 | float objectstatement4 = sdBox((mod(p, vec3(4.620000000000022, 0., 0.)) - vec3(4.620000000000022, 0., 0.)/2.)-vec3(-1.1424903583910957, 0.2004187827721106, 2.6000568155890202), vec3(0.6000000000000001, 0.5, 0.5399999999999996)); 23 | float objectstatement5 = sdBox((mod(p, vec3(4.620000000000022, 0., 0.)) - vec3(4.620000000000022, 0., 0.)/2.)-vec3(1.2545616717106394, 0.20003153738629234, 1.467790545261569), vec3(0.8000000000000003, 0.5, 0.6600000000000001)); 24 | float objectstatement6 = sdBox((mod(p, vec3(4.620000000000022, 0., 0.)) - vec3(4.620000000000022, 0., 0.)/2.)-vec3(9.224466890536453, 15.487403615205599, -0.3487322537442599), vec3(0.5, 0.5, 0.5)); 25 | float objectstatement7 = sdBox((mod(p, vec3(4.620000000000022, 0., 0.)) - vec3(4.620000000000022, 0., 0.)/2.)-objectu_positionz18z, vec3(1.8200000000000007, 0.7400000000000002, 0.09999999999999984)); 26 | float objectunion0 = max(smin(smin(smin(smin(smin(smin(smin(objectstatement0, objectstatement1, 0.2), objectstatement2, 0.2), objectstatement3, 0.2), objectstatement4, 0.2), objectstatement5, 0.2), objectstatement6, 0.2), objectstatement7, 0.2), -9999.0); 27 | return objectunion0; 28 | }`; 29 | } -------------------------------------------------------------------------------- /player.js: -------------------------------------------------------------------------------- 1 | function Player(){ 2 | 3 | this.posUniName = "playerpos"; 4 | this.pos = [0,0,0]; 5 | 6 | this.z = 0; 7 | this.x = 15; 8 | this.dead = false; 9 | 10 | let lanes = [-3, 0, 3]; 11 | this.lane = 1; 12 | 13 | this.update = () => { 14 | if(keyPressed["d"]){ 15 | if(this.lane > 0){ 16 | this.lane--; 17 | } 18 | } 19 | 20 | if(keyPressed["a"]){ 21 | if(this.lane < 2){ 22 | this.lane++; 23 | } 24 | } 25 | 26 | this.x = camPos[0] + 15; 27 | //mod(p.x/5., 1.) > 0.7 28 | 29 | //console.log(obstacles(this.x / 5)); 30 | 31 | if(2 - this.lane == obstacles(this.x / 5) && mod(this.x / 5, 1) > 0.7){ 32 | this.dead = true; 33 | } 34 | 35 | this.z = lerp(this.z, lanes[this.lane], 15*dt); 36 | } 37 | 38 | this.deIdentifier = "playerde"; 39 | 40 | this.graphicsDE = `float playerde(vec3 p){ 41 | if(length(p) > 2.){ 42 | return length(p) - 1.5; 43 | } 44 | float objectstatement0 = length(p) - 1.; 45 | float objectstatement1 = sdBox(p-vec3(-0.05291528043628058, -0.021903354372863646, 0.6578908715401734), vec3(1.6600000000000008, 0.09999999999999987, 0.9600000000000003)); 46 | float objectstatement2 = sdBox(p-vec3(-0.0001862456368470558, 0.10067630377999565, 0.8571044766685708), vec3(0.14000000000000007, 1.540000000000001, 0.9800000000000004)); 47 | float objectstatement3 = length(p - vec3(-0.005472885286035935, -0.029167183774926043, 1.2773521536590116)) - 0.6199999999999997; 48 | float objectstatement4 = length(p - vec3(-0.4679996922189376, 0.35672342974691895, -0.808756936225508)) - 0.19999999999999943; 49 | float objectstatement5 = length(p - vec3(0.5025153232879811, 0.35641370152090157, -0.7877529247719554)) - 0.19999999999999943; 50 | float objectstatement6 = sdBox(p-vec3(0.0008072258345014002, -0.3028070309368585, -0.9741866862623801), vec3(0.3599999999999999, 0.08000000000000011, 0.5)); 51 | float objectunion0 = max(objectstatement0, -smin(smin(smin(smin(smin(objectstatement1, objectstatement2, 0.2), objectstatement3, 0.2), objectstatement4, 0.2), objectstatement5, 0.2), objectstatement6, 0.2)); 52 | return objectunion0; 53 | }`; 54 | 55 | this.initUnis = () => { 56 | renderer.addUniform(this.posUniName, "vec3", this.pos); 57 | } 58 | } 59 | 60 | function obstacles(x){ 61 | let rand = Math.floor(1.4*sin( (2*Math.floor(x)-100) * (2*Math.floor(x)-100)) + 1.44); 62 | 63 | return mod(rand + 1, 3); 64 | } -------------------------------------------------------------------------------- /gamerendering.js: -------------------------------------------------------------------------------- 1 | function makeShader(src, type, gl){ 2 | let shader = gl.createShader(type); 3 | gl.shaderSource(shader, src); 4 | gl.compileShader(shader); 5 | 6 | if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){ 7 | return shader; 8 | } else { 9 | console.log(gl.getShaderInfoLog(shader)); 10 | console.log(src); 11 | gl.deleteShader(shader); 12 | } 13 | } 14 | 15 | function createProgram(vertShad, fragShad, gl){ 16 | let program = gl.createProgram(); 17 | gl.attachShader(program, vertShad); 18 | gl.attachShader(program, fragShad); 19 | 20 | gl.linkProgram(program); 21 | 22 | return program; 23 | } 24 | 25 | function createGraphics(de, colors, otherfunctions, uniforms){ 26 | 27 | let c = document.createElement("canvas"); 28 | 29 | let scale = 1; 30 | 31 | //let rat = c.height / c.width; 32 | 33 | c.width = scale * window.innerWidth; 34 | c.height = scale * window.innerHeight; 35 | 36 | document.body.appendChild(c); 37 | 38 | let gl = c.getContext("webgl2"); 39 | 40 | let vertSrc = 41 | `#version 300 es 42 | 43 | in vec4 a_position; 44 | out vec4 pos4; 45 | 46 | void main(){ 47 | pos4 = a_position; 48 | gl_Position = a_position; 49 | }`; 50 | 51 | let fragSrc = 52 | `#version 300 es 53 | 54 | #define MIN_DIST 0.001 55 | #define MAX_ITERATIONS 100 56 | #define RANGE 10000. 57 | 58 | precision highp float; 59 | 60 | out vec4 color; 61 | in vec4 pos4; 62 | 63 | uniform vec2 res; 64 | uniform vec3 camPos; 65 | uniform vec2 camAngle; 66 | uniform float t; 67 | uniform vec3 objectPos; 68 | uniform vec2 objectAngle; 69 | ${uniforms} 70 | 71 | ${libs} 72 | 73 | ${de} 74 | 75 | ${libsAfterDe} 76 | 77 | ${otherfunctions} 78 | 79 | void main(){ 80 | vec2 pos = pos4.xy; 81 | pos.x *= res.x/res.y; 82 | 83 | float fovX = .35; 84 | float fovY = .35; 85 | 86 | vec3 dir = normalize(vec3(pos.x*fovX, pos.y*fovY, 0.5515)); 87 | 88 | dir = rotX(dir, -camAngle.y); 89 | dir = rotY(dir, camAngle.x); 90 | 91 | vec3 p = camPos; 92 | 93 | float dist = de(p); 94 | float totDist = dist; 95 | 96 | float bloomDist = 9999.; 97 | 98 | while(dist > MIN_DIST && totDist < RANGE){ 99 | p += dir*dist; 100 | dist = de(p); 101 | float bd = bloomDE(p); 102 | if(bd <= bloomDist){ 103 | bloomDist = bd; 104 | } 105 | totDist += dist; 106 | } 107 | 108 | ${colors} 109 | 110 | //color = vec4(abs(pos.x),1.-length(pos),abs(pos.y),1.); 111 | 112 | } 113 | ` 114 | 115 | vertShad = makeShader(vertSrc, gl.VERTEX_SHADER, gl); 116 | fragShad = makeShader(fragSrc, gl.FRAGMENT_SHADER, gl); 117 | 118 | let program = createProgram(vertShad, fragShad, gl); 119 | 120 | let posLoc = gl.getAttribLocation(program, "a_position"); 121 | 122 | let posBuffer = gl.createBuffer(); 123 | 124 | gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer); 125 | gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1,-1,-1,1,1,1,1,1,1,-1,-1,-1]), gl.STATIC_DRAW); 126 | 127 | 128 | let va = gl.createVertexArray(); 129 | 130 | gl.bindVertexArray(va); 131 | 132 | gl.enableVertexAttribArray(posLoc); 133 | 134 | gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0); 135 | 136 | gl.viewport(0, 0, c.width, c.height); 137 | 138 | gl.clearColor(0, 0, 0, 0); 139 | gl.clear(gl.COLOR_BUFFER_BIT); 140 | 141 | gl.useProgram(program); 142 | 143 | return {gl, program, c}; 144 | } 145 | 146 | function Renderer(de, colors, otherfunctions, uniforms){ 147 | let graphics = createGraphics(de, colors, otherfunctions, uniforms); 148 | this.gl = graphics.gl; 149 | this.canvas = graphics.c; 150 | this.program = graphics.program; 151 | 152 | this.uniforms = {}; 153 | 154 | this.addUniform = (name, type, value) => { 155 | if(value.length != undefined){ 156 | if(value[0].length == undefined){ 157 | value = new Float32Array(value); 158 | } 159 | } 160 | let uni = {location: "", t: type, name: name, value: value}; 161 | uni.location = this.gl.getUniformLocation(this.program, name); 162 | if(type == "vec2"){ 163 | uni.t = (loc, val)=>{this.gl.uniform2fv(loc, val)}; 164 | } 165 | if(type == "vec3"){ 166 | uni.t = (loc, val)=>{this.gl.uniform3fv(loc, val)}; 167 | } 168 | if(type == "vec4"){ 169 | uni.t = (loc, val)=>{this.gl.uniform4fv(loc, val)}; 170 | } 171 | if(type == "float"){ 172 | uni.t = (loc, val)=>{this.gl.uniform1f(loc, val)}; 173 | } 174 | if(type == "mat3"){ 175 | uni.t = (loc, val)=>{ 176 | let temp = []; 177 | for(let i of val){ 178 | for(let j of i){ 179 | temp.push(j); 180 | } 181 | } 182 | this.gl.uniformMatrix3fv(loc, false, new Float32Array(temp)); 183 | }; 184 | } 185 | 186 | this.uniforms[name] = uni; 187 | 188 | uni.t(uni.location, uni.value); 189 | } 190 | 191 | this.setUni = (name, value) => { 192 | if(value.length != undefined){ 193 | if(value.length == undefined){ 194 | value = new Float32Array(value); 195 | } 196 | } 197 | this.uniforms[name].value = value; 198 | this.uniforms[name].t(this.uniforms[name].location, value); 199 | } 200 | 201 | this.updateUniforms = () => { 202 | for(let i of this.uniforms){ 203 | i.t(i.location, i.value); 204 | } 205 | } 206 | 207 | this.draw = () => { 208 | this.gl.drawArrays(this.gl.TRIANGLES, 0, 6); 209 | } 210 | 211 | this.changeFragShader = (fragSrc) => { 212 | 213 | let gl = this.gl; 214 | 215 | let vertSrc = 216 | `#version 300 es 217 | 218 | in vec4 a_position; 219 | out vec4 pos4; 220 | 221 | void main(){ 222 | pos4 = a_position; 223 | gl_Position = a_position; 224 | }`; 225 | 226 | vertShad = makeShader(vertSrc, gl.VERTEX_SHADER, gl); 227 | fragShad = makeShader(fragSrc, gl.FRAGMENT_SHADER, gl); 228 | 229 | let program = createProgram(vertShad, fragShad, gl); 230 | 231 | this.program = program; 232 | 233 | gl.useProgram(program); 234 | 235 | this.uniforms = {}; 236 | this.initializeBaseUniforms(); 237 | } 238 | 239 | this.changeShader = (de, colors, otherfunctions, uniforms) => { 240 | let fragSrc = 241 | `#version 300 es 242 | 243 | #define MIN_DIST 0.001 244 | #define MAX_ITERATIONS 100 245 | #define RANGE 1000. 246 | 247 | precision highp float; 248 | 249 | out vec4 color; 250 | in vec4 pos4; 251 | 252 | uniform vec2 res; 253 | uniform vec3 camPos; 254 | uniform vec2 camAngle; 255 | uniform float t; 256 | uniform vec3 objectPos; 257 | uniform vec2 objectAngle; 258 | ${uniforms} 259 | 260 | ${libs} 261 | 262 | ${de} 263 | 264 | ${libsAfterDe} 265 | 266 | ${otherfunctions} 267 | 268 | void main(){ 269 | vec2 pos = pos4.xy; 270 | pos.x *= res.x/res.y; 271 | 272 | float fovX = .35; 273 | float fovY = .35; 274 | 275 | vec3 dir = normalize(vec3(pos.x*fovX, pos.y*fovY, 0.5515)); 276 | 277 | dir = rotX(dir, -camAngle.y); 278 | dir = rotY(dir, camAngle.x); 279 | 280 | vec3 p = camPos; 281 | 282 | float dist = de(p); 283 | float totDist = dist; 284 | 285 | while(dist > MIN_DIST && totDist < RANGE){ 286 | p += dir*dist; 287 | dist = de(p); 288 | totDist += dist; 289 | } 290 | 291 | ${colors} 292 | 293 | //color = vec4(abs(pos.x),1.-length(pos),abs(pos.y),1.); 294 | 295 | } 296 | ` 297 | 298 | this.changeFragShader(fragSrc); 299 | } 300 | 301 | this.initializeBaseUniforms = () => { 302 | this.addUniform("res", "vec2", [this.canvas.width, this.canvas.height]); 303 | this.addUniform("camPos", "vec3", [0,7,10]); 304 | this.addUniform("camAngle", "vec2", [Math.PI*5/8,-0.2*Math.PI/2]); 305 | this.addUniform("t", "float", 0); 306 | this.addUniform("objectPos", "vec3", [0,0,0]); 307 | this.addUniform("objectAngle", "vec2", [0,0]); 308 | 309 | } 310 | 311 | this.initializeBaseUniforms(); 312 | } -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | let player = new Player(); 2 | let bridge = new Bridge(); 3 | let pillar = new Pillar(); 4 | let pillar2 = new Pillar2(); 5 | 6 | let entities = [player, bridge, pillar, pillar2]; 7 | 8 | let renderer; 9 | 10 | function assembleGraphics(){ 11 | let initDEs = ""; 12 | let deSum = ""; 13 | let entityUnis = ""; 14 | for(let i of entities){ 15 | initDEs += `\n${i.graphicsDE}\n`; 16 | deSum += `d = min(d, ${i.deIdentifier}(p - ${i.posUniName}));\n`; 17 | entityUnis += `uniform vec3 ${i.posUniName};`; 18 | } 19 | 20 | renderer = new Renderer( 21 | ` 22 | ${initDEs} 23 | 24 | float de(vec3 p){ 25 | float d = 9999.; 26 | d = min(d, bridgede(p)); 27 | vec3 q = p - vec3(0., -8., 15.); 28 | q = rotZ(q, 3.14159265/2.); 29 | d = min(d, pillar2de(q)); 30 | vec3 pillarq = mod(p - vec3(0.,0.,-40.), vec3(70., 0., 0.)) - vec3(35., 0., 0.); 31 | float pillars = pillarde(pillarq); 32 | d = min(d, max(max(pillars, p.y - 25.), -100000.-p.y)); 33 | vec3 playerP = p - vec3(camPos.x + 15., 1.9 + 0.2*sin(2.*t), playerZ); 34 | playerP = rotY(playerP, 3.1415926535 / 2.); 35 | d = min(d, playerde(playerP)); 36 | return d; 37 | } 38 | 39 | float bloomDE(vec3 p){ 40 | vec3 q = p - vec3(0., -8., 15.); 41 | q = rotZ(q, 3.14159265/2.); 42 | float objectstatement4 = sdBox((mod(twist(q,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.)-vec3(0., 0., -2.), vec3(0.45999999999999996, 2.1600000000000015, 0.43999999999999995)); 43 | return objectstatement4; 44 | } 45 | `, 46 | ` 47 | 48 | vec3 norm = grad(p); 49 | 50 | vec3 col = abs(norm); 51 | 52 | vec3 lightPos = vec3(-.7,1.4,.9); 53 | 54 | vec3 pillarP = p - vec3(0., -8., 15.); 55 | pillarP = rotZ(pillarP, 3.14159265/2.); 56 | 57 | vec3 pillarq = mod(p - vec3(0.,0.,-40.), vec3(70., 0., 0.)) - vec3(35., 0., 0.); 58 | 59 | float bridgeDist = bridgede(p); 60 | 61 | vec3 playerP = p - vec3(camPos.x + 15., 1.9 + 0.2*sin(2.*t), playerZ); 62 | playerP = rotY(playerP, 3.1415926535 / 2.); 63 | 64 | if(playerde(playerP) < 0.002){ 65 | if(length(playerP) >= 0.9){ 66 | col = vec3(.877, 0.74, 0.72); 67 | 68 | vec3 reflectVec = normalize(reflect(lightPos, norm)); 69 | vec3 viewPos = normalize(p - camPos); 70 | 71 | float spec = dot(reflectVec, viewPos); 72 | 73 | spec = clamp(spec, 0., 1.); 74 | 75 | col += 0.3*spec; 76 | } else { 77 | col = vec3(0.) + 0.1*dot(norm, lightPos); 78 | if(abs(playerP.y - playerP.x) < 0.05){ 79 | col = vec3(1.); 80 | } 81 | col += mix(vec3(0., 1., 1.), vec3(0.),clamp(3.*abs(playerP.y - playerP.x), 0., 1.)); 82 | } 83 | } 84 | 85 | if(bridgeDist < 0.002 || pillar2de(pillarP) < 0.002){ 86 | col = vec3(0.55, 0.5, 0.5); 87 | float tex = bridgeRock(p); 88 | 89 | float eps = 0.001/2.; 90 | 91 | 92 | vec3 texNorm = normalize(vec3( 93 | (bridgeRock(p - vec3(eps,0.,0.)) - bridgeRock(p + vec3(eps,0.,0.)))/(2.*eps), 94 | 1., 95 | (bridgeRock(p - vec3(0.,0.,eps)) - bridgeRock(p + vec3(0.,0.,eps)))/(2.*eps) 96 | )); 97 | 98 | vec3 bridgeNorm = (norm+0.3*texNorm); 99 | 100 | col += vec3(tex*0.4); 101 | col += 0.3*dot(normalize(lightPos), bridgeNorm); 102 | 103 | vec3 reflectVec = reflect(lightPos, bridgeNorm); 104 | vec3 viewPos = normalize(camPos - p); 105 | 106 | float spec = dot(reflectVec, viewPos); 107 | 108 | spec = clamp(spec, 0., 1.); 109 | 110 | if(pillar2de(pillarP) > 0.002){ 111 | col += mix(-.2, 0., (p.z + 5.)/10.); 112 | } 113 | 114 | col += spec*0.15; 115 | 116 | if(p.y > 0.6 && p.z > -4.){ 117 | col += vec3(-0.07,-0.1,-0.07); 118 | } 119 | 120 | if(abs(p.y + 0.03) <= 0.05){ 121 | col = vec3(1.); 122 | } 123 | 124 | col += 0.4*mix(vec3(1.,.5,.5), vec3(0.),clamp(abs(p.y + 0.03)*4., 0., 1.)); 125 | 126 | 127 | if(bridgeDist < 0.002){ 128 | vec3 obsCol = vec3(1., 0.4, 0.4); 129 | if(mod(p.x/5., 1.) > 0.7){ 130 | if(obstacles(p.x/5.) == 0.){ 131 | if(p.z > 1.5 && p.z < 4.3){ 132 | vec3 reflectVec = reflect(lightPos, norm); 133 | vec3 viewPos = normalize(camPos - p); 134 | 135 | float spec = dot(reflectVec, viewPos); 136 | col = vec3(1.,0.49,0.33) + clamp(spec*0.7 + 0.2*bridgeRock(p), 0., 1.) - 0.5; 137 | } 138 | } 139 | if(obstacles(p.x/5.) == 1.){ 140 | if(p.z < 1.5 && p.z > -1.4){ 141 | vec3 reflectVec = reflect(lightPos, norm); 142 | vec3 viewPos = normalize(camPos - p); 143 | 144 | float spec = dot(reflectVec, viewPos); 145 | col = vec3(1.,0.49,0.33) + clamp(spec*0.7 + 0.2*bridgeRock(p), 0., 1.) - 0.5; 146 | } 147 | } 148 | if(obstacles(p.x/5.) == 2.){ 149 | if(p.z < -1.4){ 150 | vec3 reflectVec = reflect(lightPos, norm); 151 | vec3 viewPos = normalize(camPos - p); 152 | 153 | float spec = dot(reflectVec, viewPos); 154 | col = vec3(1.,0.49,0.33) + clamp(spec*0.7 + 0.2*bridgeRock(p), 0., 1.) - 0.5; 155 | } 156 | } 157 | } 158 | 159 | if(length(p.xz - vec2(camPos.x + 15., playerZ)) < .9){ 160 | col -= 0.3; 161 | } 162 | } 163 | } 164 | 165 | if(pillar2de(pillarP) < 0.002){ 166 | vec3 objectu_sizez5z = vec3(3., 0.4, .4); 167 | float objectstatement0 = length((mod(twist(pillarP,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.) - vec3(0., 0., 0.)) - -3.3; 168 | float objectstatement1 = sdBox((mod(twist(pillarP,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.)-vec3(-2., -0.02, 0.), objectu_sizez5z); 169 | float objectstatement2 = sdBox((mod(twist(pillarP,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.)-vec3(2., 0., 0.), vec3(0.35999999999999993, 1.3000000000000007, 0.5)); 170 | float objectstatement3 = sdBox((mod(twist(pillarP,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.)-vec3(0., 0., 2.), vec3(0.41999999999999993, 1.740000000000001, 0.3999999999999999)); 171 | float objectstatement4 = sdBox((mod(twist(pillarP,0.06000000000000005), vec3(0., 3.919999999999997, 0.)) - vec3(0., 3.919999999999997, 0.)/2.)-vec3(0., 0., -2.), vec3(0.45999999999999996, 2.1600000000000015, 0.43999999999999995)); 172 | 173 | if(objectstatement1 <= 0.002){ 174 | col -= 0.2; 175 | } 176 | 177 | if(objectstatement4 <= 0.002){ 178 | col = vec3(1.); 179 | } 180 | 181 | if(objectstatement2 <= 0.002){ 182 | vec3 reflectVec = reflect(lightPos, norm); 183 | vec3 viewPos = normalize(camPos - p); 184 | 185 | float spec = dot(reflectVec, viewPos); 186 | col = vec3(1.,0.49,0.33) + spec*0.7 + 0.2*bridgeRock(p); 187 | } 188 | 189 | col += 0.3*clamp(mix(vec3(0., 1., 1.), vec3(0.), objectstatement4/3.), 0., 1.); 190 | 191 | } 192 | 193 | if(pillarde(pillarq) < 0.002 || p.z < -4.23){ 194 | col = vec3(.877, 0.74, 0.72); 195 | 196 | vec3 reflectVec = reflect(lightPos, norm); 197 | vec3 viewPos = normalize(camPos - p); 198 | 199 | float spec = dot(reflectVec, viewPos); 200 | 201 | spec = clamp(spec, 0., 1.); 202 | 203 | col += spec; 204 | } 205 | 206 | vec3 sphereP = normalize(p-camPos); 207 | 208 | vec3 skyCol = mix(vec3(0.52, 0.80, 0.92), vec3(0.52, 0.80, 0.92),length(pos)) + vec3(0.2,0.,0.); 209 | 210 | skyCol = mix(vec3(0.5, 0.8, 0.9), vec3(1., .9, 0.45), clamp(sphereP.y + 0.6, 0., 1.)); 211 | float clouds = clamp(bridgeRock(2.5*normalize(p-camPos)+t/300.), 0., 1.); 212 | 213 | skyCol += mix(vec3(clouds), vec3(0.15, 0., 0.1), clamp(sphereP.y + .6, 0., 1.)); 214 | 215 | if(dist > MIN_DIST){ 216 | col = skyCol; 217 | } else { 218 | col += 0.15*vec3(0.7, 0.8, 0.9); 219 | col = mix(col, skyCol, clamp(length(p-camPos)/1000., 0., 1.)); 220 | } 221 | 222 | 223 | col += vec3(mix(vec3(0.,1.,1.),vec3(0.),clamp(bloomDist*1., 0.,1.))); 224 | if(deadTime == 0.){ 225 | color = vec4((tone(col, 1.) + col*0.3), 1.); 226 | } else { 227 | color = mix(vec4((tone(col, 1.) + col*0.3), 1.), vec4(1.-(tone(col, 1.) + col*0.3), 1.),clamp(5.*deadTime, 0., 1.)); 228 | } 229 | 230 | `, 231 | ` 232 | float obstacles(float x){ 233 | float rand = floor(1.4*sin((2.*floor(x)-100.)*(2.*floor(x)-100.))+1.44); 234 | 235 | return mod(rand + 1., 3.); 236 | } 237 | 238 | float bridgeRock(vec3 p){ 239 | p /= 1.5; 240 | return noise(10.*p)*0.1 + 0.2*noise(5.*p) + 0.05*noise(20.*p) + 0.025*noise(40.*p); 241 | } 242 | //ty shadertoy user @nimitz!! 243 | vec3 tone(vec3 color, float gamma) 244 | { 245 | float white = 2.; 246 | float luma = dot(color, vec3(0.2126, 0.7152, 0.0722)); 247 | float toneMappedLuma = luma * (1. + luma / (white*white)) / (1. + luma); 248 | color *= toneMappedLuma / luma; 249 | color = pow(color, vec3(1. / gamma)); 250 | return color; 251 | } 252 | `, 253 | `${entityUnis} 254 | uniform float playerZ; 255 | uniform float deadTime;` 256 | ); 257 | 258 | for(let i of entities){ 259 | i.initUnis(); 260 | } 261 | } 262 | 263 | assembleGraphics(); 264 | 265 | let camPos = [0,7,10]; 266 | 267 | let t = performance.now() / 1000; 268 | let startT = t; 269 | 270 | let dt = 1/60; 271 | 272 | let speed = 10; 273 | 274 | renderer.addUniform("playerZ", "float", 0); 275 | renderer.addUniform("deadTime", "float", 0); 276 | 277 | let deadTime = 0; 278 | 279 | function update(){ 280 | let now = performance.now() / 1000; 281 | dt = now - t; 282 | t = now; 283 | renderer.setUni("t", t); 284 | speed += dt * 0.5; 285 | if(speed > 30){ 286 | speed = 30; 287 | } 288 | if(!player.dead){ 289 | camPos[0] += speed*dt; 290 | player.update(); 291 | } else { 292 | deadTime += dt; 293 | renderer.setUni("deadTime", deadTime); 294 | } 295 | renderer.setUni("playerZ", player.z); 296 | renderer.setUni("camPos", camPos); 297 | renderer.draw(); 298 | 299 | keyPressed = []; 300 | requestAnimationFrame(update); 301 | } 302 | 303 | update(); 304 | 305 | -------------------------------------------------------------------------------- /gamelibs.js: -------------------------------------------------------------------------------- 1 | let libs = 2 | ` 3 | //ty IQ for most of these 4 | float smin( float a, float b, float k ) 5 | { 6 | float h = max( k-abs(a-b), 0.0 )/k; 7 | return min( a, b ) - h*h*k*(1.0/4.0); 8 | } 9 | 10 | vec3 bend(vec3 p, float k) 11 | { 12 | float c = cos(k*p.x); 13 | float s = sin(k*p.x); 14 | mat2 m = mat2(c,-s,s,c); 15 | vec3 q = vec3(m*p.xy,p.z); 16 | return q; 17 | } 18 | vec3 rotAxis(vec3 p, float a, vec3 u){ 19 | mat3 m = mat3( 20 | cos(a) + u.x*u.x*(1.-cos(a)), u.x*u.y*(1.-cos(a))-u.z*sin(a), u.x*u.z*(1.-cos(a)) + u.y*sin(a), 21 | u.y*u.x*(1.-cos(a))+u.z*sin(a), cos(a) + u.y*u.y*(1.-cos(a)), u.y*u.z*(1.-cos(a))-u.x*sin(a), 22 | u.z*u.x*(1.-cos(a))-u.y*sin(a), u.z*u.y*(1.-cos(a))+u.x*sin(a), cos(a) + u.z*u.z*(1.-cos(a)) 23 | ); 24 | 25 | return m*p; 26 | } 27 | vec3 rotY(vec3 v, float a){ 28 | return vec3(v.x*cos(a)+v.z*sin(a),v.y,-v.x*sin(a) + v.z*cos(a)); 29 | } 30 | 31 | vec3 rotX(vec3 v, float a){ 32 | return vec3(v.x, v.y*cos(a)-v.z*sin(a), v.y*sin(a)+v.z*cos(a)); 33 | } 34 | vec3 rotZ(vec3 v, float a){ 35 | return vec3(v.x*cos(a) + v.y*sin(a), -v.x*sin(a)+v.y*cos(a), v.z); 36 | } 37 | vec3 twist( vec3 p, float k ) 38 | { 39 | float c = cos(k*p.y); 40 | float s = sin(k*p.y); 41 | mat2 m = mat2(c,-s,s,c); 42 | vec3 q = vec3(m*p.xz,p.y); 43 | return q.xzy; 44 | } 45 | 46 | vec3 palette( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d ) 47 | { 48 | return a + b*cos( 6.28318*(c*t+d) ); 49 | } 50 | float dot2(in vec3 v ) { return dot(v,v); } 51 | 52 | float sdBox( vec3 p, vec3 b ){ 53 | vec3 q = abs(p) - b; 54 | return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0); 55 | } 56 | float sdBox( in vec2 p, in vec2 b ){ 57 | vec2 d = abs(p)-b; 58 | return length(max(d,0.0)) + min(max(d.x,d.y),0.0); 59 | } 60 | float sdCapsule( vec3 p, vec3 a, vec3 b, float r ) 61 | { 62 | vec3 pa = p - a, ba = b - a; 63 | float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 ); 64 | return length( pa - ba*h ) - r; 65 | } 66 | float sdTorus( vec3 p, vec2 t ) 67 | { 68 | vec2 q = vec2(length(p.xz)-t.x,p.y); 69 | return length(q)-t.y; 70 | } 71 | float sdRoundCone( vec3 p, vec3 a, vec3 b, float r1, float r2 ) 72 | { 73 | // sampling independent computations (only depend on shape) 74 | vec3 ba = b - a; 75 | float l2 = dot(ba,ba); 76 | float rr = r1 - r2; 77 | float a2 = l2 - rr*rr; 78 | float il2 = 1.0/l2; 79 | 80 | // sampling dependant computations 81 | vec3 pa = p - a; 82 | float y = dot(pa,ba); 83 | float z = y - l2; 84 | float x2 = dot2( pa*l2 - ba*y ); 85 | float y2 = y*y*l2; 86 | float z2 = z*z*l2; 87 | 88 | // single square root! 89 | float k = sign(rr)*rr*rr*x2; 90 | if( sign(z)*a2*z2>k ) return sqrt(x2 + z2) *il2 - r2; 91 | if( sign(y)*a2*y2> 3U)); 141 | return vec3(p ^ (p >> 16U)) * (1.0 / vec3(0xffffffffU)); 142 | } 143 | vec3 stars(in vec3 p) { 144 | vec3 c = vec3(0.); 145 | float resX = 500.; 146 | 147 | for(float i = 0.; i < 5.; i++) { 148 | vec3 q = fract(p * (.15 * resX)) - 0.5; 149 | vec3 id = floor(p * (.15 * resX)); 150 | vec2 rn = nmzHash33(id).xy; 151 | float c2 = 1. - smoothstep(0., .6, length(q)); 152 | c2 *= step(rn.x, .0005 + i * 0.002); 153 | c += c2 * (mix(vec3(1.0, 0.49, 0.1), vec3(0.75, 0.9, 1.), rn.y) * 0.25 + 0.75); 154 | p *= 1.4; 155 | } 156 | return c * c; 157 | } 158 | 159 | `; 160 | 161 | let libsAfterDe = ` 162 | vec3 grad(vec3 p){ 163 | float eps = 0.01; 164 | return normalize(vec3((de(p+vec3(eps, 0., 0.)) - de(p-vec3(eps,0.,0.)))/(2.*eps), (de(p+vec3(0., eps, 0.)) - de(p-vec3(0.,eps,0.)))/(2.*eps), (de(p+vec3(0., 0., eps)) - de(p-vec3(0.,0.,eps)))/(2.*eps))); 165 | } 166 | float light(vec3 p, vec3 l){ 167 | return clamp(dot(grad(p), l), 0., 1.); 168 | } 169 | 170 | float specLight(vec3 p, vec3 l){ 171 | vec3 pos = normalize(p-camPos); 172 | vec3 ray = reflect(l, grad(p)); 173 | return clamp(dot(pos, ray), 0., 1.); 174 | } 175 | 176 | ` 177 | function rotY(v, a){ 178 | return [v[0]*cos(a) + v[2]*sin(a), v[1], -v[0]*sin(a) + v[2]*cos(a)]; 179 | } 180 | function rotX(v, a){ 181 | return [v[0], v[1]*cos(a)-v[2]*sin(a), v[1]*sin(a)+v[2]*cos(a)]; 182 | } 183 | function rotZ(v, a){ 184 | return [v[0]*cos(a)+v[1]*sin(a), -v[0]*sin(a)+v[1]*cos(a), v[2]]; 185 | } 186 | function plus(a1, a2){ 187 | return [a1[0] + a2[0], a1[1] + a2[1], a1[2] + a2[2]]; 188 | } 189 | function minus(a,b){ 190 | return [a[0] - b[0], a[1] - b[1], a[2]-b[2]]; 191 | } 192 | function times(a, s){ 193 | return [a[0]*s, a[1]*s, a[2]*s]; 194 | } 195 | function smin(a, b, k){ 196 | h = max( k-abs(a-b), 0.0 )/k; 197 | return min( a, b ) - h*h*k*(1.0/4.0); 198 | } 199 | 200 | function min(){ 201 | return Math.min(...arguments); 202 | } 203 | function max(){ 204 | return Math.max(...arguments); 205 | } 206 | function abs(x){ 207 | if(x.length != undefined){ 208 | let temp = []; 209 | for(let i of x){ 210 | temp.push(Math.abs(i)); 211 | } 212 | return temp; 213 | } 214 | return Math.abs(x); 215 | } 216 | function matPlus(a, b){ 217 | let temp = []; 218 | for(let i in a){ 219 | temp[i] = []; 220 | for(let j in a[i]){ 221 | temp[i][j] = a[i][j] + b[i][j]; 222 | } 223 | } 224 | 225 | return temp; 226 | } 227 | function matTimes(m, v){ 228 | return [ 229 | m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]*v[2], 230 | m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]*v[2], 231 | m[2][0]*v[0] + m[2][1]*v[1] + m[2][2]*v[2] 232 | ]; 233 | } 234 | function matTimesMat(a, b){ 235 | let temp = [[],[],[]]; 236 | for(let i in b){ 237 | let col = matTimes(a, [b[0][i], b[1][i], b[2][i]]); 238 | for(let j in col){ 239 | temp[j].push(col[j]); 240 | } 241 | } 242 | return temp; 243 | } 244 | function matTimesS(m, s){ 245 | let temp = []; 246 | for(let i in m){ 247 | temp[i] = []; 248 | for(let j in m[i]){ 249 | temp[i][j] = m[i][j]*s; 250 | } 251 | } 252 | return temp; 253 | } 254 | function I(){ 255 | return [[1,0,0],[0,1,0],[0,0,1]]; 256 | } 257 | //skew-symmetric cross-product matrix of v ?? (don't know what this means) 258 | function sscpm(v){ 259 | return [ 260 | [0, -v[2], v[1]], 261 | [v[2], 0, -v[0]], 262 | [-v[1], v[0], 0] 263 | ] 264 | } 265 | //https://math.stackexchange.com/questions/180418/calculate-rotation-matrix-to-align-vector-a-to-vector-b-in-3d 266 | function rotMatFromTwoVectors(a, b){ 267 | let v = cross(a,b); 268 | let s = len(v); 269 | let c = dot(a,b); 270 | 271 | let vx = sscpm(v); 272 | let vx2 = matTimesS(matTimesMat(vx, vx), (1/(1+c))); 273 | 274 | let R = matPlus(matPlus(I(), vx), vx2); 275 | 276 | return R; 277 | } 278 | function rotMatFromVec(v){ 279 | v = normalize(v); 280 | let u = [0,0,1]; 281 | let k = sscpm(u); 282 | let c = dot(v,u); 283 | let s = len(cross(v,u)); 284 | 285 | let k2 = matTimesMat(k, k); 286 | 287 | k = matTimesS(k, s); 288 | k2 = matTimesS(k2, (1-c)); 289 | 290 | let R = matPlus(I(), matPlus(k,k2)); 291 | 292 | return R; 293 | } 294 | function rotAxis(p, a, u){ 295 | let m = [ 296 | [cos(a)+u[0]*u[0]*(1-cos(a)), u[0]*u[1]*(1-cos(a))-u[2]*sin(a), u[0]*u[2]*(1-cos(a))+u[1]*sin(a)], 297 | [u[1]*u[0]*(1-cos(a))+u[2]*sin(a), cos(a)+u[1]*u[1]*(1-cos(a)), u[1]*u[2]*(1-cos(a))-u[0]*sin(a)], 298 | [u[2]*u[0]*(1-cos(a))-u[1]*sin(a), u[2]*u[1]*(1-cos(a))+u[0]*sin(a), cos(a)+u[2]*u[2]*(1-cos(a))] 299 | ]; 300 | 301 | return matTimes(m, p); 302 | } 303 | function rotAxisMat(a, u){ 304 | return [ 305 | [cos(a)+u[0]*u[0]*(1-cos(a)), u[0]*u[1]*(1-cos(a))-u[2]*sin(a), u[0]*u[2]*(1-cos(a))+u[1]*sin(a)], 306 | [u[1]*u[0]*(1-cos(a))+u[2]*sin(a), cos(a)+u[1]*u[1]*(1-cos(a)), u[1]*u[2]*(1-cos(a))-u[0]*sin(a)], 307 | [u[2]*u[0]*(1-cos(a))-u[1]*sin(a), u[2]*u[1]*(1-cos(a))+u[0]*sin(a), cos(a)+u[2]*u[2]*(1-cos(a))] 308 | ]; 309 | } 310 | function mod(x, m){ 311 | if(x.length != undefined){ 312 | let temp = []; 313 | for(let i of x){ 314 | temp.push(((i%m)+m)%m); 315 | } 316 | return temp; 317 | } 318 | return ((x%m)+m)%m; 319 | } 320 | function cos(x){ 321 | if(x.length != undefined){ 322 | let temp = []; 323 | for(let i of x){ 324 | temp.push(Math.cos(i)); 325 | } 326 | return temp; 327 | } 328 | return Math.cos(x); 329 | } 330 | function sin(x){ 331 | if(x.length != undefined){ 332 | let temp = []; 333 | for(let i of x){ 334 | temp.push(Math.sin(i)); 335 | } 336 | return temp; 337 | } 338 | return Math.sin(x); 339 | } 340 | function len(v){ 341 | return Math.hypot(...v); 342 | } 343 | function normalize(v){ 344 | if(len(v) == 0){ 345 | return [0,0,0]; 346 | } 347 | return times(v, 1/len(v)); 348 | } 349 | function dot(a, b){ 350 | return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; 351 | } 352 | function cross(a, b){ 353 | return [ 354 | a[1]*b[2]-a[2]*b[1], 355 | a[2]*b[0]-a[0]*b[2], 356 | a[0]*b[1]-a[1]*b[0] 357 | ]; 358 | } 359 | function reflect(d, n){ 360 | return plus(d, times(n, -2*dot(d,n))); 361 | } 362 | function deNormal(p){ 363 | let eps = 0.01; 364 | eps /= 2; 365 | return normalize([ 366 | de(plus(p, [eps, 0, 0])) - de(plus(p, [-eps, 0, 0])), 367 | de(plus(p, [0, eps, 0])) - de(plus(p, [0, -eps, 0])), 368 | de(plus(p, [0, 0, eps])) - de(plus(p, [0, 0, -eps])) 369 | ]); 370 | } 371 | function lerp(a,b,w){ 372 | if(a.length != undefined){ 373 | let temp = []; 374 | for(let i in a){ 375 | temp.push(a[i] + (b[i]-a[i])*w); 376 | } 377 | return temp; 378 | } 379 | return a+(b-a)*w; 380 | } 381 | 382 | function sinLerp(a,b,w){ 383 | return lerp(a,b, sin(Math.PI*(w-0.5))/2 + 0.5); 384 | } 385 | 386 | function aLerp(a,b,w){ 387 | a %= 2*Math.PI; 388 | b %= 2*Math.PI; 389 | if(abs(b-a) < Math.PI){ 390 | return lerp(a,b,w); 391 | } else { 392 | a += Math.sign(b-a)*2*Math.PI; 393 | return lerp(a,b,w); 394 | } 395 | } 396 | function sdSphere(p, r){ 397 | return len(p) - r; 398 | } 399 | function sdBox3(p, b){ 400 | let q = plus(abs(p), times(b, -1)); 401 | return len([max(q[0], 0),max(q[1], 0),max(q[2], 0)]) + min(max(q[0],q[1],q[2]), 0); 402 | } 403 | 404 | function sdTorus(p, t){ 405 | let q = [len([p[0], p[2]])-t[0], p[1]]; 406 | return len(q)-t[1]; 407 | } 408 | 409 | function sdRoundCone(p, a, b, r1, r2){ 410 | let ba = minus(b,a); 411 | let l2 = dot(ba,ba); 412 | let rr = minus(r1,r2); 413 | let a2 = l2 - rr*rr; 414 | let il2 = 1/l2; 415 | 416 | let pa = minus(p,a); 417 | let y = dot(pa, ba); 418 | let z = y-l2; 419 | let temp = minus(times(pa, l2), times(ba,y)); 420 | let x2 = dot(temp,temp); 421 | let y2 = y*y*l2; 422 | let z2 = z*z*l2; 423 | 424 | let k = Math.sign(rr)*rr*rr*x2; 425 | if(Math.sign(z)*a2*z2 > k) return Math.sqrt(x2+z2) * il2 - r2; 426 | if(Math.sign(y)*a2*y2 < k) return Math.sqrt(x2+y2) * il2 - r1; 427 | 428 | return (Math.sqrt(x2*a2*il2)+y*rr)*il2 - r1; 429 | } 430 | function dirFromAngle(ax, ay){ 431 | let dir = [0,0,1]; 432 | dir = rotX(dir, -ay); 433 | dir = rotY(dir, ax); 434 | 435 | return dir; 436 | } 437 | 438 | function march(df, p, dir){ 439 | let eps = 0.001; 440 | let range = 10000; 441 | let totDist = 0; 442 | 443 | let dist = df(p); 444 | while(dist > eps && totDist < range){ 445 | p = plus(p, times(dir, dist)); 446 | totDist += dist; 447 | dist = df(p); 448 | } 449 | 450 | if(dist < eps){ 451 | return p; 452 | } else { 453 | return false; 454 | } 455 | } 456 | 457 | function cast(x, y, de){ 458 | let dir = normalize([x*0.35, y*0.35, 0.5515]); 459 | 460 | dir = rotX(dir, -camAngle[1]); 461 | dir = rotY(dir, camAngle[0]); 462 | 463 | return march(de, camPos, dir); 464 | } 465 | 466 | let displayWidth = 0.6; 467 | function normalizeScreenCoords(x,y){ 468 | return [2*((x - (window.innerWidth*displayWidth-window.innerHeight)/2) / window.innerHeight) - 1, 2*(1-(y / window.innerHeight)) - 1]; 469 | } 470 | 471 | function float(x){ 472 | let s = "" + x; 473 | if(s.indexOf(".") == -1){ 474 | s += "."; 475 | } 476 | 477 | return s; 478 | } --------------------------------------------------------------------------------