{"id":1007,"date":"2013-04-29T07:32:58","date_gmt":"2013-04-29T07:32:58","guid":{"rendered":"http:\/\/www.osd.net\/blog\/?p=1007"},"modified":"2013-06-05T12:05:09","modified_gmt":"2013-06-05T12:05:09","slug":"3d-board-game-in-a-browser-using-webgl-and-three-js-part-1","status":"publish","type":"post","link":"https:\/\/www.osd.net\/blog\/web-development\/3d-board-game-in-a-browser-using-webgl-and-three-js-part-1\/","title":{"rendered":"3D board game in a browser using WebGL and Three.js, part 1"},"content":{"rendered":"<p>This is the first part from a series of articles that will show you how to build a 3D board game that will run in a modern browser.<\/p>\n<p>Checkers is the game that will be used to demonstrate the browser&#8217;s 3D capabilities. To find out more about the game go <a title=\"Checkers game\" href=\"http:\/\/en.wikipedia.org\/wiki\/English_draughts\">here<\/a>.<\/p>\n<p>Some notes before starting:<\/p>\n<ul class=\"indented-list\">\n<li>This and the following articles will not show you how to build a complete checkers game, but instead will show you\u00a0only the basics because the focus will be on the actual 3D rendering.<\/li>\n<li>The 3D assets needed will be provided to you and there is no info on how to create them other than some basic guidelines specific to our goal.<\/li>\n<\/ul>\n<h2>What you&#8217;ll learn in this part<\/h2>\n<p>This article will cover the basic setup of the game, like directory structure and needed files. In the end you&#8217;ll have a wireframe cube and you&#8217;ll be able to orbit around it. You can scroll down at the end of the article if you want to see it in all its glory.<\/p>\n<p>Now let&#8217;s clarify some things.<\/p>\n<h2>What is WebGL?<\/h2>\n<p>Let&#8217;s see what Wikipedia has to say:<\/p>\n<blockquote><p><strong>WebGL<\/strong> (Web Graphics Library) is a <strong>JavaScript API<\/strong> for rendering interactive <strong>3D graphics<\/strong> and <strong>2D graphics<\/strong> within any compatible web browser without the use of plug-ins. WebGL is integrated completely into all the web standards of the browser allowing <strong>GPU accelerated<\/strong> usage of physics and image processing and effects as part of the web page canvas.<\/p><\/blockquote>\n<p>That pretty much says it all. To find out more you can read the full description <a title=\"WebGL\" href=\"http:\/\/en.wikipedia.org\/wiki\/WebGL\">here<\/a>.<\/p>\n<p>To test if your browser and graphics card supports WebGL go to <a title=\"WebGL capability check\" href=\"http:\/\/get.webgl.org\/\">get.webgl.org<\/a>. It should tell you that <em>&#8220;Your browser supports WebGL&#8221;<\/em> and you should see a spinning cube.<\/p>\n<p>The only browsers that currently support WebGL out of the box are Mozilla Firefox and Google Chrome. Safari and Opera have implemented support for WebGL also, but it&#8217;s disabled by default.<\/p>\n<h2>What is Three.js?<\/h2>\n<p><a title=\"Three.js, a JavaScript 3D library\" href=\"http:\/\/threejs.org\/\">Three.js<\/a> is a <strong>JavaScript 3D library<\/strong> that takes away the complexity of WebGL low-level API. Here&#8217;s an official description:<\/p>\n<blockquote><p>The aim of the project is to create a <strong>lightweight 3D library<\/strong> with a very low level of complexity \u2014 in other words, for dummies. The library provides &lt;canvas&gt;, &lt;svg&gt;, CSS3D and <strong>WebGL renderers<\/strong>.<\/p><\/blockquote>\n<p>We will be using this library to build our 3D board game.<\/p>\n<h2>Before we begin<\/h2>\n<p>You should be familiar with the following concepts in JavaScript:<\/p>\n<p><a title=\"Introduction to Object-Oriented JavaScript\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/JavaScript\/Introduction_to_Object-Oriented_JavaScript\">Object-Oriented JavaScript<\/a><\/p>\n<p><a title=\"Self-Invoking Anonymous Function\" href=\"http:\/\/sarfraznawaz.wordpress.com\/2012\/01\/26\/javascript-self-invoking-functions\/\">Self-Invoking Anonymous Function<\/a><\/p>\n<p><a title=\"Private Members in JavaScript\" href=\"http:\/\/javascript.crockford.com\/private.html\">Private Members in JavaScript<\/a><\/p>\n<p><a title=\"JavaScript Strict Mode\" href=\"http:\/\/www.yuiblog.com\/blog\/2010\/12\/14\/strict-mode-is-coming-to-town\/\">Strict Mode<\/a><\/p>\n<p>You may also want to read about <strong>ECMAScript 5<\/strong> new features:<\/p>\n<p><a title=\"ECMAScript 5 Objects and Properties\" href=\"http:\/\/ejohn.org\/blog\/ecmascript-5-objects-and-properties\/\">ECMAScript 5 Objects and Properties<\/a><\/p>\n<p><a title=\"ECMAScript 5 Strict Mode, JSON, and More\" href=\"http:\/\/ejohn.org\/blog\/ecmascript-5-strict-mode-json-and-more\/\">ECMAScript 5 Strict Mode, JSON, and More<\/a><\/p>\n<h3>About testing<\/h3>\n<p>Because the 3D assets will be loaded via AJAX, opening the index.html file in the browser will only work in Firefox.<\/p>\n<p>In Google Chrome you&#8217;ll see the following error message in Developer tools console: <em>&#8220;Cross origin requests are only supported for HTTP&#8221;. <\/em>To fix that you either use a local web server to access the project or you open Google Chrome with the <code>--disable-web-security<\/code> argument (<a href=\"http:\/\/stackoverflow.com\/questions\/3102819\/chrome-disable-same-origin-policy\">Disable same origin policy<\/a>).<\/p>\n<h2>The beginining<\/h2>\n<p>Create a directory for our game and make it to reassemble the following structure:<\/p>\n<p><a href=\"https:\/\/www.osd.net\/blog\/wp-content\/uploads\/2013\/04\/webgl_3d_checkers_directory_structure.jpg\"><img loading=\"lazy\" class=\"size-full wp-image-1012 alignnone\" alt=\"WebGL 3D checkers game directory structure\" src=\"https:\/\/www.osd.net\/blog\/wp-content\/uploads\/2013\/04\/webgl_3d_checkers_directory_structure.jpg\" width=\"148\" height=\"167\" \/><\/a><\/p>\n<p><strong>3d_assets\/:<\/strong> the directory where the 3D content files will resides.<\/p>\n<p><strong>css\/style.css<\/strong>: some basic CSS styles.<\/p>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\n\r\nhtml, body {\r\n    height: 100%;\r\n}\r\n\r\nbody {\r\n    margin: 0;\r\n    overflow: hidden;\r\n}\r\n\r\n#boardContainer {\r\n    width: 100%;\r\n    height: 100%;\r\n    background: #e6e0cf;\r\n}\r\n\r\n<\/pre>\n<p><strong>js\/three\/:<\/strong> the three.js library home.<\/p>\n<p><strong>js\/main.js:<\/strong> the checkers game will start from here.<\/p>\n<p><strong>js\/Game.js:<\/strong> it will handle game logic and it will create a BoardController.<\/p>\n<p><strong>js\/BoardController.js:<\/strong> it will handle all the actual drawing and mouse interaction.<\/p>\n<p><strong>index.html:<\/strong><\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n\r\n&lt;!DOCTYPE html&gt;\r\n&lt;html&gt;\r\n    &lt;head&gt;\r\n        &lt;link rel=&quot;stylesheet&quot; type=&quot;text\/css&quot; href=&quot;css\/style.css&quot; \/&gt;\r\n    &lt;\/head&gt;\r\n    &lt;body&gt;\r\n        &lt;div id=&quot;boardContainer&quot;&gt;&lt;\/div&gt;\r\n\r\n        &lt;script src=&quot;js\/three\/three.js&quot;&gt;&lt;\/script&gt;\r\n        &lt;script src=&quot;js\/three\/OrbitControls.js&quot;&gt;&lt;\/script&gt;\r\n        &lt;script src=&quot;js\/Game.js&quot;&gt;&lt;\/script&gt;\r\n        &lt;script src=&quot;js\/BoardController.js&quot;&gt;&lt;\/script&gt;\r\n        &lt;script src=&quot;js\/main.js&quot;&gt;&lt;\/script&gt;\r\n    &lt;\/body&gt;\r\n&lt;\/html&gt;\r\n\r\n<\/pre>\n<p><a title=\"Three.js 3D library\" href=\"http:\/\/github.com\/mrdoob\/three.js\/zipball\/master\">Download three.js<\/a> library and copy into <strong>js\/three\/<\/strong> the following files: <strong>build\/three.js<\/strong> and\u00a0<strong>examples\/js\/controls\/OrbitControls.js<\/strong>.<\/p>\n<h2>Starting the game<\/h2>\n<p>Our game will be started from <strong>main.js<\/strong>:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\n(function () {\r\n    'use strict';\r\n\r\n    var game = new CHECKERS.Game({\r\n        \/\/ The DOM element in which the drawing will happen.\r\n        containerEl: document.getElementById('boardContainer'),\r\n\r\n        \/\/ The base URL from where the BoardController will load its data.\r\n        assetsUrl: '3d_assets\/'\r\n    });\r\n\r\n})();\r\n\r\n<\/pre>\n<p>The <em>Game<\/em> object will be placed in the <em>CHECKERS<\/em> namespace and it will automatically start a new game on instantiation. The properties passed to the configuration object will be passed to <em>BoardController<\/em>&#8216;s instantiation also.<\/p>\n<p>Let&#8217;s have a look at <strong>Game.js<\/strong>:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\nvar CHECKERS = {};\r\n\r\nCHECKERS.Game = function (options) {\r\n    'use strict';\r\n\r\n    options = options || {};\r\n\r\n    var boardController = null;\r\n\r\n    function init() {\r\n        boardController = new CHECKERS.BoardController({\r\n            containerEl: options.containerEl,\r\n            assetsUrl: options.assetsUrl\r\n        });\r\n\r\n        boardController.drawBoard();\r\n    }\r\n\r\n    init();\r\n};\r\n\r\n<\/pre>\n<p>On line 8 we define a private property that will holds the <em>BoardController<\/em> instance. On line 10 the <em>init<\/em> function is defined and on line 19 the same function is called.<\/p>\n<p><strong>Note:<\/strong> The <em>init<\/em> function should be kept always at the bottom.<\/p>\n<p>The job of the <em>init<\/em> function is to create an instance of <em>BoardController<\/em> and to request the board drawing at line 16.<\/p>\n<p>Let&#8217;s move on to <strong>BoardController.js<\/strong>:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\nCHECKERS.BoardController = function (options) {\r\n    'use strict';\r\n\r\n    options = options || {};\r\n\r\n    var containerEl = options.containerEl || null;\r\n\r\n    var assetsUrl = options.assetsUrl || '';\r\n\r\n    this.drawBoard = function () {\r\n        console.log('drawBoard');\r\n    };\r\n};\r\n\r\n<\/pre>\n<p>Load\/reload the <em>index.html<\/em> file in the browser and you should see the word &#8216;drawBoard&#8217; printed in the browser&#8217;s console.<\/p>\n<h2>Creating the 3D virtual space<\/h2>\n<p><em>The rest of the article will add code to BoardController.js file.<\/em><\/p>\n<p>Before drawing some actual 3D elements we need to create the WebGL renderer, a scene that will hold the 3D objects, a camera and a camera controller that will allow the mouse to control the camera position.<\/p>\n<p>First let&#8217;s declare the needed variables:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\nassetsUrl: options.assetsUrl || '';\r\n\r\nvar renderer;\r\nvar scene;\r\nvar camera;\r\nvar cameraController;\r\n\r\n<\/pre>\n<p>We will initialize the variables in a function named <strong>initEngine<\/strong> called from <em>drawBoard<\/em>:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\nthis.drawBoard = function () {\r\n    initEngine();\r\n};\r\n\r\nfunction initEngine() {\r\n    var viewWidth = containerEl.offsetWidth;\r\n    var viewHeight = containerEl.offsetHeight;\r\n\r\n    \/\/ instantiate the WebGL Renderer\r\n    renderer = new THREE.WebGLRenderer({\r\n        antialias: true\r\n    });\r\n    renderer.setSize(viewWidth, viewHeight);\r\n\r\n    \/\/ create the scene\r\n    scene = new THREE.Scene();\r\n\r\n    \/\/ create camera\r\n    camera = new THREE.PerspectiveCamera(35, viewWidth \/ viewHeight, 1, 1000);\r\n    camera.position.set(0, 120, 150);\r\n    cameraController = new THREE.OrbitControls(camera, containerEl);\r\n    \/\/\r\n    scene.add(camera);\r\n\r\n    containerEl.appendChild(renderer.domElement);\r\n}\r\n\r\n<\/pre>\n<p>The code should be pretty self-explanatory. To see what all those arguments passed to the <em>PerspectiveCamera<\/em> creation on line 19 means, have a look at the <a title=\"Three.js PerspectiveCamera\" href=\"http:\/\/threejs.org\/docs\/58\/#Reference\/Cameras\/PerspectiveCamera\">documentation<\/a>.<\/p>\n<p>All objects added to the scene will be positioned in the center, so on line 20 we move the camera up and towards us. On line 21 the camera controller is created by passing to the constructor the camera and the element that will listen for mouse events.<\/p>\n<h2>Drawing 3D objects<\/h2>\n<p>With the virtual world created now we are ready to add some 3D objects in it. That will be accomplished in a <strong>initObjects<\/strong> function added below the <em>initEngine<\/em>:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\nfunction initObjects(callback) {\r\n    var cube = new THREE.Mesh(new THREE.CubeGeometry(50, 50, 50));\r\n    scene.add(cube);\r\n\r\n    callback();\r\n}\r\n\r\n<\/pre>\n<p>The first thing to notice is that the function will accept a callback that is called at the end. For now only a cube is created and added to the scene on\u00a0 line 2 and 3, but later on the checkers board and the pieces will be loaded via AJAX and we&#8217;ll want to know when everything have been loaded.<\/p>\n<p>The <em>initObjects<\/em> function should be be called from <em>drawBoard<\/em> after <em>initEngine<\/em> like this:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\ninitObjects(function () {\r\n    onAnimationFrame();\r\n});\r\n\r\n<\/pre>\n<p>After the objects have been loaded we need to tell the WebGL renderer to render the scene on each animation frame.<\/p>\n<p><strong>The render loop.<\/strong><\/p>\n<p>After the <em>initObjects<\/em> function add the following:<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\r\nfunction onAnimationFrame() {\r\n    requestAnimationFrame(onAnimationFrame);\r\n\r\n    cameraController.update();\r\n\r\n    renderer.render(scene, camera);\r\n}\r\n\r\n<\/pre>\n<p>On line 2 an animation frame is requested (<a title=\"requestAnimationFrame\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/DOM\/window.requestAnimationFrame\">info about requestAnimationFrame<\/a>).<\/p>\n<p>The camera controller needs to be updated on each frame, so we do that on line 4.<\/p>\n<p>On line 6 the scene is getting rendered.<\/p>\n<p>Now if you test in the browser you should see a wireframe cube:<\/p>\n<p><a href=\"https:\/\/www.osd.net\/blog\/wp-content\/uploads\/2013\/04\/webgl_3d_checkers_testing_cube.jpg\"><img loading=\"lazy\" class=\"alignnone size-full wp-image-1019\" alt=\"webgl_3d_checkers_testing_cube\" src=\"https:\/\/www.osd.net\/blog\/wp-content\/uploads\/2013\/04\/webgl_3d_checkers_testing_cube.jpg\" width=\"599\" height=\"357\" srcset=\"https:\/\/www.osd.net\/blog\/wp-content\/uploads\/2013\/04\/webgl_3d_checkers_testing_cube.jpg 599w, https:\/\/www.osd.net\/blog\/wp-content\/uploads\/2013\/04\/webgl_3d_checkers_testing_cube-300x178.jpg 300w\" sizes=\"(max-width: 599px) 100vw, 599px\" \/><\/a><\/p>\n<p>Your cube may look different since the colors of the lines are changing randomly with each refresh.<\/p>\n<p>You can orbit around with left mouse button down and drag. To zoom use the mouse scroll and to pan drag with the right mouse button.<\/p>\n<h2>End of part 1<\/h2>\n<p>That&#8217;s all folks! In the next article we will load the checkers board and the pieces; we&#8217;ll also add some lights in scene.<\/p>\n<p>You can download the current phase of the project from <a href=\"https:\/\/www.osd.net\/blog\/wp-content\/uploads\/2013\/04\/webgl_3d_checkers_part1.zip\">here<\/a>.<\/p>\n<p><strong><\/strong>If you have questions, suggestions or improvements don\u2019t hesitate to add a comment and let me know about them.<\/p>\n<div id=\"share-and-beer-container\">\t<div id=\"buy_me_a_beer_div\" class=\"single beer\">\n\t \t\n\t\t<div class=\"buy-beer\" onclick=\"document.getElementById('buy_me_a_beer_form').submit();\">\n\t\t\t<form action=\"https:\/\/www.paypal.com\/cgi-bin\/webscr\" id=\"buy_me_a_beer_form\" method=\"post\">\n\t\t\t\t<input type=\"hidden\" name=\"cmd\" value=\"_xclick\" \/>\n\t\t\t\t<input type=\"hidden\" name=\"business\" value=\"info@directaccess.ro\" \/>  \n\t\t\t\t<input type=\"hidden\" name=\"item_name\" value=\"A Beer For 3D board game in a browser using WebGL and Three.js, part 1\" \/>  \n\t\t\t\t<input type=\"hidden\" name=\"item_number\" value=\"1\" \/>  \n\t\t\t\t<input type=\"hidden\" name=\"return\" value=\"https:\/\/www.osd.net\/blog\/web-development\/3d-board-game-in-a-browser-using-webgl-and-three-js-part-1\/\" \/>  \n\t\t\t\t<input type=\"hidden\" name=\"amount\" value=\"5\" \/>  \n\t\t\t\t<input type=\"hidden\" name=\"undefined_quantity\" value=\"1\" \/>  \n\t\t\t\t<input type=\"hidden\" name=\"currency_code\" value=\"USD\" \/>  \n\t\t\t<\/form>\n\t\t\t<p class=\"buy-beer-text\">If you liked this post <br \/> you can <strong>buy me a beer<\/strong><\/p>\n\t\t<\/div>\n\t<\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>This is the first part from a series of articles that will show you how to build a 3D board game that will run in a modern browser. Checkers is the game that will be used to demonstrate the browser&#8217;s 3D capabilities. To find out more about the game go here. Some notes before starting: &hellip;<\/p>\n<div class=\"cta1\"><a href=\"https:\/\/www.osd.net\/blog\/web-development\/3d-board-game-in-a-browser-using-webgl-and-three-js-part-1\/\">Read more<\/a><\/div>\n<div class=\"like-excerpt\"><div\n        class=\"fb-like\"\n        data-href=\"https:\/\/www.osd.net\/blog\/web-development\/3d-board-game-in-a-browser-using-webgl-and-three-js-part-1\/\"\n        data-layout=\"button_count\"\n        data-action=\"like\"\n        data-show-faces=\"false\"\n        data-share=\"false\">\n        <\/div><\/div>","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[18,13],"tags":[122,121,120],"_links":{"self":[{"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/posts\/1007"}],"collection":[{"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/comments?post=1007"}],"version-history":[{"count":12,"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/posts\/1007\/revisions"}],"predecessor-version":[{"id":1099,"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/posts\/1007\/revisions\/1099"}],"wp:attachment":[{"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/media?parent=1007"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/categories?post=1007"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.osd.net\/blog\/wp-json\/wp\/v2\/tags?post=1007"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}