twgl.js/examples/3d-textures-tone-mapping.html
Gregg Tavares 67551111b4 Fix CSS
There was a time when 100vh was correct but mobile browsers changed.
2025-10-13 14:54:12 -07:00

290 lines
7.8 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<!--
@license twgl.js Copyright (c) 2015, Gregg Tavares All Rights Reserved.
Available via the MIT license.
see: http://github.com/greggman/twgl.js for details
-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<meta property="og:title" content="TWGL.js - 3d-textures tone mapping" />
<meta property="og:type" content="website" />
<meta property="og:image" content="http://twgljs.org/examples/screenshots/3d-textures.png" />
<meta property="og:description" content="TWGL.js - 3d-textures tone mapping" />
<meta property="og:url" content="http://twgljs.org" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@greggman">
<meta name="twitter:creator" content="@greggman">
<meta name="twitter:domain" content="twgljs.org">
<meta name="twitter:title" content="TWGL.js - 3d-textures tone mapping">
<meta name="twitter:url" content="http://twgljs.org/examples/3d-textures-tone-mapping.html">
<meta name="twitter:description" content="TWGL.js - 3d-textures tone mapping">
<meta name="twitter:image:src" content="http://twgljs.org/examples/screenshots/3d-textures-tone-mapping.png">
<link href="/resources/images/twgljs-icon.png" rel="shortcut icon" type="image/png">
<title>twgl.js - 3d textures</title>
<style>
html, body {
margin: 0;
font-family: monospace;
color: white;
height: 100%;
}
canvas {
width: 100%;
height: 100%;
}
a {
color: lightblue;
}
#b {
position: absolute;
top: 10px;
right: 10px;
width: 20%;
padding: 1em;
text-align: center;
z-index: 2;
background: rgba(0, 0, 0, 0.8);
}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="b">
<div><a href="http://twgljs.org">twgl.js</a> - 3d-textures tone mapping</div>
<div>style: <span id="name"></span></div>
</div>
</body>
<script src="../dist/7.x/twgl-full.min.js"></script>>
<script type="module">
import * as twgl from '../dist/7.x/twgl-full.module.js';
function main() {
const m4 = twgl.m4;
twgl.setDefaults({attribPrefix: "a_"});
const gl = document.getElementById("c").getContext('webgl2');
if (!twgl.isWebGL2(gl)) {
alert("Sorry, this example requires WebGL 2.0"); // eslint-disable-line
return;
}
const size = 64;
const sizeMinus1 = size - 1;
const original = new Uint8Array(size * size * size * 4);
const inverse = new Uint8Array(size * size * size * 4);
const bw = new Uint8Array(size * size * size * 4);
let offset = 0;
for (let z = 0; z < size; ++z) {
const zv = z * 255 / sizeMinus1;
for (let y = 0; y < size; ++y) {
const yv = y * 255 / sizeMinus1;
for (let x = 0; x < size; ++x) {
const xv = x * 255 / sizeMinus1;
original[offset + 0] = xv;
original[offset + 1] = yv;
original[offset + 2] = zv;
original[offset + 3] = 255;
inverse[offset + 0] = 255 - xv;
inverse[offset + 1] = 255 - yv;
inverse[offset + 2] = 255 - zv;
inverse[offset + 3] = 255;
const m = Math.max(xv, yv, zv);
bw[offset + 0] = m;
bw[offset + 1] = m;
bw[offset + 2] = m;
bw[offset + 3] = 255;
offset += 4;
}
}
}
let images;
const textures = twgl.createTextures(gl, {
image: {
src: "images/tokufuji.jpg",
flipY: true,
colorspaceConversion: gl.NONE,
},
original: {
target: gl.TEXTURE_3D,
src: original,
gwrap: gl.CLAMP_TO_EDGE,
},
blackAndWhite: {
target: gl.TEXTURE_3D,
src: bw,
},
inverse: {
target: gl.TEXTURE_3D,
src: inverse,
},
blacklightPoster: {
target: gl.TEXTURE_3D,
src: "images/color-adjustments/blacklight-poster.png",
colorspaceConversion: gl.NONE,
},
orangeToGreen: {
target: gl.TEXTURE_3D,
src: "images/color-adjustments/orange-to-green.png",
colorspaceConversion: gl.NONE,
},
posterize: {
target: gl.TEXTURE_3D,
src: "images/color-adjustments/posterize.png",
colorspaceConversion: gl.NONE,
},
sepia: {
target: gl.TEXTURE_3D,
src: "images/color-adjustments/sepia.png",
colorspaceConversion: gl.NONE,
},
sunset: {
target: gl.TEXTURE_3D,
src: "images/color-adjustments/sunset.png",
colorspaceConversion: gl.NONE,
},
}, (err, textures, imgs) => {
images = imgs;
requestAnimationFrame(render); // eslint-disable-line
});
const vs = `
#version 300 es
in vec4 a_position;
in vec2 a_texcoord;
out vec2 v_texcoord;
uniform mat4 u_worldViewProjection;
void main() {
v_texcoord = a_texcoord;
gl_Position = u_worldViewProjection * a_position;
}
`;
const fs = `
#version 300 es
precision mediump float;
precision mediump sampler3D;
in vec2 v_texcoord;
uniform sampler2D u_image;
uniform sampler3D u_colorCube1;
uniform sampler3D u_colorCube2;
uniform float u_mixAmount;
out vec4 color;
void main() {
vec3 imageColor = texture(u_image, v_texcoord).rgb;
vec3 cubeSize1 = vec3(textureSize(u_colorCube1, 0));
vec4 color1 = texture(u_colorCube1, (imageColor * (cubeSize1 - 1.) + 0.5) / cubeSize1);
vec3 cubeSize2 = vec3(textureSize(u_colorCube2, 0));
vec4 color2 = texture(u_colorCube2, (imageColor * (cubeSize2 - 1.) + 0.5) / cubeSize2);
color = mix(color1, color2, u_mixAmount);
}
`;
const colorAdjustments = [
"original",
"blackAndWhite",
"inverse",
"sepia",
"blacklightPoster",
"orangeToGreen",
"posterize",
"sunset",
];
const nameNode = document.createTextNode("waiting for textures");
document.querySelector("#name").appendChild(nameNode);
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
const bufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);
const uniforms = {
u_image: textures.image,
u_colorCube1: textures.original,
u_colorCube2: textures.original,
u_worldViewProjection: m4.identity(),
u_mixAmount: 0,
};
function setTexture(uniform, colorNdx) {
const textureName = colorAdjustments[colorNdx % colorAdjustments.length];
uniforms[uniform] = textures[textureName];
}
function easeInOutSine(pos) {
return (-0.5 * (Math.cos(Math.PI * pos) - 1));
}
let colorNdx = 0;
let timer = 0;
let then = 0;
const duration = 3;
let oldMix = -1;
function render(now) {
now *= 0.001;
const deltaTime = now - then;
then = now;
let draw = false;
timer -= deltaTime;
if (timer < 0) {
colorNdx = (colorNdx + 1) % colorAdjustments.length;
setTexture("u_colorCube1", colorNdx);
setTexture("u_colorCube2", colorNdx + 1);
nameNode.nodeValue = colorAdjustments[colorNdx];
timer = duration;
draw = true;
}
uniforms.u_mixAmount = 1 - easeInOutSine(Math.min(1, Math.max(0, timer)));
if (uniforms.u_mixAmount !== oldMix) {
oldMix = uniforms.u_mixAmount;
draw = true;
}
draw |= twgl.resizeCanvasToDisplaySize(gl.canvas);
if (draw) {
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
const img = images.image;
const imgAspect = img.width / img.height;
const screenAspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const aspect = 1 / (screenAspect / imgAspect);
const scale = aspect < 1 ? 1 : 1 / aspect;
m4.ortho(-scale, scale, scale * -aspect, scale * aspect, -1, 1, uniforms.u_worldViewProjection);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
}
requestAnimationFrame(render);
}
}
main();
</script>
</html>