index.vert
#version 300 es
void main() {
float x = float((gl_VertexID & 1) << 2);
float y = float((gl_VertexID & 2) << 1);
gl_Position = vec4(x - 1.0, y - 1.0, 0, 1);
}
index.frag
#version 300 es
precision highp float;
out vec4 fragColor;
uniform vec2 uResolution;
uniform vec2 uMouse;
uniform float uTime;
const float PI = 3.1415926;
vec2 rot2(vec2 p, float angle) {
float s = sin(angle);
float c = cos(angle);
return vec2(c * p.x - s * p.y, s * p.x + c * p.y);
}
vec3 rotX(vec3 p, float angle) {
return vec3(p.x, rot2(p.yz, angle));
}
float checkerd(vec2 p) {
return mod(floor(p.x) + floor(p.y), 2.0);
}
void main() {
vec2 p = (2.0 * gl_FragCoord.xy - uResolution.xy) / min(uResolution.x, uResolution.y);
float angle = uMouse.y / uResolution.y * -0.5 * PI;
vec3 cameraPos = vec3(0.0, 0.0, 0.0);
vec3 cameraDir = vec3(0.0, 0.0, -1.0);
vec3 cameraUp = vec3(0.0, 1.0, 0.0);
cameraDir = rotX(cameraDir, angle);
cameraUp = rotX(cameraUp, angle);
vec3 cameraRight = cross(cameraDir, cameraUp);
float targetDepth = 1.0;
vec3 ray = cameraRight * p.x + cameraUp * p.y + cameraDir * targetDepth;
ray -= cameraPos;
ray = normalize(ray);
vec3 groundNormal = vec3(0.0, 1.0, 0.0);
float rayGroundAngle = dot(ray, groundNormal);
vec3 outColor = vec3(0.0);
if (rayGroundAngle < 0.0) {
float groundHeight = uMouse.x / uResolution.x + 1.0;
vec3 hit = cameraPos - ray * groundHeight / rayGroundAngle;
float texture = checkerd(hit.zx);
outColor = vec3(texture);
}
fragColor = vec4(outColor, 1.0);
}
render.ts
import { Space } from "@/lib/canvas/index"
import { Program } from "@/lib/webgl/program"
import { Timer } from "@/lib/control/timer"
import { Clock } from "@/lib/event/clock"
import { UniformLoader } from "@/lib/webgl/uniform-loader"
import { MouseCoords } from "@/lib/control/mouse-coords"
import vert from "./index.vert?raw"
import frag from "./index.frag?raw"
export const onload = () => {
const space = new Space("gl-canvas")
const canvas = space.canvas
const gl = space.gl
if (!canvas || !gl) return
let timer: Timer
let clock: Clock
let mouse: MouseCoords
const uniforms = new UniformLoader(gl, ["uResolution", "uTime", "uMouse"])
const onResize = () => {
space.fitScreen()
render()
}
const configure = () => {
space.fitScreen()
gl.clearColor(0.0, 0.0, 0.0, 1.0)
gl.clearDepth(1.0)
const program = new Program(gl, vert, frag)
clock = new Clock()
timer = new Timer()
mouse = new MouseCoords(canvas, 0, 0)
uniforms.init(program)
timer.start()
space.onResize = onResize
}
const render = () => {
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
uniforms.float("uTime", timer.elapsed * 0.001)
uniforms.fvector2("uResolution", [canvas.width, canvas.height])
uniforms.fvector2("uMouse", mouse.xy)
gl.drawArrays(gl.TRIANGLE_FAN, 0, 3)
}
const init = () => {
configure()
clock.on("tick", render)
}
init()
}