├── 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 | }
--------------------------------------------------------------------------------