Cube Map 系列之:手把手教你 实现天空盒(Sky Box)

news2024/12/23 16:42:11

什么是天空盒

在这里插入图片描述

  • An skybox is a box with textures on it to look like the sky in all directions or rather to look like what is very far away including the horizon.
  • 天空盒是一个使用纹理贴图构建的盒子,人在其中朝任何一个方向看去,其纹理彷佛天空一样包裹着视野。

制作天空盒的问题以及如何解决

首先,前面制作环境光贴图和立方体贴图的时候,我们的方式是使用物体的空间坐标,通过投影计算获取纹理坐标,然后进行渲染但是在实现天空盒如果按上述方式,则会存在一些问题。

问题描述以及解决方式

  • 参考下面的图,我们可以看见:
  1. 问题:我们希望天空盒不会超出我们的视界之外,以避免某些位置出现空缺,但是这会导致一些物体被天空盒遮挡
  2. 常见的解决方式是:先绘制天空盒并关闭深度测试,但这会带来性能的损耗,避免不必要的绘制;
  3. 我们的解决方式:
  • 将天空盒的gl_Position固定在[-1, 1]区间,从而可以确保覆盖整个屏幕
  • 将天空盒的gl_Positionz设定为1,从而确保不影响后面的深度测试
  • 通过vp逆矩阵,求得gl_Position的模型坐标,并获取对应天空盒纹理

在这里插入图片描述

开始制作天空盒

效果图

在这里插入图片描述

开肝

下面我们开始在环境光贴图代码的基础上,进行修改

  1. 修改顶点坐标信息以及顶点attribute的绑定方式(将size从3修改为2)
function getGeometry(){
    return new Float32Array(
        [
            -1, -1,
            1, -1,
            -1,  1,
            -1,  1,
            1, -1,
            1,  1,
        ]);
}

// Fill the buffer with the values that define a cube.
function setGeometry(gl, positions) {
	const positionLocation = gl.getAttribLocation(gl.program, "a_position");
	
	const positionBuffer = gl.createBuffer();
	gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
	gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
	
	gl.enableVertexAttribArray(positionLocation);
	const size = 2;
	const type = gl.FLOAT;
	const normalize = false;
	const stride = 0;
	const offset = 0;
	gl.vertexAttribPointer(positionLocation, size, type, normalize, stride, offset);
}
  1. 注释setNormals(gl, getNormals())
  2. 修改顶点着色器
// 传递进来的a_position范围为[-1, 1] 确保覆盖整个屏幕
// 将`gl_Position`的z设定为`1`,从而确保不影响后面的深度测试
 const V_SHADER_SOURCE = '' +
      'attribute vec4 a_position;' +
      'varying vec4 v_position;' +
      'void main(){' +
      'v_position = a_position;' +
      'gl_Position = a_position;' +
      'gl_Position.z = 1.0;}'
  1. 计算viewDirectionProjectionInverse矩阵 并传递
function setVPInverse(gl, time){
	const skyboxLocation = gl.getUniformLocation(gl.program, "u_skybox");
	const viewDirectionProjectionInverseLocation =
	gl.getUniformLocation(gl.program, "u_viewDirectionProjectionInverse");
	
	
	// Set the uniforms
	gl.uniformMatrix4fv(
	viewDirectionProjectionInverseLocation,false,getVPInverse(time));
	gl.uniform1i(skyboxLocation, 0);
}
  1. 修改片元着色器
const F_SHADER_SOURCE = '' +
	'precision mediump float;' +
	'uniform samplerCube u_skybox;' +
	'uniform mat4 u_viewDirectionProjectionInverse;' +
	'varying vec4 v_position;' +
	'void main(){' +
	'vec4 t = u_viewDirectionProjectionInverse * v_position;' +
	'gl_FragColor = textureCube(u_skybox, normalize(t.zyx / t.w));' +
	'}'
  1. 设定深度测试函数
setVPInverse(gl, time);
// let our quad pass the depth test at 1.0
gl.depthFunc(gl.LEQUAL);
// Draw the geometry.
gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CubeMap</title>
</head>
<body>
<script src="https://webglfundamentals.org/webgl/resources/m4.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<canvas id="canvas" style="height: 100%; width:100%"></canvas>
<script>
    const V_SHADER_SOURCE = '' +
        'attribute vec4 a_position;' +
        'varying vec4 v_position;' +
        'void main(){' +
        'v_position = a_position;' +
        'gl_Position = a_position;' +
        'gl_Position.z = 1.0;}'


    const F_SHADER_SOURCE = '' +
        'precision mediump float;' +
        'uniform samplerCube u_skybox;' +
        'uniform mat4 u_viewDirectionProjectionInverse;' +
        'varying vec4 v_position;' +
        'void main(){' +
        'vec4 t = u_viewDirectionProjectionInverse * v_position;' +
        'gl_FragColor = textureCube(u_skybox, normalize(t.zyx / t.w));' +
        '}'


    function main(){
        // Get A WebGL context
        /** @type {HTMLCanvasElement} */
        const canvas = document.querySelector("#canvas");
        const gl = canvas.getContext("webgl");
        if (!gl) {
            return;
        }

        if (!initShaders(gl, V_SHADER_SOURCE, F_SHADER_SOURCE)){
            console.log('Failed to initialize shaders.');
            return;
        }

        setGeometry(gl, getGeometry());
        // setNormals(gl, getNormals())
        setTexture(gl)


        function radToDeg(r) {
            return r * 180 / Math.PI;
        }

        function degToRad(d) {
            return d * Math.PI / 180;
        }

        const fieldOfViewRadians = degToRad(60);
        let modelXRotationRadians = degToRad(0);
        let modelYRotationRadians = degToRad(0);

        // Get the starting time.
        let then = 0;

        requestAnimationFrame(drawScene);

        function drawScene(time){
            gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
            gl.enable(gl.CULL_FACE);
            gl.enable(gl.DEPTH_TEST);

            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

            gl.useProgram(gl.program);


            setVPInverse(gl, time);
            // let our quad pass the depth test at 1.0
            gl.depthFunc(gl.LEQUAL);
            // Draw the geometry.
            gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);

            requestAnimationFrame(drawScene);
        }

        function setVPInverse(gl, time){
            const skyboxLocation = gl.getUniformLocation(gl.program, "u_skybox");
            const viewDirectionProjectionInverseLocation =
                gl.getUniformLocation(gl.program, "u_viewDirectionProjectionInverse");


            // Set the uniforms
            gl.uniformMatrix4fv(
                viewDirectionProjectionInverseLocation,
                false,
                getVPInverse(time));

            gl.uniform1i(skyboxLocation, 0);
        }

        function getVPInverse(time){
            time *= 0.001;
            const deltaTime = time - then;
            then = time;

            webglUtils.resizeCanvasToDisplaySize(gl.canvas);
            modelXRotationRadians += -0.7 * deltaTime;
            modelYRotationRadians += -0.4 * deltaTime;
            // Compute the projection matrix
            const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
            const projectionMatrix =
                m4.perspective(fieldOfViewRadians, aspect, 1, 2000);

            const cameraPosition = [Math.cos(time * .1), 0, Math.sin(time * .1)];
            const target = [0, 0, 0];
            const up = [0, 1, 0];

            // Compute the camera's matrix using look at.
            const cameraMatrix = m4.lookAt(cameraPosition, target, up);

            // Make a view matrix from the camera matrix.
            const viewMatrix = m4.inverse(cameraMatrix);

            // We only care about direction so remove the translation
            viewMatrix[12] = 0;
            viewMatrix[13] = 0;
            viewMatrix[14] = 0;

            const viewDirectionProjectionMatrix =
                m4.multiply(projectionMatrix, viewMatrix);
            return m4.inverse(viewDirectionProjectionMatrix);
        }

    }

    /**
     * create a program object and make current
     * @param gl GL context
     * @param vShader  a vertex shader program (string)
     * @param fShader   a fragment shader program(string)
     */
    function initShaders(gl, vShader, fShader){
        const program = createProgram(gl, vShader, fShader);
        if (!program){
            console.log("Failed to create program");
            return false;
        }

        gl.useProgram(program);
        gl.program = program;

        return true;
    }

    /**
     * create a program object and make current
     * @param gl GL context
     * @param vShader  a vertex shader program (string)
     * @param fShader   a fragment shader program(string)
     */
    function createProgram(gl, vShader, fShader){
        const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vShader);
        const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fShader);

        if (!vertexShader || !fragmentShader){
            return null;
        }

        const program = gl.createProgram();
        if (!program){
            return null;
        }

        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);

        gl.linkProgram(program);

        const linked = gl.getProgramParameter(program, gl.LINK_STATUS);
        if (!linked){
            const error = gl.getProgramInfoLog(program);
            console.log('Failed to link program: ' + error);
            gl.deleteProgram(program);
            gl.deleteShader(vertexShader);
            gl.deleteShader(fragmentShader);
        }
        return program;
    }

    /**
     *
     * @param gl GL context
     * @param type  the type of the shader object to be created
     * @param source    shader program (string)
     */
    function loadShader(gl, type, source){
        const shader = gl.createShader(type);
        if (shader == null){
            console.log('unable to create shader');
            return null;
        }

        gl.shaderSource(shader, source);

        gl.compileShader(shader);

        const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
        if (!compiled){
            const error = gl.getShaderInfoLog(shader);
            console.log('Failed to compile shader: ' + error);
            gl.deleteShader(shader);
            return null;
        }

        return shader;
    }


    function getGeometry(){
        return new Float32Array(
            [
                -1, -1,
                1, -1,
                -1,  1,
                -1,  1,
                1, -1,
                1,  1,
            ]);

    }
    // Fill the buffer with the values that define a cube.
    function setGeometry(gl, positions) {
        const positionLocation = gl.getAttribLocation(gl.program, "a_position");

        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);

        gl.enableVertexAttribArray(positionLocation);
        const size = 2;
        const type = gl.FLOAT;
        const normalize = false;
        const stride = 0;
        const offset = 0;
        gl.vertexAttribPointer(positionLocation, size, type, normalize, stride, offset);

    }


    function setTexture(gl){

        // Create a texture.
        const texture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);

        const ctx = document.createElement("canvas").getContext("2d");

        ctx.canvas.width = 128;
        ctx.canvas.height = 128;

        const faceInfos = [
            {
                target: gl.TEXTURE_CUBE_MAP_POSITIVE_X,
                url: 'resources/pos-x.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
                url: 'resources/neg-x.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
                url: 'resources/pos-y.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
                url: 'resources/neg-y.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
                url: 'resources/pos-z.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
                url: 'resources/neg-z.jpg',
            },
        ];

        faceInfos.forEach((faceInfo) => {
            const {target, url} = faceInfo;

            // Upload the canvas to the cube map face.
            const level = 0;
            const internalFormat = gl.RGBA;
            const width = 512;
            const height = 512;
            const format = gl.RGBA;
            const type = gl.UNSIGNED_BYTE;
            gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, null);

            const image = new Image();
            image.src = url;
            image.addEventListener("load", function (){
                gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
                gl.texImage2D(target, level, internalFormat, format, type, image);
                gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
            })


        })

        gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);

    }
    function setNormals(gl, normal){
        const normalBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, normal, gl.STATIC_DRAW);
        //
        const normalLocation = gl.getAttribLocation(gl.program, "a_normal");
        gl.enableVertexAttribArray(normalLocation);
        const size = 3;
        const type = gl.FLOAT;
        const normalize = false;
        const stride = 0;
        const offset = 0;
        gl.vertexAttribPointer(normalLocation, size, type, normalize, stride, offset);
    }

    function getNormals() {
        return new Float32Array(
            [
                0, 0, -1,
                0, 0, -1,
                0, 0, -1,
                0, 0, -1,
                0, 0, -1,
                0, 0, -1,

                0, 0, 1,
                0, 0, 1,
                0, 0, 1,
                0, 0, 1,
                0, 0, 1,
                0, 0, 1,

                0, 1, 0,
                0, 1, 0,
                0, 1, 0,
                0, 1, 0,
                0, 1, 0,
                0, 1, 0,

                0, -1, 0,
                0, -1, 0,
                0, -1, 0,
                0, -1, 0,
                0, -1, 0,
                0, -1, 0,

                -1, 0, 0,
                -1, 0, 0,
                -1, 0, 0,
                -1, 0, 0,
                -1, 0, 0,
                -1, 0, 0,

                1, 0, 0,
                1, 0, 0,
                1, 0, 0,
                1, 0, 0,
                1, 0, 0,
                1, 0, 0,
            ]);
    }
    main()

</script>
</body>
</html>

添加Cube对象以及环境光贴图

  • 下面我们按照之前的操作,重新添加Cube对象,并进行环境光贴图

效果图

在这里插入图片描述

完整代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>CubeMap</title>
</head>
<body>
<script src="https://webglfundamentals.org/webgl/resources/m4.js"></script>
<script src="https://webglfundamentals.org/webgl/resources/webgl-utils.js"></script>
<canvas id="canvas" style="height: 100%; width:100%"></canvas>
<script>
    const V_SHADER_SOURCE = '' +
        'attribute vec4 a_position;' +
        'varying vec4 v_position;' +
        'void main(){' +
        'v_position = a_position;' +
        'gl_Position = a_position;' +
        'gl_Position.z = 1.0;}'


    const F_SHADER_SOURCE = '' +
        'precision mediump float;' +
        'uniform samplerCube u_skybox;' +
        'uniform mat4 u_viewDirectionProjectionInverse;' +
        'varying vec4 v_position;' +
        'void main(){' +
        'vec4 t = u_viewDirectionProjectionInverse * v_position;' +
        'gl_FragColor = textureCube(u_skybox, normalize(t.zyx / t.w));' +
        '}'

    const V_Environment_SHADER_SOURCE = '' +
        'attribute vec4 a_position;' +
        'attribute vec3 a_normal;' +
        'uniform mat4 u_projection;' +
        'uniform mat4 u_view;' +
        'uniform mat4 u_world;' +
        'varying vec3 v_worldPosition;' +
        'varying vec3 v_worldNormal;' +
        'void main(){' +
        'gl_Position = u_projection * u_view * u_world * a_position;' +
        'v_worldPosition = (u_world * a_position).xyz;' +
        'v_worldNormal = mat3(u_world) * a_normal;' +
        '}'

    const F_Environment_SHADER_SOURCE = '' +
        'precision mediump float;' +
        'varying vec3 v_worldPosition;' +
        'varying vec3 v_worldNormal;' +
        'uniform samplerCube u_texture;' +
        'uniform vec3 u_worldCameraPosition;' +
        'void main(){' +
        'vec3 worldNormal = normalize(v_worldNormal);' +
        'vec3 eyeToSurfaceDir = normalize(v_worldPosition - u_worldCameraPosition);' +
        'vec3 direction = reflect(eyeToSurfaceDir, worldNormal);' +
        ' gl_FragColor = textureCube(u_texture, direction);' +
        '}'


    function main(){
        // Get A WebGL context
        /** @type {HTMLCanvasElement} */
        const canvas = document.querySelector("#canvas");
        const gl = canvas.getContext("webgl");
        if (!gl) {
            return;
        }

        //
        setTexture(gl)


        function radToDeg(r) {
            return r * 180 / Math.PI;
        }

        function degToRad(d) {
            return d * Math.PI / 180;
        }

        const fieldOfViewRadians = degToRad(60);
        // Get the starting time.
        let then = 0;

        requestAnimationFrame(drawScene);

        function drawScene(time){
            gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
            gl.enable(gl.CULL_FACE);
            gl.enable(gl.DEPTH_TEST);

            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

            // 绘制cube
            // 绘制skybox
            if (!initShaders(gl, V_Environment_SHADER_SOURCE, F_Environment_SHADER_SOURCE)){
                console.log('Failed to initialize shaders.');
                return;
            }

            const {
                projectionMatrix,
                viewMatrix,
                worldMatrix,
                cameraPosition,
                viewDirectionProjectionInverseMatrix
            } = getUniforms(time);

            gl.useProgram(gl.program);
            setGeometry2(gl, getGeometry2());
            setNormals(gl, getNormals())
            setCubeUniform(gl, projectionMatrix, viewMatrix, worldMatrix, cameraPosition);
            gl.depthFunc(gl.LESS);
            // Draw the geometry.
            gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);

            // 绘制skybox
            if (!initShaders(gl, V_SHADER_SOURCE, F_SHADER_SOURCE)){
                console.log('Failed to initialize shaders.');
                return;
            }
            gl.useProgram(gl.program);

            setGeometry(gl, getGeometry());
            setSkyBoxUniform(gl, viewDirectionProjectionInverseMatrix)
            // let our quad pass the depth test at 1.0
            gl.depthFunc(gl.LEQUAL);
            // Draw the geometry.
            gl.drawArrays(gl.TRIANGLES, 0, 6 * 6);

            requestAnimationFrame(drawScene);
        }

        function getUniforms(time){
            time *= 0.001;
            const deltaTime = time - then;
            then = time;
            webglUtils.resizeCanvasToDisplaySize(gl.canvas);

            // Compute the projection matrix
            const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
            const projectionMatrix =
                m4.perspective(fieldOfViewRadians, aspect, 1, 2000);

            const cameraPosition = [Math.cos(time * .1) * 2, 0, Math.sin(time * .1) * 2];
            const target = [0, 0, 0];
            const up = [0, 1, 0];

            // Compute the camera's matrix using look at.
            const cameraMatrix = m4.lookAt(cameraPosition, target, up);

            // Make a view matrix from the camera matrix.
            const viewMatrix = m4.inverse(cameraMatrix);

            let worldMatrix = m4.xRotation(time * 0.11);;

            // We only care about direction so remove the translation
            const viewDirectionMatrix = m4.copy(viewMatrix);
            viewDirectionMatrix[12] = 0;
            viewDirectionMatrix[13] = 0;
            viewDirectionMatrix[14] = 0;

            const viewDirectionProjectionMatrix =
                m4.multiply(projectionMatrix, viewDirectionMatrix);
            const viewDirectionProjectionInverseMatrix =
                m4.inverse(viewDirectionProjectionMatrix);

            return {projectionMatrix, viewMatrix, worldMatrix, cameraPosition, viewDirectionProjectionInverseMatrix}
        }

        function setCubeUniform(gl, projectionMatrix, viewMatrix, worldMatrix, cameraPosition){
            const projectionLocation = gl.getUniformLocation(gl.program, "u_projection");
            const viewLocation = gl.getUniformLocation(gl.program, "u_view");
            const worldLocation = gl.getUniformLocation(gl.program, "u_world");
            const textureLocation = gl.getUniformLocation(gl.program, "u_texture");
            const worldCameraPositionLocation = gl.getUniformLocation(gl.program, "u_worldCameraPosition");


            // Set the uniforms
            gl.uniformMatrix4fv(projectionLocation, false, projectionMatrix);
            gl.uniformMatrix4fv(viewLocation, false, viewMatrix);
            gl.uniformMatrix4fv(worldLocation, false, worldMatrix);
            gl.uniform3fv(worldCameraPositionLocation, cameraPosition);
            gl.uniform1i(textureLocation, 0);
        }

        function setSkyBoxUniform(gl, viewDirectionProjectionInverseMatrix){
            const skyboxLocation = gl.getUniformLocation(gl.program, "u_skybox");
            const viewDirectionProjectionInverseLocation =
                gl.getUniformLocation(gl.program, "u_viewDirectionProjectionInverse");

            // Set the uniforms
            gl.uniformMatrix4fv(
                viewDirectionProjectionInverseLocation,
                false,
            viewDirectionProjectionInverseMatrix);

            gl.uniform1i(skyboxLocation, 0);
        }

    }

    /**
     * create a program object and make current
     * @param gl GL context
     * @param vShader  a vertex shader program (string)
     * @param fShader   a fragment shader program(string)
     */
    function initShaders(gl, vShader, fShader){
        const program = createProgram(gl, vShader, fShader);
        if (!program){
            console.log("Failed to create program");
            return false;
        }

        gl.useProgram(program);
        gl.program = program;

        return true;
    }

    /**
     * create a program object and make current
     * @param gl GL context
     * @param vShader  a vertex shader program (string)
     * @param fShader   a fragment shader program(string)
     */
    function createProgram(gl, vShader, fShader){
        const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vShader);
        const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fShader);

        if (!vertexShader || !fragmentShader){
            return null;
        }

        const program = gl.createProgram();
        if (!program){
            return null;
        }

        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);

        gl.linkProgram(program);

        const linked = gl.getProgramParameter(program, gl.LINK_STATUS);
        if (!linked){
            const error = gl.getProgramInfoLog(program);
            console.log('Failed to link program: ' + error);
            gl.deleteProgram(program);
            gl.deleteShader(vertexShader);
            gl.deleteShader(fragmentShader);
        }
        return program;
    }

    /**
     *
     * @param gl GL context
     * @param type  the type of the shader object to be created
     * @param source    shader program (string)
     */
    function loadShader(gl, type, source){
        const shader = gl.createShader(type);
        if (shader == null){
            console.log('unable to create shader');
            return null;
        }

        gl.shaderSource(shader, source);

        gl.compileShader(shader);

        const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
        if (!compiled){
            const error = gl.getShaderInfoLog(shader);
            console.log('Failed to compile shader: ' + error);
            gl.deleteShader(shader);
            return null;
        }

        return shader;
    }


    function getGeometry(){
        return new Float32Array(
            [
                -1, -1,
                1, -1,
                -1,  1,
                -1,  1,
                1, -1,
                1,  1,
            ]);

    }
    // Fill the buffer with the values that define a cube.
    function setGeometry(gl, positions) {
        const positionLocation = gl.getAttribLocation(gl.program, "a_position");

        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);

        gl.enableVertexAttribArray(positionLocation);
        const size = 2;
        const type = gl.FLOAT;
        const normalize = false;
        const stride = 0;
        const offset = 0;
        gl.vertexAttribPointer(positionLocation, size, type, normalize, stride, offset);

    }


    function setTexture(gl){

        // Create a texture.
        const texture = gl.createTexture();
        gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);

        const ctx = document.createElement("canvas").getContext("2d");

        ctx.canvas.width = 128;
        ctx.canvas.height = 128;

        const faceInfos = [
            {
                target: gl.TEXTURE_CUBE_MAP_POSITIVE_X,
                url: 'resources/pos-x.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_NEGATIVE_X,
                url: 'resources/neg-x.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_POSITIVE_Y,
                url: 'resources/pos-y.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Y,
                url: 'resources/neg-y.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_POSITIVE_Z,
                url: 'resources/pos-z.jpg',
            },
            {
                target: gl.TEXTURE_CUBE_MAP_NEGATIVE_Z,
                url: 'resources/neg-z.jpg',
            },
        ];

        faceInfos.forEach((faceInfo) => {
            const {target, url} = faceInfo;

            // Upload the canvas to the cube map face.
            const level = 0;
            const internalFormat = gl.RGBA;
            const width = 512;
            const height = 512;
            const format = gl.RGBA;
            const type = gl.UNSIGNED_BYTE;
            gl.texImage2D(target, level, internalFormat, width, height, 0, format, type, null);

            const image = new Image();
            image.src = url;
            image.addEventListener("load", function (){
                gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture);
                gl.texImage2D(target, level, internalFormat, format, type, image);
                gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
            })


        })

        gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);

    }
    function setNormals(gl, normal){
        const normalBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, normal, gl.STATIC_DRAW);
        //
        const normalLocation = gl.getAttribLocation(gl.program, "a_normal");
        gl.enableVertexAttribArray(normalLocation);
        const size = 3;
        const type = gl.FLOAT;
        const normalize = false;
        const stride = 0;
        const offset = 0;
        gl.vertexAttribPointer(normalLocation, size, type, normalize, stride, offset);
    }

    function getNormals() {
        return new Float32Array(
            [
                0, 0, -1,
                0, 0, -1,
                0, 0, -1,
                0, 0, -1,
                0, 0, -1,
                0, 0, -1,

                0, 0, 1,
                0, 0, 1,
                0, 0, 1,
                0, 0, 1,
                0, 0, 1,
                0, 0, 1,

                0, 1, 0,
                0, 1, 0,
                0, 1, 0,
                0, 1, 0,
                0, 1, 0,
                0, 1, 0,

                0, -1, 0,
                0, -1, 0,
                0, -1, 0,
                0, -1, 0,
                0, -1, 0,
                0, -1, 0,

                -1, 0, 0,
                -1, 0, 0,
                -1, 0, 0,
                -1, 0, 0,
                -1, 0, 0,
                -1, 0, 0,

                1, 0, 0,
                1, 0, 0,
                1, 0, 0,
                1, 0, 0,
                1, 0, 0,
                1, 0, 0,
            ]);
    }

    function getGeometry2(){
        return new Float32Array(
            [
                -0.5, -0.5, -0.5,
                -0.5, 0.5, -0.5,
                0.5, -0.5, -0.5,
                -0.5, 0.5, -0.5,
                0.5, 0.5, -0.5,
                0.5, -0.5, -0.5,

                -0.5, -0.5, 0.5,
                0.5, -0.5, 0.5,
                -0.5, 0.5, 0.5,
                -0.5, 0.5, 0.5,
                0.5, -0.5, 0.5,
                0.5, 0.5, 0.5,

                -0.5, 0.5, -0.5,
                -0.5, 0.5, 0.5,
                0.5, 0.5, -0.5,
                -0.5, 0.5, 0.5,
                0.5, 0.5, 0.5,
                0.5, 0.5, -0.5,

                -0.5, -0.5, -0.5,
                0.5, -0.5, -0.5,
                -0.5, -0.5, 0.5,
                -0.5, -0.5, 0.5,
                0.5, -0.5, -0.5,
                0.5, -0.5, 0.5,

                -0.5, -0.5, -0.5,
                -0.5, -0.5, 0.5,
                -0.5, 0.5, -0.5,
                -0.5, -0.5, 0.5,
                -0.5, 0.5, 0.5,
                -0.5, 0.5, -0.5,

                0.5, -0.5, -0.5,
                0.5, 0.5, -0.5,
                0.5, -0.5, 0.5,
                0.5, -0.5, 0.5,
                0.5, 0.5, -0.5,
                0.5, 0.5, 0.5,

            ]);

    }
    // Fill the buffer with the values that define a cube.
    function setGeometry2(gl, positions) {
        const positionLocation = gl.getAttribLocation(gl.program, "a_position");

        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);

        gl.enableVertexAttribArray(positionLocation);
        const size = 3;
        const type = gl.FLOAT;
        const normalize = false;
        const stride = 0;
        const offset = 0;
        gl.vertexAttribPointer(positionLocation, size, type, normalize, stride, offset);

    }


    main()

</script>
</body>
</html>

参考资料

WebGPUEngine-Wiki

WebGL Cubemaps

WebGL Environment Maps (reflections)

WebGL SkyBox

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/544366.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java版本企业工程管理系统软件源码 自主研发,工程行业适用

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&#xff09;项目显示…

Linux【工具 02】OpenStreetMap数据处理工具OSMCTools下载安装使用举例(osmconvert命令说明)

OSMCTools安装使用实例 1.Tools2.官网安装步骤3.实际安装步骤3.1 环境3.2 步骤 4.工具使用实例 OpenStreetMap的下载地址&#xff1a;Geofabrik Download Server。 OSMCTools的GitHub地址&#xff1a;https://github.com/ramunasd/osmctools Windows操作系统&#xff0c;可以…

MyBatis之注解开发

除了XML映射方式&#xff0c;MyBatis还支持注解方式实现POJO对象和数据表之间的关联映射&#xff0c;使用注解的方式一般将SQL语句直接写到接口上。与XML的映射方式相比&#xff0c;基于注解的映射方式相对简单。Mybatis提供的注解有&#xff1a; 1.环境准备 1.1 数据库准备…

C语言函数大全-- _w 开头的函数(3)

C语言函数大全 本篇介绍C语言函数大全-- _w 开头的函数 1. _wmkdir 1.1 函数说明 函数声明函数功能int _wmkdir(const wchar_t* dirname);用于创建指定路径名的新目录 参数&#xff1a; dirname &#xff1a; 指向以 null 结尾的宽字符数组&#xff0c;该数组包含要创建的目…

客户管理系统软件怎么用?

阅读本文您将了解&#xff1a;1.客户管理系统的作用&#xff1b;2.客户管理系统软件怎么用&#xff1b;3.客户管理的注意事项。 一、客户管理系统的作用 客户是企业的重要财富&#xff0c;因此客户管理是企业发展过程中至关重要的一部分&#xff0c;那么客户管理怎么做&#…

《编码——隐匿在计算机软硬件背后的语言》精炼——第17章收尾

古之立大事者,不惟有超世之才,亦必有坚忍不拔之志。——苏轼 文章目录 数字计算机硬件软件 数字计算机 数字计算机分为硬件和软件两部分&#xff0c;硬件是组成计算机的设备&#xff0c;软件是输入计算机的指令和数值。之所以将它们区分&#xff0c;是因为相对于硬件而言&…

照片从安卓手机中消失了?让他们恢复回来的几个方法请收好

“我安卓上的所有照片都消失了&#xff0c;我的照片去哪儿了” “我安卓上的所有照片都不见了” “下载的图片从安卓上消失了” …… 您是否遇到类似的问题&#xff1f;导致Android手机照片丢失的原因有很多&#xff0c;例如软件更新、误删、误操作、系统崩溃、应用程序崩溃、…

【算法】——动态规划题目讲解

本期继续为大家带来的是关于动态规划类题目的讲解&#xff0c;对于这类题目大家一定要多加练习&#xff0c;争取掌握。 &#xff08;一&#xff09;不同路径 链接如下&#xff1a;62. 不同路径 题目如下&#xff1a; 算法思路&#xff1a; 1. 状态表⽰&#xff1a; 对于这种「…

【FMC200】基于FMC标准的1路CameraLink Full 输出子卡模块

产品概述 FMC200是一款CameraLink发送FMC子卡模块&#xff0c;该模块支持2路CameraLink Base模式或者1路CameraLink Full模式的图像信号输出。板卡具有2个CameraLink端口&#xff08;SDR26&#xff09;&#xff0c;可以作为模拟相机的输出。 技术指标 图像接口性能&#xff1a…

202305-第二周资讯

山川软件愿为您提供最优质的服务。 您的每一个疑问都会被认真对待&#xff0c;您的每一个建议都将都会仔细思考。 我们希望人人都能分析大数据&#xff0c;人人都能搭建应用。 因此我们将不断完善DEMO、文档、以及视频&#xff0c;期望能在最大程度上快速帮助用户快速解决问…

高效易懂,打造维护性好的Web自动化测试框架PO模式精讲

目录 前言&#xff1a; 一、 PO概述 二、PO何实现于Web框架素自动化测试重中之重。 1.为了保证易维护性和易读性&#xff0c;我们可以在项目中定义一个统一的库&#xff0c;用来存放所有的定位器类。 2.定义一个基础的类&#xff0c;该类用于针对PO的元素定位进行封装。 3…

Visual Studio 2022 17.7 发布首个预览版

Visual Studio 2022 17.7 已发布首个预览版&#xff0c;这个版本有大量社区贡献的新改进&#xff0c;主要改动如下&#xff1a; 生产效率 文件对比功能&#xff0c;可以在 Solution Explorer 中对比不同的文件差异。在资源管理器中右键单击一个文件&#xff0c;然后使用上下文…

Java 中 Token 是什么,有哪些用途

简介 Token 是一种身份验证机制&#xff0c;通常由服务器生成并返回给客户端&#xff0c;客户端在后续的请求中携带 Token&#xff0c;以证明自己的身份。在 Java 中&#xff0c;Token 的应用场景非常广泛&#xff0c;例如用户登录、API 认证、OAuth 授权等等。 在用户登录的…

Hash索引和B+树

Hash索引和B树所有有什么区别或者说优劣呢? 首先要知道Hash索引和B树索引的底层实现原理&#xff1a; hash索引底层就是hash表&#xff0c;进行查找时&#xff0c;调用一次hash函数就可以获取到相应的键值&#xff0c;之后进行回表查询获得实际数据。B树底层实现是多路平衡查…

晨控CK-GW208-EC与欧姆龙PLC工业EtherCAT协议通讯指南

晨控CK-GW208-EC与欧姆龙PLC工业EtherCAT协议通讯指南 EtherCAT 是一种实时以太网络通讯协议&#xff0c;旨在解决传统现场总线系统在数据传输速率和复杂性方面的限制。相比传统现场总线&#xff0c;EtherCAT 的数据传输速率有了极大的提升&#xff0c;同时&#xff0c;EtherC…

借《2023年Q1TikTok电商带货达人趋势分析报告》教你分析TikTok数据报告

现今TikTok的电商业务正进入爆发期。在众多跨境电商的商业营销中&#xff0c;许多商家把TikTok作为重点选择的平台&#xff0c;期望能搭上这波海外流量红利的巨轮。TikTok营销正越来越受商家青睐和使用。那么作为TikTok电商商家&#xff0c;该如何挑选高匹配、高ROI的带货达人&…

公司招了一个00后,以为是个小年轻,没想到人家是个卷王...

公司前段缺人&#xff0c;也面了不少测试&#xff0c;结果竟然没有一个合适的。一开始瞄准的就是中级的水准&#xff0c;也没指望来大牛&#xff0c;提供的薪资也不低&#xff0c;面试的人很多&#xff0c;但平均水平很让人失望。 令我印象最深的是一个00后测试员&#xff0c;…

基于αβ剪枝算法的五子棋

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 五子棋是世界智力运动会竞技项目之一&#xff0c;是一种两人对弈的纯策略型棋类游戏&#xff0c;是世界智力运动会竞技项目之一&#xff0c;通常双方分别使用黑白两色的棋子&#xff0c;下在棋盘直线与横线的交叉点上&#xf…

Husky + lint-staged + ESlint + Prettier(可选) 实现git增量代码lint校验

工具介绍 Husky lint-staged ESlint Prettier(可选) 实现git增量代码lint校验 Husky&#xff1a;一个为 git 客户端增加 hook 的工具&#xff0c;它有一些钩子函数&#xff0c;比如pre-commit、 pre-push等lint-staged: 一个过滤出 git 代码暂存区文件的工具&#xff0c;在…

防火墙NAT策略中各项之间以及策略与策略之间的关系

实验结论 将实验结论写在前面方便大家直接查看 1、NAT策略中rule与rule之间的关系为“或”的关系&#xff0c;即多个rule存在时&#xff0c;流量只需要匹配其中一个rule即可&#xff0c;流量会按照匹配的rule规则进行流量转发。&#xff08;华为华三的防火墙rule是没有ID的&a…