立方体贴图

主要是在 gl.bufferData( gl.ARRAY_BUFFER, data, gl.STATIC_DRAW ) 中传两次数据:立方体的 x、y、z 坐标和纹理的 s、t 坐标, 关键是要坐标对应好。如果绕y轴旋转,适宜把前后左右4个面的方向都一致,x轴、z轴同理。

<script id="vertexShader" type="x-shader/x-vertex"> attribute vec4 a_Position; attribute vec2 a_TexCoord; uniform mat4 u_mvpMatrix; varying vec2 v_TexCoord; void main(){ gl_Position = u_mvpMatrix * a_Position; v_TexCoord = a_TexCoord; } </script> <script id="fragmentShader" type="x-shader/x-fragment"> precision mediump float; uniform sampler2D u_Sampler; // 采样器 varying vec2 v_TexCoord; void main(){ gl_FragColor = texture2D(u_Sampler, v_TexCoord); } </script> var u_mvpMatrix; var viewProjMatrix = new Matrix4(); var n, angle_step = 1/2; function init(){ var canvas = document.getElementById('canvas'), gl = canvas.getContext('webgl'); if(!gl){ console.log('Failed to get WebGL.'); return; } if(!initShaders(gl, "vertexShader", "fragmentShader")){ console.log('Failed to initShaders.'); return; } gl.clearColor( 0.0, 0.0, 0.0, 1.0 ); gl.enable( gl.DEPTH_TEST ); viewProjMatrix.setPerspective(45, canvas.width/canvas.height, 1, 100); viewProjMatrix.lookAt(2, 2, 5, 0, 0, 0, 0, 1, 0); var u_mvpMatrix = gl.getUniformLocation(gl.program, 'u_mvpMatrix'); gl.uniformMatrix4fv(u_mvpMatrix, false, viewProjMatrix.elements); // 立方体纹理 initVertexBuffers(gl); initTexture(gl); } function initVertexBuffers(gl){ // 顶点索引 var indices = new Uint8Array([ 0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23 ]); var indicesBuffer = gl.createBuffer(); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, indicesBuffer ); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); // 顶点位置 var vertices = new Float32Array([ -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0 ]), texCoords = new Float32Array([ 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 ]); var indicesBuffer = gl.createBuffer(); gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, indicesBuffer ); gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW ); initArrayBuffer(gl, 'a_Position', vertices, 3, gl.FLOAT); initArrayBuffer(gl, 'a_TexCoord', texCoords, 2, gl.FLOAT); n = indices.length; } function initArrayBuffer(gl, attribute, data, num, type){ var buffer = gl.createBuffer(); var a_attribute = gl.getAttribLocation(gl.program, attribute); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW); gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0); gl.enableVertexAttribArray(a_attribute); } function initTexture(gl){ var texture = gl.createTexture(); var u_Sampler = gl.getUniformLocation( gl.program, 'u_Sampler' ); var image = new Image(); image.onload = function(){ loadTexture(gl, texture, u_Sampler, image); }; image.src = '../assets/textures/view.png'; } function loadTexture(gl, texture, u_Sampler, image){ gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, true ); gl.activeTexture( gl.TEXTURE0 ); gl.bindTexture( gl.TEXTURE_2D, texture ); gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR ); gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image); gl.uniform1i( u_Sampler, 0 ); // 旋转动画 animate(); function animate(){ changeAngle( gl, u_mvpMatrix ); gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0); requestAnimationFrame( animate ); } } function changeAngle( gl, location ){ viewProjMatrix.rotate( angle_step, 0, 1, 0); gl.uniformMatrix4fv(location, false, viewProjMatrix.elements); }