3d Texturing

Webgl sphere gradient

by schrodingers

HTML

<script src="http://greggman.github.com/webgl-fundamentals/webgl/resources/webgl-utils.js"></script>
<script id="vshader" type="whatever">
    attribute vec4 a_position;
    varying vec3 v_texcoord;
    void main() {
        gl_Position = a_position;
        v_texcoord = a_position.xyz * 0.5 + 0.5;
    }
</script>
<script id="fshader" type="whatever">
    precision mediump float;

    // tex is a texture with each slice of the cube placed in grid in a texture.
    // texCoord is a 3d texture coord
    // size is the size if the cube in pixels.
    // slicesPerRow is how many slices there are across the texture
    // numRows is the number of rows of slices

    vec2 computeSliceOffset(float slice, float slicesPerRow, vec2 sliceSize) {
        return sliceSize * vec2(mod(slice, slicesPerRow),
        floor(slice / slicesPerRow));
    }

    vec4 sampleAs3DTexture(
    sampler2D tex, vec3 texCoord, float size, float numRows, float slicesPerRow) {
        float slice = texCoord.z * size;
        float sliceZ = floor(slice); // slice we need
        float zOffset = fract(slice); // dist between slices

        vec2 sliceSize = vec2(1.0 / slicesPerRow, // u space of 1 slice
        1.0 / numRows); // v space of 1 slice

        vec2 slice0Offset = computeSliceOffset(sliceZ, slicesPerRow, sliceSize);
        vec2 slice1Offset = computeSliceOffset(sliceZ + 1.0, slicesPerRow, sliceSize);

        vec2 slicePixelSize = sliceSize / size; // space of 1 pixel
        vec2 sliceInnerSize = slicePixelSize * (size - 1.0); // space of size pixels

        vec2 uv = slicePixelSize * 0.5 + texCoord.xy * sliceInnerSize;
        vec4 slice0Color = texture2D(tex, slice0Offset + uv);
        vec4 slice1Color = texture2D(tex, slice1Offset + uv);
        return mix(slice0Color, slice1Color, zOffset);
        return slice0Color;
    }

    varying vec3 v_texcoord;

    uniform float u_size;
    uniform float u_numRows;
    uniform float u_slicesPerRow;
    uniform sampler2D u_texture;

 ...

CSS

canvas {
    border: 1px solid black;
    margin: 2px;
}

JavaScript

var canvas = document.getElementById("c");
var gl = canvas.getContext("experimental-webgl");
var program = createProgramFromScripts(
gl, ["vshader", "fshader"], ["a_position"]);
gl.useProgram(program);

var sizeLoc = gl.getUniformLocation(program, "u_size");
var numRowsLoc = gl.getUniformLocation(program, "u_numRows");
var slicesPerRowLoc = gl.getUniformLocation(program, "u_slicesPerRow");

// make sphere triangles
var numDivisionsAround = 32;
var numDivisionsDown = 16;
var verts = [];
for (var v = 0; v < numDivisionsDown; ++v) {
    var v0 = Math.sin((v + 0) / numDivisionsDown * Math.PI);
    var v1 = Math.sin((v + 1) / numDivisionsDown * Math.PI);
    var y0 = Math.cos((v + 0) / numDivisionsDown * Math.PI);
    var y1 = Math.cos((v + 1) / numDivisionsDown * Math.PI);
    for (var h = 0; h < numDivisionsAround; ++h) {
        var a0 = (h + 0) * Math.PI * 2 / numDivisionsAround;
        var a1 = (h + 1) * Math.PI * 2 / numDivisionsAround;
        var x00 = Math.sin(a0) * v0;
        var x10 = Math.sin(a1) * v0;
        var x01 = Math.sin(a0) * v1;
        var x11 = Math.sin(a1) * v1;
        var z00 = Math.cos(a0) * v0;
        var z10 = Math.cos(a1) * v0;
        var z01 = Math.cos(a0) * v1;
        var z11 = Math.cos(a1) * v1;
        verts.push(
        x00, y0, z00,
        x10, y0, z10,
        x01, y1, z01,

        x01, y1, z01,
        x10, y0, z10,
        x11, y1, z11);
    }
}


var vertBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);

// Make 3D texture
var size = 8;
var slicesPerRow = 4;
var numRows = Math.floor((size + slicesPerRow - 1) / slicesPerRow);
var pixels = new Uint8Array(size * slicesPerRow * size * numRows * 4);
var pixelsAcross = slicesPerRow * size;
for (var slice = 0; slice < size; ++slice) {
    var row = Math.floor(slice / slicesPerRow);
    var xOff =...