/linear-webgl

WebGL demos, but flat. Because it's more hackable that way.

Primary LanguageHTML

EDIT: this started out with the lofty goals stated below, and quickly just became my scratchpad where I test out random ideas, only most of which are WebGL-related ...

webgl demos in a single file, the way god intended

If you ask me, any attempt to make an abstraction over WebGL ... only makes it more difficult to use.

But don't take it from me, let's look at the numbers:

WebGPU will be nice, but I've been waiting for it since 2018. It's only just been rolled out in a single browser, it will be forever before it makes it to low-end mobile devices, and that's where performance (and therefore clever graphics programming) matters the most.

So raw, unadulterated WebGL it is. Webglfundamentals.org is great, but it's just that: fundamentals. I want scrollbars and dropshadows and examples where those "fundamentals" are used to do real shit.

Ergo: flat, linear WebGL.

Other useful resources in the same vein:

simple

link desc
tri triangle; starting-off point; well, I tri-d.
lines shows how to do constant-screenspace-thickness 3D-based lines.
gazebo simple OBJ model
Screenshot 2024-03-08 at 2 54 01 PM

from cube to simple 3D editor

link desc
cube it's a cube.
cube grid this cube has a grid!
cube camera this cube has a grid AND mouse-based camera controls!
cube gizmos cube, grid, mouse-based camera controls, and "gizmos" (translate, rotate, scale
cube editor everything in gizmos + support for multiple things, undo/redo, etc.
Screenshot 2024-05-06 at 12 48 29 PM

shadows and lighting

link desc
shadow super simple shadow with no PCF, etc. just reprojection
shadow_bake soft shadows + ambient occlusion + shadows dynamically from progressive lightmap
paint technically NOT shadows/lighting, but can be helpful to read alongside them. also silly, messy, and fun!
Screenshot 2024-05-06 at 12 45 15 PM
ok.mov

nodes

interactive data thing with text, drop shadows, zooming, panning, scrollbars, etc.

nodes, nodes-rpi

also: nodes-rpi, a WebGL 1 version that works (~25 fps) at low resolutions on a raspberry pi Model B that only supports WebGL 1

(this was a rewrite of an SVG-based application that got 200ms frametimes (5 fps) on a $3000 macbook)

Screenshot 2024-03-08 at 2 40 15 PM

text

simple text demo, based on mapbox's TinySDF

I've tried a lot of different mechanisms for doing text and this one works the best by far with arbitrary zoom

link desc
text shows off tinysdf, arbitrarily zoomable text on an infinite canvas
text-dropin simpler text (no controls) you can just drop into an existing project
text-clipped example of how to clip text without scissor rects, useful for doing a lot of text with few drawcalls

also: example of how to clip text without scissor rects, useful for doing a lot of text with few drawcalls

Screenshot 2024-03-08 at 2 54 36 PM

quad squad

link desc
quad premultiplied alpha
quad-blur separable gaussian blur
quad-blur-depth separable gaussian blur + depth texture attached to rendertarget
quad-shadow demonstrates prebaking shadow for static geometry so you don't need to redo every frame -- can be easier for layering as well.
quad-woosh some fun with feedback transforms
Screenshot 2024-03-10 at 11 34 47 PM

✨ texture time ✨

link desc
image emoji -> canvas -> texture -> quad -> screen
image_atlas like "image," but demonstrates how to use several images on a single atlas.
galaxy see above + fun with gaussian blur
skybox all that, inside a spinning cube!
shadow has a one-shot function which adds a (customizable) shadow to a texture. pretty handy!
Screenshot 2024-06-04 at 2 32 42 PM Screenshot 2024-05-06 at 12 49 59 PM

🚀 instancing 🚀

link desc
pulling_texture useful when your instances need random access to a buffer of data (e.g. compute-type things)
pulling_buffer useful when your instances can use sequential data from a buffer; output looks just like pulling_texture
graph_slow just calls drawLine; naive, slow, CPU-bound graph
graph_fast exactly the same as graph_slow, but it does the slow part on the GPU.
graph_100k stress test; graphing 100k datapoints in red, and 2 million in blue. works well on M2 Max
graph where I keep the actual good up-to-date graph code.

super performant graph, outperforms chart.js, echarts, amcharts by about x100 Screenshot 2024-06-01 at 9 38 09 PM

errata

I'll fix these eventually, but

I say "high-retina" in almost every demo, where I should say "high-resolution retina" (one brain skip, copy/pasted a million times)

paint.html is the only demo which has a touchscreen rotatable camera, and almost the only demo where the camera doesn't skip if you rotate up too far. (That is just a one-line fix after yaw =.) More work is necessary for many demos to make sure they work on mobile. EDIT: some issues with the touch controls here, needs a rework. Probably need to completely separate this codepath from mouse controls.

On the topic of camera controls, scroll_thick.html and sphere_texture.html have much smoother camera controls than cube_camera, cube_grid, cube_editor, etc. Also probably some other demos which use that camera code outside of the cube family which I have forgotten.

I say "set up premultiplied alpha," then do gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_DST_ALPHA) but the way premultiplied alpha works, the color should be multiplied by ... nothing. gl.ONE. It's premultiplied. So I need to audit transparency in a lot of places. Alternatively, I could keep that "premultiplied alpha" blend func, and simply divide rgb by a in the shader, which may be preferable since premultiplication is lossy. Should note if so though because it's not obvious.

There are some places where things aren't especially "linear" or flat. I do have indirection/object orientation/etc. in some instances. I ought to audit myself to see if I'm doing so tastefully. Or perhaps it simply doesn't matter.

In several .htmls (cube family in particular) input.released is commented "true for a frame after up," when it is actually "true for a frame after down." Not as simple as just updating the comment, because _released shouldn't be the field name.

Pretty much all of the files have a let shaders; { } block, but they switch between vs_shader/fs_shader vs. shader_fs/shader_vs, and this should be homogenized.

errata - optimization

Plenty of matrices are allocated that don't need to be.

Plenty of buffers are recreated every frame when they could be created once at init, and almost everywhere buffers are created dynamically, the TypedArray is created on the fly every frame, and I would prefer to avoid the allocation if possible.

There are examples which do not perform well on my iPhone 8 (2017). Warrants investigation. I suspect the dampedEvent *= 0.8 could be exacerbating things, should probably use a framerate independent approach there.