Skip to content

Instantly share code, notes, and snippets.

@mhekel
Created December 13, 2024 16:20
Show Gist options
  • Select an option

  • Save mhekel/f1c85ebb88d7b1fc4ff9e6ad27628d21 to your computer and use it in GitHub Desktop.

Select an option

Save mhekel/f1c85ebb88d7b1fc4ff9e6ad27628d21 to your computer and use it in GitHub Desktop.
a trip
<div class="container">
<canvas id="glcanvas"></canvas>
<div class="top-container">
<h2 id="text3d">Because, Donut</h2>
</div>
<div id="navbar">
<a href="home.html">Home</a>
<a href="https://becausedonut-shop.fourthwall.com">Products</a>
<a href="iracing.html">iRacing</a>
</div>
<script id="vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0.0, 1.0);
}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
uniform float u_terrainHeight;
uniform float u_terrainNoise;
uniform float u_camPosY;
uniform float u_lookAtY;
uniform float u_speedZ;
vec3 palette( float t ) {
vec3 a = vec3(0.5, 0.5, 0.0);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.25,0.4,0.55);
return a + b*cos( 6.28318*(c*t+d) );
}
vec3 palette2( float t ) {
vec3 a = vec3(0.5, 0.5, 0.5);
vec3 b = vec3(0.5, 0.5, 0.5);
vec3 c = vec3(1.0, 1.0, 1.0);
vec3 d = vec3(0.25,0.4,0.55);
return a + b*cos( 6.28318*(c*t+d) );
}
float hash(vec3 p) {
p = 50.0 * fract(p * 0.3183099 + vec3(0.71, 0.113, 0.5));
return -1.0 + 2.0 * fract(p.x * p.y * p.z * (p.x + p.y + p.z));
}
float noiseF(vec3 p) {
vec3 i = floor(p);
vec3 f = fract(p);
float a = hash(i);
float b = hash(i + vec3(1.0, 0.0, 0.0));
float c = hash(i + vec3(0.0, 1.0, 0.0));
float d = hash(i + vec3(1.0, 1.0, 0.0));
float e = hash(i + vec3(0.0, 0.0, 1.0));
float f1 = hash(i + vec3(1.0, 0.0, 1.0));
float g = hash(i + vec3(0.0, 1.0, 1.0));
float h = hash(i + vec3(1.0, 1.0, 1.0));
vec3 u = f * f * (3.0 - 2.0 * f);
return mix(mix(mix(a, b, u.x), mix(c, d, u.x), u.y), mix(mix(e, f1, u.x), mix(g, h, u.x), u.y), u.z);
}
vec3 warp(vec3 p) {
vec3 offset = vec3(noiseF(p + u_time));
return p + offset;
}
vec2 rotate(vec2 pos, float angle) {
float cosAngle = cos(angle);
float sinAngle = sin(angle);
mat2 rotationMatrix = mat2(cosAngle, -sinAngle, sinAngle, cosAngle);
return rotationMatrix * pos;
}
vec3 getRayDirection(vec2 uv, vec3 camPos, vec3 camForward, vec3 camRight, vec3 camUp, float fov) {
vec3 dir = camForward + uv.x * camRight * fov + uv.y * camUp * fov;
return normalize(dir);
}
float oscillate(float time, float minVal, float maxVal) {
float sineWave = sin(time);
float normalizedSine = (sineWave + 1.0) / 2.0;
return mix(minVal, maxVal, normalizedSine);
}
float waveX(float z){
return sin((z + u_time) * 0.1) * 10.0;
}
float waveXOffset(float z, float zOffset) {
return sin((z + zOffset + u_time) * 0.1) * 10.0;
}
float boxSDF(vec3 p, vec3 bsize) {
p.x += waveX(p.z);
vec3 d = vec3(mod(p.x, 3.0) - 1.5, p.y * 2.0, mod(p.z, 3.0) - 1.5);
d = abs(d) - bsize;
if (p.x < -3.0 || p.x > 3.0) {
return 100.0;
}
return length(max(d, 0.0)) + min(max(d.x, max(d.y, d.z)), 0.0);
}
float roadSDF(vec3 p, vec3 bsize) {
p.x += waveX(p.z);
vec3 repeatedPos = vec3(p.x, p.y, mod(p.z, 6.0) - 3.0);
vec3 d = abs(repeatedPos) - bsize;
return length(max(d, 0.0)) + min(max(d.x, max(d.y, d.z)), 0.0);
}
float sphereSDF( vec3 p, float size )
{
float noise = noiseF(p + u_time);
p = mod(p + noise, 100.0) - 50.0 * 0.5;
return length(p)-size;
}
float terrainSDF(vec3 p) {
float scale = u_terrainNoise;
float height = u_terrainHeight;
p.x += waveX(p.z);
float baseTerrainHeight = max(0.0, noiseF(vec3(p.x * scale, 0.0, p.z * scale)) * height);
float detailNoise1 = max(0.0, noiseF(vec3(p.x * scale * 2.0, 0.0, p.z * scale * 2.0)) * height * 0.5);
float detailNoise2 = max(0.0, noiseF(vec3(p.x * scale * 4.0, 0.0, p.z * scale * 4.0)) * height * 0.25);
float detailNoise3 = max(0.0, noiseF(vec3(p.x * scale * 6.0, 0.0, p.z * scale * 6.0)) * height * 0.1);
float totalHeight = baseTerrainHeight + detailNoise1 + detailNoise2 + detailNoise3;
float distanceFromCenter = abs(p.x) - 20.0;
float terrain = p.y - totalHeight;
return max(terrain, -distanceFromCenter);
}
vec3 sky(vec2 uv) {
uv.x += noiseF(vec3(uv.x * 0.5, uv.y * 0.5, uv.y * 0.5));
uv.y += noiseF(vec3(uv.x * 0.5, uv.y * 0.5, uv.y * 0.5));
float angle = atan(uv.y, uv.x);
float radius = length(uv);
float spiral = sin(radius * u_time * 0.001 - u_time * 2.0 + angle * 4.0);
float t = 5.0 + 0.1 * spiral + u_time * 0.1 + radius * 0.4;
vec3 color = palette2(t + u_time/200.0) * 0.2;
return color;
}
float sceneSDF(vec3 p, vec3 camPos) {
float road = roadSDF(p, vec3(20.0, 0.0, 10.0));
float stripes = boxSDF(p, vec3(0.2, 0.0, 1.0));
float terrain = terrainSDF(p);
return min(road, min(terrain, stripes));
}
vec3 getColor(vec3 worldPos, vec3 camPos) {
float roadDist = roadSDF(worldPos, vec3(10.0, 0.0, 10.0));
float stripeDist = boxSDF(worldPos, vec3(0.2, 1.0, 1.0));
float reverseWave = waveXOffset(camPos.z, -25.0);
float terrainDist = terrainSDF(worldPos);
float closestDist = min(terrainDist, min(roadDist, stripeDist));
if(closestDist == terrainDist){
return palette(exp(length((worldPos.y)* 0.02)) + u_time/50.0);
}
if (closestDist == roadDist) {
worldPos.x += waveX(worldPos.z);
return palette(exp(-length((worldPos.x )* 0.011)) + u_time/20.0);
} else if (closestDist == stripeDist) {
worldPos.x += waveX(worldPos.z);
return palette(exp(length((worldPos.x )* 0.11)) + u_time/20.0);
}
return vec3(0.0);
}
float rayMarch(vec3 ro, vec3 rd) {
float t = 0.0;
float maxDist = 400.0;
float hitThreshold = 0.003;
for (int i = 0; i < 400; i++) {
vec3 p = ro + rd * t;
float dist = sceneSDF(p, ro);
if (dist < hitThreshold) {
return t;
}
t += dist * 0.5;
if (t > maxDist) break;
}
return maxDist;
}
void main() {
vec2 uv = (gl_FragCoord.xy / u_resolution.xy) * 2.0 - 1.0;
uv.x *= u_resolution.x / u_resolution.y;
vec3 camPos = vec3(0.0 , u_camPosY, u_time * u_speedZ);
camPos.x = waveXOffset(camPos.z, -25.0);
vec3 camForward = normalize(vec3(waveXOffset(camPos.z, -5.0), u_lookAtY, 20.0));
vec3 camRight = normalize(cross(camForward, vec3(0.0, 1.0, 0.0)));
vec3 camUp = cross(camRight, camForward);
vec3 rayDir = getRayDirection(uv, camPos, camForward, camRight, camUp, 1.5);
float dist = rayMarch(camPos, rayDir);
vec3 color = vec3(0.0);
if (dist < 200.0) {
vec3 worldPos = camPos + rayDir * dist;
color += getColor(worldPos, camPos);
}else {
color += sky(uv);
}
gl_FragColor = vec4(color, 1.0);
}
</script>
<canvas id="text" width="400" height="300">this is a test</canvas>
</div>
import { GUI } from "https://cdn.skypack.dev/dat.gui";
const canvas = document.getElementById("glcanvas");
const gl = canvas.getContext("webgl2") || canvas.getContext("webgl");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
function getShaderSource(id) {
return document.getElementById(id).textContent;
}
const vertexShaderSource = getShaderSource("vertex-shader");
const fragmentShaderSource = getShaderSource("fragment-shader");
function createShader(gl, type, source) {
const shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(
"An error occurred compiling the shaders:",
gl.getShaderInfoLog(shader)
);
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error(
"Unable to initialize the shader program:",
gl.getProgramInfoLog(program)
);
return null;
}
return program;
}
const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(
gl,
gl.FRAGMENT_SHADER,
fragmentShaderSource
);
const program = createProgram(gl, vertexShader, fragmentShader);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = [-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
const positionLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.useProgram(program);
const u_terrainHeight = gl.getUniformLocation(program, 'u_terrainHeight');
const u_terrainNoise = gl.getUniformLocation(program, 'u_terrainNoise');
const u_camPosY = gl.getUniformLocation(program, 'u_camPosY');
const u_lookAtY = gl.getUniformLocation(program, 'u_lookAtY');
const u_speedZ = gl.getUniformLocation(program, 'u_speedZ');
const resolutionLocation = gl.getUniformLocation(program, "u_resolution");
const timeLocation = gl.getUniformLocation(program, "u_time");
const gui = new GUI({ width: "100%", closeOnTop: true, closed: true });
const guiParams = {
terrainHeight: 20.0,
terrainNoise: 0.033,
camPosY: 5.0,
lookAtY: 0.0,
speedZ: 4.0,
};
gui.domElement.querySelector(".close-button").innerHTML = "Open Controls";
gl.uniform1f(u_terrainHeight, guiParams.terrainHeight);
gl.uniform1f(u_terrainNoise, guiParams.terrainNoise);
gl.uniform1f(u_camPosY, guiParams.camPosY);
gl.uniform1f(u_lookAtY, guiParams.lookAtY);
gl.uniform1f(u_speedZ, guiParams.speedZ);
gui.add(guiParams, 'terrainHeight', 0.0, 20.0).onChange((value) => {
gl.uniform1f(u_terrainHeight, value);
});
gui.add(guiParams, 'terrainNoise', 0.0, 1.0).onChange((value) => {
gl.uniform1f(u_terrainNoise, value);
});
gui.add(guiParams, 'camPosY', 1.0, 50.0).onChange((value) => {
gl.uniform1f(u_camPosY, value);
});
gui.add(guiParams, 'lookAtY', -200.0, 0.0).onChange((value) => {
gl.uniform1f(u_lookAtY, value);
});
gui.add(guiParams, 'speedZ', 0.0, 100.0).onChange((value) => {
gl.uniform1f(u_speedZ, value);
});
gl.clearColor(0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
let startTime = null;
function render(time) {
if (!startTime) startTime = time; // Set the start time only once.
const elapsedTime = (time - startTime) * 0.001; // Convert time to seconds.
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
gl.uniform1f(timeLocation, elapsedTime); // Pass elapsed time to the shader.
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
requestAnimationFrame(render);
}
resize();
function resize() {
const devicePixelRatio = Math.min(window.devicePixelRatio || 1, 2);
canvas.width = Math.floor(window.innerWidth * devicePixelRatio);
canvas.height = Math.floor(window.innerHeight * devicePixelRatio);
gl.viewport(0, 0, canvas.width, canvas.height);
canvas.style.width = window.innerWidth + "px";
canvas.style.height = window.innerHeight + "px";
document.documentElement.requestFullscreen();
}
window.addEventListener("resize", resize);
requestAnimationFrame(render);
@import url('https://fonts.googleapis.com/css2?family=Lobster&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Permanent+Marker&display=swap');
body {
height`: 100vh;
margin: 0;
}
body, html, #glcanvas {
overflow: hidden
}
.container {
position: relative;
}
canvas {
display: block;
width: 100vw;
height: 100vh;
z-index: -1;
position: fixed;
}
.top-container {
background-color: rgba(0,0,0,0.5);
padding: 75px 0;
text-align: center;
min-width: 100vw;
max-height: 100vh;
}
.header {
background-color: rgba(0,0,0,0.4);
}
.content {
padding: 5px;
}
.sticky {
position: fixed;
top: 0;
width: 100%;
}
.sticky + .content {
padding-top: 102px;
}
@import url("https://fonts.googleapis.com/css2?family=Lobster&display=swap");
h2 {
font-family: "Lobster", cursive;
font-size: 7em;
text-align: center;
}
h4 {
font-family: "Permanent Marker", cursive;
font-weight: 400;
font-style: normal;
font-size: 3em;
}
#text3d {
font-family: Lobster;
text-transform: lowercase;
text-align: center;
color: #000000;
-webkit-text-stroke: 3px orange;
text-shadow: #f9f9f9 3px 5px 5px, #999 16px 8px 3px, #ccc 9px 11px 10px;
}
/* Style the navbar */
#navbar {
position: sticky;
top: 0;
overflow: hidden;
background-color: rgba(100,100,100,0.5);
}
/* Navbar links */
#navbar a {
float: left;
display: block;
color: #f2f2f2;
text-align: center;
padding: 14px;
text-decoration: none;
font-family: "Permanent Marker";
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment