{"id":103,"date":"2017-12-18T21:37:36","date_gmt":"2017-12-18T21:37:36","guid":{"rendered":"http:\/\/eipsoftware.com\/musings\/?p=103"},"modified":"2018-02-01T16:41:57","modified_gmt":"2018-02-01T16:41:57","slug":"webgl-rotating-cube","status":"publish","type":"post","link":"https:\/\/eipsoftware.com\/musings\/webgl-rotating-cube\/","title":{"rendered":"WebGL &#8211; Rotating Cube"},"content":{"rendered":"<p>In this posting I will again be using WebGL.\u00a0 However as opposed to just drawing a triangle and doing a gradient fill, which you can see here.\u00a0 <a href=\"https:\/\/eipsoftware.com\/musings\/webgl\/glt\/gradient_triangle.html\">Gradient Triangle.<\/a><\/p>\n<p>The code listed below will use WebGL to draw a cube and make it rotate.<\/p>\n<h4>WebGL Rotating a Cube<\/h4>\n<p><!--more--><\/p>\n<p>The cube has solid face colors, each color different so you can easily see the rotation of the cube faces.\u00a0 In the\u00a0var boxVertices, you can see that we are drawing two triangles for each cube face.<\/p>\n<p>In the second part of the tuple the RGB values are specified, and they are listed as a range of luminance from 0.0 to 1.0.\u00a0 It is a little different than how colors are represented in most other programs.\u00a0 You normally see the RGB values shown as a value from 0 to 255, i.e. 2^8. It is just one of the fun things about working with WebGL.<\/p>\n<p>The example uses a JavaScript library available from\u00a0<a href=\"http:\/\/glmatrix.net\/\">glMatrix.net<\/a> The library will handle the matrix math that are required to rotate the cube.<\/p>\n<p>Link to a working example.\u00a0 <a href=\"https:\/\/eipsoftware.com\/musings\/webgl\/rc\/rotate_cube.html\">Rotating a Cube<\/a><\/p>\n<p>The code should work on most modern browsers including iPhones.\u00a0 The speed the cube is being rotated can be adjusted by changing the value of 6 in the line below. Change 6 to a lower value to rotate the cube faster or higher value to rotate slower.<\/p>\n<pre class=\"\">angle = performance.now() \/ 1000 \/ 6 * 2 * Math.PI;<\/pre>\n<h4>Code<\/h4>\n<pre class=\"theme:github lang:r decode:true \">\/\/js draw a cube via webGL\r\n\r\n\/\/vertex shader\r\nvar vertexShaderText =\r\n\t\t\t\t\t[\r\n\t\t\t\t\t'precision mediump float;'\r\n\t\t\t\t\t,''\r\n\t\t\t\t\t,'attribute vec3 vertPosition;'\r\n\t\t\t\t\t,'attribute vec3 vertColor;'\r\n\t\t\t\t\t,'varying vec3 fragColor;'\r\n\t\t\t\t\t,'uniform mat4 mWorld;'\r\n\t\t\t\t\t,'uniform mat4 mView;'\r\n\t\t\t\t\t,'uniform mat4 mProj;'\r\n\t\t\t\t\t,''\r\n\t\t\t\t\t,'void main()'\r\n\t\t\t\t\t,'{'\r\n\t\t\t\t\t,' fragColor = vertColor;'\r\n\t\t\t\t\t,' gl_Position = mProj * mView * mWorld * vec4(vertPosition, 1.0);'\r\n\t\t\t\t\t,'}'\r\n\t\t\t\t\t].join('\\n');\r\n\r\n\/\/fragment shader\r\nvar fragmentShaderText =\r\n[\r\n\t'precision mediump float;'\r\n\t,''\r\n\t,'varying vec3 fragColor;'\r\n\t,'void main()'\r\n\t,'{'\r\n\t,' gl_FragColor = vec4(fragColor ,1.0);'\r\n\t,'}'\r\n].join('\\n');\r\n\r\n\t\r\n\r\nvar InitDemo = function()\r\n{\r\n\tconsole.log(\"this is working\");\r\n\tvar canvas = document.getElementById('blank_surface');\r\n\tvar gl = canvas.getContext(\"webgl\");\r\n\t\r\n\tif (!gl)\r\n\t{\r\n\t\tconsole.log(\"using experimental webgl\");\r\n\t\tgl = canvas.getContext(\"experimental-webgl\");\r\n\t}\r\n\tif(!gl)\r\n\t{\r\n\t\talert(\"Your Browser doesn't have webGL support\");\r\n\t}\r\n\t\r\n\t\/\/adjust the width \/ height of canvas\r\n\t\/\/canvas.width = window.innerWidth;\r\n\t\/\/canvas.width = window.innerHeight;\r\n\t\/\/reset the viewport since adjusted the canvas size\r\n\t\/\/gl.viewport(0, 0, window.innerWidth, window.innerHeight);\r\n\t\r\n\t\/\/setting color in format of RGB Alpha\r\n\tgl.clearColor(0.75,0.85,0.8,1.0);\r\n\t\/\/argument of what buffer to render too\r\n\tgl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);\r\n\t\r\n\t\/\/enable the depth tester\r\n\tgl.enable(gl.DEPTH_TEST);\r\n\t\r\n\t\/\/enable back culling\r\n\tgl.enable(gl.CULL_FACE);\r\n\tgl.frontFace(gl.CCW);\r\n\tgl.cullFace(gl.BACK);\r\n\t\r\n\t\/\/ open the shaders\r\n\tvar vertexShader = gl.createShader(gl.VERTEX_SHADER);\r\n\tvar fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);\r\n\t\r\n\t\/\/set shader source\r\n\tgl.shaderSource(vertexShader, vertexShaderText);\r\n\tgl.shaderSource(fragmentShader, fragmentShaderText);\r\n\t\r\n\t\/\/compile the shaders\r\n\tgl.compileShader(vertexShader);\r\n\t\/\/to check if compiled correctly\r\n\tif(!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS))\r\n\t{\r\n\t\tconsole.error(\"ERROR in compile: vertex shader\"\r\n\t\t\t\t\t  ,gl.getShaderInfoLog(vertexShader));\r\n\t\treturn;\r\n\t}\r\n\t\r\n\t\r\n\tgl.compileShader(fragmentShader);\r\n\t\tif(!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS))\r\n\t{\r\n\t\tconsole.error(\"ERROR in compile: fragment shader\"\r\n\t\t\t\t\t  ,gl.getShaderInfoLog(fragmentShader));\r\n\t\treturn;\r\n\t}\r\n\t\r\n\t\/\/create an opengl program\r\n\tvar program = gl.createProgram();\r\n\tgl.attachShader(program, vertexShader);\r\n\tgl.attachShader(program, fragmentShader);\r\n\t\r\n\t\/\/link gl program\r\n\tgl.linkProgram(program);\r\n\t\/\/check for errors while linking\r\n\tif(!gl.getProgramParameter(program, gl.LINK_STATUS))\r\n\t{\r\n\t\tconsole.error(\"ERROR linking program\"\r\n\t\t\t\t\t  , gl.getProgramInfoLog(program));\r\n\t\treturn;\r\n\t}\r\n\t\/\/validate the program -- only in debug, not production code\r\n\tgl.validateProgram(program);\r\n\tif(!gl.getProgramParameter(program, gl.VALIDATE_STATUS))\r\n\t{\r\n\t\tconsole.error(\"ERROR validating program\"\r\n\t\t\t\t\t  ,gl.getProgramInfoLog(program));\r\n\t\treturn;\r\n\t}\r\n\t\r\n\t\/\/ create buffer\r\n\t\/\/ x coord, y coord, z coord, RGB\r\n\tvar boxVertices =\r\n\t[\r\n\t\t\/\/top\r\n\t\t -1.0 \t,1.0\t,-1.0\t\t,0.5 ,0.5 ,0.5\r\n\t\t,-1.0\t,1.0\t,1.0\t\t,0.5 ,0.5 ,0.5\r\n\t\t,1.0\t,1.0\t,1.0\t\t,0.5 ,0.5 ,0.5\r\n\t\t,1.0\t,1.0\t,-1.0\t\t,0.5 ,0.5 ,0.5\r\n\t\t\r\n\t\t\/\/left\r\n\t\t,-1.0\t,1.0\t,1.0\t\t,0.75 ,0.25 ,0.5\r\n\t\t,-1.0\t,-1.0\t,1.0\t\t,0.75 ,0.25 ,0.5\r\n\t\t,-1.0\t,-1.0\t,-1.0\t\t,0.75 ,0.25 ,0.5\r\n\t\t,-1.0\t,1.0\t,-1.0\t\t,0.75 ,0.25 ,0.5\r\n\t\t\r\n\t\t\/\/right\r\n\t\t,1.0\t,1.0\t,1.0\t\t,0.25 ,0.25 ,0.75\r\n\t\t,1.0\t,-1.0\t,1.0\t\t,0.25 ,0.25 ,0.75\r\n\t\t,1.0\t,-1.0\t,-1.0\t\t,0.25 ,0.25 ,0.75\r\n\t\t,1.0\t,1.0\t,-1.0\t\t,0.25 ,0.25 ,0.75\r\n\t\t\r\n\t\t\r\n\t\t\/\/front\r\n\t\t,1.0\t,1.0\t,1.0\t\t,1.0 ,0.0 ,0.15\r\n\t\t,1.0\t,-1.0\t,1.0\t\t,1.0 ,0.0 ,0.15\r\n\t\t,-1.0\t,-1.0\t,1.0\t\t,1.0 ,0.0 ,0.15\r\n\t\t,-1.0\t,1.0\t,1.0\t\t,1.0 ,0.0 ,0.15\r\n\t\t\r\n\t\t\/\/back\r\n\t\t,1.0\t,1.0\t,-1.0\t\t,0.0 ,1.0 ,0.15\r\n\t\t,1.0\t,-1.0\t,-1.0\t\t,0.0 ,1.0 ,0.15\r\n\t\t,-1.0\t,-1.0\t,-1.0\t\t,0.0 ,1.0 ,0.15\r\n\t\t,-1.0\t,1.0\t,-1.0\t\t,0.0 ,1.0 ,0.15\r\n\t\t\r\n\t\t\/\/bottom\r\n\t\t,-1.0\t,-1.0\t,-1.0\t\t,0.5 ,0.5 ,1.0\r\n\t\t,-1.0\t,-1.0\t,1.0\t\t,0.5 ,0.5 ,1.0\r\n\t\t,1.0\t,-1.0\t,1.0\t\t,0.5 ,0.5 ,1.0\r\n\t\t,1.0\t,-1.0\t,-1.0\t\t,0.5 ,0.5 ,1.0\r\n\t];\r\n\r\n\tvar boxIndices =\r\n\t[\r\n\t\t\/\/top\r\n\t\t0,1,2\r\n\t\t,0,2,3\r\n\t\t\/\/left\r\n\t\t,5,4,6\r\n\t\t,6,4,7\r\n\t\t\/\/right\r\n\t\t,8,9,10\r\n\t\t,8,10,11\r\n\t\t\/\/front\r\n\t\t,13,12,14\r\n\t\t,15,14,12\r\n\t\t\/\/back\r\n\t\t,16,17,18\r\n\t\t,16,18,19\r\n\t\t\/\/bottom\r\n\t\t,21,20,22\r\n\t\t,22,20,23\r\n\t];\r\n\r\n\t\r\n\tvar boxVertexBufferObject = gl.createBuffer();\r\n\tgl.bindBuffer(gl.ARRAY_BUFFER, boxVertexBufferObject);\r\n\t\/\/cast array to float 32\r\n\tgl.bufferData(gl.ARRAY_BUFFER, new Float32Array(boxVertices), gl.STATIC_DRAW);\r\n\t\r\n\tvar boxIndexBufferObject = gl.createBuffer();\r\n\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boxIndexBufferObject);\r\n\tgl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(boxIndices), gl.STATIC_DRAW);\r\n\t\r\n\tvar positionAttribLocation = gl.getAttribLocation(program, 'vertPosition');\r\n\tvar colorAttribLocation = gl.getAttribLocation(program, 'vertColor');\r\n\t\/\/layout of the attribute\r\n\tgl.vertexAttribPointer(\r\n\t\t\t\t\t\t\tpositionAttribLocation\t\t\/\/attribute location\r\n\t\t\t\t\t\t\t,3\t\t\t\t\t\t\t\/\/number of elements per attribute\r\n\t\t\t\t\t\t\t,gl.FLOAT \t\t\t\t\t\/\/32 bit float\r\n\t\t\t\t\t\t\t,gl.FALSE\t\t\t\t\t\/\/\r\n\t\t\t\t\t\t\t,6 * Float32Array.BYTES_PER_ELEMENT \/\/size of an individual vertex\r\n\t\t\t\t\t\t\t,0 \/\/offset from the beginning of a single vertex to this attribute\r\n\t\t\t\t\t\t\t);\r\n\t\r\n\tgl.vertexAttribPointer(\r\n\t\t\t\t\t\t\tcolorAttribLocation\t\t\t\/\/attribute location\r\n\t\t\t\t\t\t\t,3\t\t\t\t\t\t\t\/\/number of elements per attribute\r\n\t\t\t\t\t\t\t,gl.FLOAT \t\t\t\t\t\/\/32 bit float\r\n\t\t\t\t\t\t\t,gl.FALSE\t\t\t\t\t\/\/\r\n\t\t\t\t\t\t\t,6 * Float32Array.BYTES_PER_ELEMENT \/\/size of an individual vertex\r\n\t\t\t\t\t\t\t,3 * Float32Array.BYTES_PER_ELEMENT \/\/offset from the beginning of a single vertex to this attribute\r\n\t\t\t\t\t\t\t);\r\n\t\r\n\tgl.enableVertexAttribArray(positionAttribLocation);\r\n\tgl.enableVertexAttribArray(colorAttribLocation);\r\n\t\r\n\t\/\/activate the main program for openGL\r\n\tgl.useProgram(program);\r\n\t\r\n\tvar matWorldUniformLocation = gl.getUniformLocation(program, 'mWorld');\r\n\tvar matViewUniformLocation = gl.getUniformLocation(program, 'mView');\r\n\tvar matProjUniformLocation = gl.getUniformLocation(program, 'mProj');\r\n\t\r\n\t\/\/create the matrix values\r\n\tvar worldMatrix = new Float32Array(16);\r\n\tvar viewMatrix = new Float32Array(16);\r\n\tvar projMatrix = new Float32Array(16);\r\n\t\r\n\tmat4.identity(worldMatrix);\r\n\tmat4.lookAt(viewMatrix,[0,0,-8],[0,0,0,],[0,1,0]);\r\n\tmat4.identity(projMatrix);\r\n\tmat4.perspective(projMatrix,glMatrix.toRadian(45), canvas.width \/ canvas.height, 0.1, 1000.0);\r\n\t\r\n\t\/\/send matrix over to graphics card\r\n\tgl.uniformMatrix4fv(matWorldUniformLocation, gl.FALSE, worldMatrix);\r\n\tgl.uniformMatrix4fv(matViewUniformLocation, gl.FALSE, viewMatrix);\r\n\tgl.uniformMatrix4fv(matProjUniformLocation, gl.FALSE, projMatrix);\r\n\t\r\n\t\/\/lateral rotation\r\n\tvar xRotationMatrix = new Float32Array(16);\r\n\tvar yRotationMatrix = new Float32Array(16);\r\n\r\n\t\/\/main render loop\r\n\t\/\/rotate primative\r\n\tvar angle = 0;\r\n\tvar identityMatrix = new Float32Array(16);\r\n\tmat4.identity(identityMatrix);\r\n\t\r\n\tvar loop = function()\r\n\t{\r\n\t\t\/\/one rotation per every 6 seconds\r\n\t\tangle = performance.now() \/ 1000 \/ 6 * 2 * Math.PI;\r\n\t\t\r\n\t\tmat4.rotate(yRotationMatrix, identityMatrix, angle, [0,1,0]);\r\n\t\tmat4.rotate(xRotationMatrix, identityMatrix, angle\/4, [1,0,0]);\r\n\t\t\/\/multiple both rotations\r\n\t\tmat4.mul(worldMatrix, yRotationMatrix, xRotationMatrix);\r\n\t\tgl.uniformMatrix4fv(matWorldUniformLocation, gl.FALSE, worldMatrix);\r\n\t\t\r\n\t\t\/\/clear the screen\r\n\t\tgl.clearColor(0.75,0.85,0.8,1.0);\r\n\t\t\/\/argument of what buffer to render too\r\n\t\tgl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);\r\n\t\t\r\n\t\tgl.drawElements(gl.TRIANGLES, boxIndices.length, gl.UNSIGNED_SHORT, 0);\r\n\t\t\/\/only called when it has focus\r\n\t\trequestAnimationFrame(loop);\r\n\t\t\r\n\t};\r\n\t\r\n\trequestAnimationFrame(loop);\r\n};<\/pre>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this posting I will again be using WebGL.\u00a0 However as opposed to just drawing a triangle and doing a gradient fill, which you can see here.\u00a0 Gradient Triangle. The code listed below will use WebGL to draw a cube and make it rotate. WebGL Rotating a Cube<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","footnotes":""},"categories":[4,10,11],"tags":[19,23,24],"series":[],"class_list":["post-103","post","type-post","status-publish","format-standard","hentry","category-code","category-javascript","category-webgl","tag-webgl","tag-rotate","tag-cube"],"_links":{"self":[{"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/posts\/103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/comments?post=103"}],"version-history":[{"count":5,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/posts\/103\/revisions"}],"predecessor-version":[{"id":140,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/posts\/103\/revisions\/140"}],"wp:attachment":[{"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/media?parent=103"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/categories?post=103"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/tags?post=103"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/eipsoftware.com\/musings\/wp-json\/wp\/v2\/series?post=103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}