Map from isometric bar to cube

  • The environmental information is obtained directly using isometric bar projections, but these operations are still relatively expensive
  • The performance of sampling cube maps directly is higher
  • The following HDR is an isometric columnar projection

  • After code conversion to cube map

  • Cubemap vertex shader
export var vs_cubemap =
`#version 300 es precision mediump float; layout (location = 0) in vec3 aPos; out vec3 WorldPos; uniform mat4 projection; uniform mat4 view; void main() { WorldPos = aPos; Gl_Position = projection * view * vec4(WorldPos, 1.0); } `
Copy the code
  • Cubemap element shader (equidistant histogram projection to cubemap)
export var fs_equirectangularToCubemap =
`#version 300 es precision mediump float; out vec4 FragColor; //out uvec4 uFragColor; in vec3 WorldPos; uniform sampler2D equirectangularMap; // By calculating atan(n.z, n.x), U can be obtained, and by calculating asin(n.y), V can be obtained. At the same time, since atan returns results between [−π,π] and asin returns results between [−π/2,π/2], all need to be mapped to [0,1]. / / conversion from (- PI, PI) = > (1/2) - 1/2, and (PI / 2, PI / 2) = > (1/2) - 1/2, const vec2 invAtan = vec2 (0.1591, 0.3183); vec2 SampleSphericalMap(vec3 v) { vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); uv *= invAtan; Uv + = 0.5; return uv; } void main() { vec2 uv = SampleSphericalMap(normalize(WorldPos)); vec3 color = texture(equirectangularMap, uv).rgb; FragColor = vec4 (color, 1.0); //uFragColor = uvec4(100, 0, 0, 1); } `
Copy the code
  • Cubeface vertex shader
export var vs_cubeface =
`#version 300 es precision mediump float; layout (location = 0) in vec3 aPos; //uniform mat4 projection; //uniform mat4 view; uniform float index; uniform float aspectRatio; out vec3 WorldPos; void main() { WorldPos = aPos; Float f = 0.24; vec3 clipPos = f*WorldPos; ClipPos. X = - (1.0 + f + clipPos. X + index * (2.0 + 0.01 * f)); clipPos.y=clipPos.y*aspectRatio; Gl_Position = vec4 (clipPos, 1.0); } `
Copy the code
  • Cubeface slice shader
export var fs_cubeface =
`#version 300 es precision mediump float; out vec4 FragColor; in vec3 WorldPos; uniform samplerCube environmentMap; uniform bool showIntensity; uniform int id; void main() { // I will use the openGL id's for the different sides of the cube // Lefthanded, positive Z is backside cube! // 0 GL_TEXTURE_CUBE_MAP_POSITIVE_X =right // 1 GL_TEXTURE_CUBE_MAP_NEGATIVE_X =left // 2 GL_TEXTURE_CUBE_MAP_POSITIVE_Y  =top // 3 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y =bottom // 4 GL_TEXTURE_CUBE_MAP_POSITIVE_Z =back! // 5 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z =front! // if (showLeftRight) [1, 5, 0, 4] else [2, 4, 3] vec3 cubePos = WorldPos; //if id = 5 (front, negatiev_z) no changes. if (id==1) {cubePos.x = -WorldPos.z; cubePos.z = WorldPos.x; } //left if (id==4) {cubePos.x = -WorldPos.x; cubePos.z =-WorldPos.z; } //back if (id==0) {cubePos.x = WorldPos.z; cubePos.z =-WorldPos.x; } //right if (id==5) {cubePos.x = WorldPos.x; cubePos.z =WorldPos.z; } //front if (id==2) {cubePos.z = WorldPos.y; cubePos.y=WorldPos.z; } //bottom if (id==3) {cubePos.z = -WorldPos.y; cubePos.y=-WorldPos.z; } //top vec3 envColor = texture(environmentMap, cubePos).rgb; If (showIntensity) {if (envColor. R > 1.0 | | envColor. 1.0 g > | | envColor. > 1.0 b) {FragColor = vec4 (1.0, 0.0, 0.0, 1.0); } else {FragColor = vec4(0.0, 0.0, 1.0, 1.0); } return; } // HDR tonemap and gamma correct envColor = envColor/(envColor + vec3(1.0)); (envColor, vec3 envColor = pow (1.0/2.2)); FragColor = vec4 (envColor, 1.0); } `
Copy the code
let captureViews = [
    mat4.lookAt(mat4.create(), vec3.fromValues(0.0.0.0.0.0), vec3.fromValues(1.0.0.0.0.0), vec3.fromValues(0.0, -1.0.0.0)),
    mat4.lookAt(mat4.create(), vec3.fromValues(0.0.0.0.0.0), vec3.fromValues(-1.0.0.0.0.0), vec3.fromValues(0.0, -1.0.0.0)),
    mat4.lookAt(mat4.create(), vec3.fromValues(0.0.0.0.0.0), vec3.fromValues(0.0.1.0.0.0), vec3.fromValues(0.0.0.0.1.0)),
    mat4.lookAt(mat4.create(), vec3.fromValues(0.0.0.0.0.0), vec3.fromValues(0.0, -1.0.0.0), vec3.fromValues(0.0.0.0, -1.0)),
    mat4.lookAt(mat4.create(), vec3.fromValues(0.0.0.0.0.0), vec3.fromValues(0.0.0.0.1.0), vec3.fromValues(0.0, -1.0.0.0)),
    mat4.lookAt(mat4.create(), vec3.fromValues(0.0.0.0.0.0), vec3.fromValues(0.0.0.0, -1.0), vec3.fromValues(0.0, -1.0.0.0))];let hdrTexture;
if (data) {
    let floats = rgbeToFloat(data);
    hdrTexture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, hdrTexture);
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB16F, width, height, 0, gl.RGB, gl.FLOAT, floats);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
}
else {
    console.log("Failed to load HDR image.");
}
function rgbeToFloat(buffer) {
    var s, l = buffer.byteLength >> 2, res = res || new Float32Array(l * 3);
    for (var i = 0; i < l; i++) {
        s = Math.pow(2, buffer[i * 4 + 3] - (128 + 8));
        res[i * 3] = buffer[i * 4] * s;
        res[i * 3 + 1] = buffer[i * 4 + 1] * s;
        res[i * 3 + 2] = buffer[i * 4 + 2] * s;
    }
    return res;
}
function m(a, b) { for (var i in b)
    a[i] = b[i]; returna; };function loadHDR(url, completion) {
    var req = m(new XMLHttpRequest(), { responseType: "arraybuffer" });
    req.onerror = completion.bind(req, false);
    req.onload = function () {
        if (this.status >= 400)
            return this.onerror();
        var header = ' ', pos = 0, d8 = new Uint8Array(this.response), format;
        while(! header.match(/\n\n[^\n]+\n/g))
            header += String.fromCharCode(d8[pos++]);
        format = header.match(/FORMAT=(.*)$/m) [1];
        if(format ! ='32-bit_rle_rgbe')
            return console.warn('unknown format : ' + format), this.onerror();
        var rez = header.split(/\n/).reverse()[1].split(' '), width = +rez[3] * 1, height = +rez[1] * 1;
        var img = new Uint8Array(width * height * 4), ipos = 0;
        for (var j = 0; j < height; j++) {
            var rgbe = d8.slice(pos, pos += 4), scanline = [];
            if (rgbe[0] != 2 || (rgbe[1] != 2) || (rgbe[2] & 0x80)) {
                var len = width, rs = 0;
                pos -= 4;
                while (len > 0) {
                    img.set(d8.slice(pos, pos += 4), ipos);
                    if (img[ipos] == 1 && img[ipos + 1] = =1 && img[ipos + 2] = =1) {
                        for (img[ipos + 3] << rs; i > 0; i--) {
                            img.set(img.slice(ipos - 4, ipos), ipos);
                            ipos += 4;
                            len--;
                        }
                        rs += 8;
                    }
                    else {
                        len--;
                        ipos += 4;
                        rs = 0; }}}else {
                if ((rgbe[2] < <8) + rgbe[3] != width)
                    return console.warn('HDR line mismatch .. '), this.onerror();
                for (var i = 0; i < 4; i++) {
                    var ptr = i * width, ptr_end = (i + 1) * width, buf, count;
                    while (ptr < ptr_end) {
                        buf = d8.slice(pos, pos += 2);
                        if (buf[0] > 128) {
                            count = buf[0] - 128;
                            while (count-- > 0)
                                scanline[ptr++] = buf[1];
                        }
                        else {
                            count = buf[0] - 1;
                            scanline[ptr++] = buf[1];
                            while (count-- > 0) scanline[ptr++] = d8[pos++]; }}}for (var i = 0; i < width; i++) {
                    img[ipos++] = scanline[i];
                    img[ipos++] = scanline[i + width];
                    img[ipos++] = scanline[i + 2 * width];
                    img[ipos++] = scanline[i + 3 * width];
                }
            }
        }
        completion && completion(img, width, height);
    };
    req.open("GET", url, true);
    req.send(null);
    return req;
}
function toCubemap(data, width, height) {
    let captureFBO = gl.createFramebuffer();
    let captureRBO = gl.createRenderbuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, captureFBO);
    gl.bindRenderbuffer(gl.RENDERBUFFER, captureRBO);
    gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT24, whCube, whCube);
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, captureRBO);
    envCubemap = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, envCubemap);
    for (let i = 0; i < 6; ++i) {
        gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA16F, whCube, whCube, 0, gl.RGBA, gl.FLOAT, new Float32Array(whCube * whCube * 4));
    }
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    let captureProjection = mat4.create();
    mat4.perspective(captureProjection, (90.0) * Math.PI / 180.1.0.0.1.10.0);
    equirectangularToCubemapShader.use(gl);
    equirectangularToCubemapShader.setInt(gl, "equirectangularMap".0);
    gl.uniformMatrix4fv(gl.getUniformLocation(equirectangularToCubemapShader.programId, "projection"), false, captureProjection);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, hdrTexture);
    gl.viewport(0.0, whCube, whCube);
    gl.bindFramebuffer(gl.FRAMEBUFFER, captureFBO);
    let error = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
    if(error ! = gl.FRAMEBUFFER_COMPLETE)console.log("framebuf(1) status error= " + error);
    for (let i = 0; i < 6; ++i) {
        gl.uniformMatrix4fv(gl.getUniformLocation(equirectangularToCubemapShader.programId, "view"), false, captureViews[i]);
        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, envCubemap, 0);
        let error = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
        if(error ! = gl.FRAMEBUFFER_COMPLETE)console.log("framebuf(2) status error= " + error);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        renderCube();
    }
    gl.bindFramebuffer(gl.FRAMEBUFFER, null);
    gl.viewport(0.0, canvas.width, canvas.height);
    cubefaceShader.use(gl);
    let projection = mat4.create();
    mat4.perspective(projection, 0.5 * Math.PI, canvas.width / canvas.height, 0.1.10.0);
    gl.uniformMatrix4fv(gl.getUniformLocation(cubefaceShader.programId, "projection"), false, projection);
    animate();
}
function renderCube() {
    if(! cubeVAO) {let vertices = new Float32Array([-1.0, -1.0, -1.0.0.0.0.0, -1.0.0.0.0.0.1.0.1.0, -1.0.0.0.0.0, -1.0.1.0.1.0.1.0, -1.0, -1.0.0.0.0.0, -1.0.1.0.0.0.1.0.1.0, -1.0.0.0.0.0, -1.0.1.0.1.0,
            -1.0, -1.0, -1.0.0.0.0.0, -1.0.0.0.0.0,
            -1.0.1.0, -1.0.0.0.0.0, -1.0.0.0.1.0,
            -1.0, -1.0.1.0.0.0.0.0.1.0.0.0.0.0.1.0, -1.0.1.0.0.0.0.0.1.0.1.0.0.0.1.0.1.0.1.0.0.0.0.0.1.0.1.0.1.0.1.0.1.0.1.0.0.0.0.0.1.0.1.0.1.0,
            -1.0.1.0.1.0.0.0.0.0.1.0.0.0.1.0,
            -1.0, -1.0.1.0.0.0.0.0.1.0.0.0.0.0,
            -1.0.1.0.1.0, -1.0.0.0.0.0.1.0.0.0,
            -1.0.1.0, -1.0, -1.0.0.0.0.0.1.0.1.0,
            -1.0, -1.0, -1.0, -1.0.0.0.0.0.0.0.1.0,
            -1.0, -1.0, -1.0, -1.0.0.0.0.0.0.0.1.0,
            -1.0, -1.0.1.0, -1.0.0.0.0.0.0.0.0.0,
            -1.0.1.0.1.0, -1.0.0.0.0.0.1.0.0.0.1.0.1.0.1.0.1.0.0.0.0.0.1.0.0.0.1.0, -1.0, -1.0.1.0.0.0.0.0.0.0.1.0.1.0.1.0, -1.0.1.0.0.0.0.0.1.0.1.0.1.0, -1.0, -1.0.1.0.0.0.0.0.0.0.1.0.1.0.1.0.1.0.1.0.0.0.0.0.1.0.0.0.1.0, -1.0.1.0.1.0.0.0.0.0.0.0.0.0,
            -1.0, -1.0, -1.0.0.0, -1.0.0.0.0.0.1.0.1.0, -1.0, -1.0.0.0, -1.0.0.0.1.0.1.0.1.0, -1.0.1.0.0.0, -1.0.0.0.1.0.0.0.1.0, -1.0.1.0.0.0, -1.0.0.0.1.0.0.0,
            -1.0, -1.0.1.0.0.0, -1.0.0.0.0.0.0.0,
            -1.0, -1.0, -1.0.0.0, -1.0.0.0.0.0.1.0,
            -1.0.1.0, -1.0.0.0.1.0.0.0.0.0.1.0.1.0.1.0.1.0.0.0.1.0.0.0.1.0.0.0.1.0.1.0, -1.0.0.0.1.0.0.0.1.0.1.0.1.0.1.0.1.0.0.0.1.0.0.0.1.0.0.0,
            -1.0.1.0, -1.0.0.0.1.0.0.0.0.0.1.0,
            -1.0.1.0.1.0.0.0.1.0.0.0.0.0.0.0
        ]);
        cubeVAO = gl.createVertexArray();
        let cubeVBO = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, cubeVBO);
        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
        gl.bindVertexArray(cubeVAO);
        gl.enableVertexAttribArray(0);
        gl.vertexAttribPointer(0.3, gl.FLOAT, false.8 * sizeFloat, 0);
        gl.enableVertexAttribArray(1);
        gl.vertexAttribPointer(1.3, gl.FLOAT, false.8 * sizeFloat, (3 * sizeFloat));
        gl.enableVertexAttribArray(2);
        gl.vertexAttribPointer(2.2, gl.FLOAT, false.8 * sizeFloat, (6 * sizeFloat));
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
        gl.bindVertexArray(null);
    }
    gl.bindVertexArray(cubeVAO);
    gl.drawArrays(gl.TRIANGLES, 0.36);
    gl.bindVertexArray(null);
}
Copy the code
const sizeFloat = 4;
const whCube = 512;
const ext = gl.getExtension("EXT_color_buffer_float");
if(! ext) {console.log("EXT_color_buffer_float needed");
}
let showIntensity = true;
let showLeftRight = true;
let spacePressed = false;
let equirectangularToCubemapShader = null;
let cubefaceShader = null;
let cubeVAO = null;
let quadVAO = null;
let envCubemap = null;
let camera = new Camera(vec3.fromValues(0.0.0.0.3.0), vec3.fromValues(0.0.1.0.0.0));
let deltaTime = 0.0;
let main = function () {
    gl.enable(gl.DEPTH_TEST);
    gl.depthFunc(gl.LEQUAL);
    equirectangularToCubemapShader = new Shader(gl, vs_cubemap, fs_equirectangularToCubemap);
    cubefaceShader = new Shader(gl, vs_cubeface, fs_cubeface);
    cubefaceShader.use(gl);
    cubefaceShader.setInt(gl, "environmentMap".0);
    loadHDR(".. /.. /textures/hdr/newport_loft.hdr", toCubemap); } ();function animate() {
    gl.clearColor(0.1.0.1.0.1.1.0);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    showCubefaces();
    processInput();
    requestAnimationFrame(animate);
}
function showCubefaces() {
    cubefaceShader.setBoolean(gl, "showIntensity", showIntensity);
    if (showLeftRight) {
        [1.5.0.4].forEach((id, index) = > showCubeface(id, index));
    }
    else
        [2.5.3].forEach((id, index) = > showCubeface(id, index));
}
function showCubeface(id, index) {
    cubefaceShader.setFloat(gl, "index", index);
    cubefaceShader.setInt(gl, "id", id);
    cubefaceShader.setFloat(gl, "aspectRatio", canvas.width / canvas.height);
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_CUBE_MAP, envCubemap);
    renderQuad();
}

function renderQuad() {
    if(! quadVAO) {let vertices = new Float32Array([-1.0, -1.0.1.0.0.0.0.0, -1.0.0.0.0.0.1.0.1.0.1.0.0.0.0.0, -1.0.1.0.1.0.1.0, -1.0.1.0.0.0.0.0, -1.0.1.0.0.0.1.0.1.0.1.0.0.0.0.0, -1.0.1.0.1.0,
            -1.0, -1.0.1.0.0.0.0.0, -1.0.0.0.0.0,
            -1.0.1.0.1.0.0.0.0.0, -1.0.0.0.1.0,]); quadVAO = gl.createVertexArray();let quadVBO = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, quadVBO);
        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
        gl.bindVertexArray(quadVAO);
        gl.enableVertexAttribArray(0);
        gl.vertexAttribPointer(0.3, gl.FLOAT, false.8 * sizeFloat, 0);
        gl.enableVertexAttribArray(1);
        gl.vertexAttribPointer(1.3, gl.FLOAT, false.8 * sizeFloat, (3 * sizeFloat));
        gl.enableVertexAttribArray(2);
        gl.vertexAttribPointer(2.2, gl.FLOAT, false.8 * sizeFloat, (6 * sizeFloat));
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
        gl.bindVertexArray(null);
    }
    gl.bindVertexArray(quadVAO);
    gl.drawArrays(gl.TRIANGLES, 0.6);
    gl.bindVertexArray(null);
}


Copy the code