{"id":27910,"date":"2022-06-16T06:11:09","date_gmt":"2022-06-16T06:11:09","guid":{"rendered":"http:\/\/create-3d-models-with-webgl"},"modified":"2022-06-16T06:11:09","modified_gmt":"2022-06-16T06:11:09","slug":"create-3d-models-with-webgl","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/","title":{"rendered":"Create 3D Models with WebGL"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>There are a lot of different technologies that are in the browser that enable a lot of interesting functionality. One of these things is WebGL. You can make all kinds of advanced animations and models, some of which can be used in other applications. We\u2019re going to go through a tutorial on how to make a 3D model in WebGL.<\/p>\n<p>If you\u2019re using the Chrome browser, like me, you\u2019ll need to enable WebGL. You can do that by going to chrome:\/\/flags and enabling the WebGL options. With those enabled, let\u2019s start with a little background on what WebGL is.<\/p>\n<h2>Brief background on WebGL<\/h2>\n<p>WebGL is a JavaScript API that lets us render 2D and 3D graphics in the browser without any extra plugins. It utilizes the hardware on the user\u2019s computer. It works with OpenGL to let us render these high-performance graphics in an HTML canvas element. So you can create complex models and animations with JavaScript and make them interactive for users.<\/p>\n<p>Learning the syntax to build decent models in WebGL can take time since you\u2019re dealing with vertices of objects, shaders to handle color effects, and possibly animations. While all of this is handled through JavaScript, it can still be different from what you\u2019re used to with regular development.<\/p>\n<p>Let\u2019s go ahead and start making the model with just an HTML file and a JavaScript file. (When\u2019s the last time you did that?)<\/p>\n<h2>Set up the canvas<\/h2>\n<p>We\u2019ll start by creating a new HTML file called <code>index.html<\/code>. This will have a few JavaScript imports and a canvas to support our 3D model. Add the following code to your new file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-meta\">&lt;!DOCTYPE <span class=\"hljs-meta-keyword\">html<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">html<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"en\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">charset<\/span>=<span class=\"hljs-string\">\"utf-8\"<\/span> \/&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>WebGL 3D Model<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>\n      <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/gl-matrix\/2.8.1\/gl-matrix-min.js\"<\/span>\n      <span class=\"hljs-attr\">integrity<\/span>=<span class=\"hljs-string\">\"sha512-zhHQR0\/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ==\"<\/span>\n      <span class=\"hljs-attr\">crossorigin<\/span>=<span class=\"hljs-string\">\"anonymous\"<\/span>\n      <span class=\"hljs-attr\">defer<\/span>\n    &gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"model.js\"<\/span> <span class=\"hljs-attr\">defer<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">head<\/span>&gt;<\/span>\n\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">canvas<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"glcanvas\"<\/span> <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">\"640\"<\/span> <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">\"480\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">canvas<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">html<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We\u2019re importing the <a href=\"https:\/\/www.npmjs.com\/package\/gl-matrix\"><code>gl-matrix<\/code> library<\/a> to support the model rendering and animation in WebGL and we\u2019re importing a custom <code>model.js<\/code> file to load the model we\u2019re about to build. Finally, we define the <code>&lt;canvas&gt;<\/code> element that the model will be rendered in. That\u2019s all we need for the HTML! Now let\u2019s start working on that <code>model.js<\/code> file.<\/p>\n<h2>Make the WebGL context<\/h2>\n<p>In the same folder as <code>index.html<\/code> add a new JavaScript file called <code>model.js<\/code>. This is where we\u2019ll do all of the fancy WebGL model building. There are libraries like <a href=\"https:\/\/threejs.org\/\">three.js<\/a> and <a href=\"https:\/\/www.babylonjs.com\/\">Babylon.js<\/a> that can handle this for us, but you still have to know what\u2019s happening under the hood to use it effectively.<\/p>\n<p>To kick things off, let\u2019s start by defining the WebGL context. This is the only way we can render objects in that <code>&lt;canvas&gt;<\/code> element with WebGL. In the <code>model.js<\/code> file, add the following code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">main();\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">main<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> canvas = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">\"#model-container\"<\/span>);\n\n  <span class=\"hljs-keyword\">const<\/span> wgl =\n    canvas.getContext(<span class=\"hljs-string\">\"webgl\"<\/span>) || canvas.getContext(<span class=\"hljs-string\">\"experimental-webgl\"<\/span>);\n\n  <span class=\"hljs-comment\">\/\/ If we don't have a GL context, return error message<\/span>\n  <span class=\"hljs-keyword\">if<\/span> (!wgl) {\n    alert(<span class=\"hljs-string\">\"Try to enable WebGL in Chrome.\"<\/span>);\n    <span class=\"hljs-keyword\">return<\/span>;\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>That\u2019s all for setting up the context.<\/p>\n<h2>Add a 2D object<\/h2>\n<h2>Make the shader<\/h2>\n<p>You\u2019ll run into two shader functions when working with WebGL: the fragment shader and the vertex shader. The fragment shader is called after the object\u2019s vertices have been handled by the vertex shader. It\u2019s called once for each pixel on the object. The vertex shader transforms the input vertex into the coordinate system used by WebGL. This is what we use to define lighting and textures on the model.<\/p>\n<p>In <code>model.js<\/code>, add the following code beneath the alert we made earlier to define the vertex shader.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ model.js<\/span>\n...\nconst vsSource = <span class=\"hljs-string\">`\n  attribute vec4 aVertexPosition;\n  attribute vec4 aVertexColor;\n\n  uniform mat4 uModelViewMatrix;\n  uniform mat4 uProjectionMatrix;\n\n  varying lowp vec4 vColor;\n\n  void main(void) {\n    gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;\n    vColor = aVertexColor;\n  }\n`<\/span>;\n...\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is all written using the <a href=\"https:\/\/www.khronos.org\/opengl\/wiki\/OpenGL_Shading_Language\">OpenGL Shading Language (GLSL)<\/a>. What\u2019s happening here is all of the calculations to render the shader to the vertices of the object we\u2019re going to draw. Now let\u2019s add the fragment shader below the vertex shader.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ model.js<\/span>\n...\nconst fsSource = <span class=\"hljs-string\">`\n  varying lowp vec4 vColor;\n\n  void main(void) {\n    gl_FragColor = vColor;\n  }\n`<\/span>;\n...\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This is responsible for applying the color to the sides of the object and is also written in GLSL. Next, we need to initialize the shader functions so they can be used together. Add this code after the fragment shader.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ model.js<\/span>\n...\n<span class=\"hljs-keyword\">const<\/span> shaderProgram = initShaderProgram(wgl, vsSource, fsSource);\n\n<span class=\"hljs-keyword\">const<\/span> programInfo = {\n  program: shaderProgram,\n  attribLocations: {\n    vertexPosition: wgl.getAttribLocation(shaderProgram, <span class=\"hljs-string\">\"aVertexPosition\"<\/span>),\n    vertexColor: wgl.getAttribLocation(shaderProgram, <span class=\"hljs-string\">\"aVertexColor\"<\/span>),\n  },\n  uniformLocations: {\n    projectionMatrix: wgl.getUniformLocation(\n      shaderProgram,\n      <span class=\"hljs-string\">\"uProjectionMatrix\"<\/span>\n    ),\n    modelViewMatrix: wgl.getUniformLocation(\n      shaderProgram,\n      <span class=\"hljs-string\">\"uModelViewMatrix\"<\/span>\n    ),\n  },\n};\n...\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This takes the shader functions we wrote and defines the object that will tell WebGL what to do with our model. You\u2019ll notice we have a function called <code>initShaderProgram<\/code> that we need to define. Outside of the <code>main<\/code> function, add the following code below it.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ model.js<\/span>\n...\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">initShaderProgram<\/span><span class=\"hljs-params\">(wgl, vsSource, fsSource)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> vertexShader = loadShader(wgl, wgl.VERTEX_SHADER, vsSource);\n  <span class=\"hljs-keyword\">const<\/span> fragmentShader = loadShader(wgl, wgl.FRAGMENT_SHADER, fsSource);\n\n  <span class=\"hljs-keyword\">const<\/span> shaderProgram = wgl.createProgram();\n\n  wgl.attachShader(shaderProgram, vertexShader);\n  wgl.attachShader(shaderProgram, fragmentShader);\n  wgl.linkProgram(shaderProgram);\n\n  <span class=\"hljs-keyword\">if<\/span> (!wgl.getProgramParameter(shaderProgram, wgl.LINK_STATUS)) {\n    alert(\n      <span class=\"hljs-string\">\"Unable to initialize the shader program: \"<\/span> +\n        wgl.getProgramInfoLog(shaderProgram)\n    );\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">null<\/span>;\n  }\n\n  <span class=\"hljs-keyword\">return<\/span> shaderProgram;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This function converts the individual shader functions into a shader program that WebGL will use to apply colors to the 3D object. But you\u2019ll probably see there\u2019s another helper function we need called <code>loadShader<\/code>. Add this below the <code>initShaderProgram<\/code> function we just defined.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ model.js<\/span>\n...\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">loadShader<\/span><span class=\"hljs-params\">(wgl, type, source)<\/span> <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> shader = wgl.createShader(type);\n\n  wgl.shaderSource(shader, source);\n\n  wgl.compileShader(shader);\n\n  <span class=\"hljs-keyword\">if<\/span> (!wgl.getShaderParameter(shader, wgl.COMPILE_STATUS)) {\n    alert(\n      <span class=\"hljs-string\">\"An error occurred compiling the shaders: \"<\/span> + wgl.getShaderInfoLog(shader)\n    );\n\n    wgl.deleteShader(shader);\n\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">null<\/span>;\n  }\n\n  <span class=\"hljs-keyword\">return<\/span> shader;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This takes the vertex and fragment shader functions and compiles them to something WebGL can interpret. There\u2019s just one more function we need to make sure the shader is applied to the model with the colors we want.<\/p>\n<p>We need to define the model\u2019s vertices and the colors we want to apply.<\/p>\n<h2>Create the 3D model<\/h2>\n<p>We need to create an array of the vertex colors and store it in a WebGL buffer. That\u2019s how WebGL will actually render the 3D model on the page. So below the <code>loadShader<\/code> function, add this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ model.js<\/span>\n...\nfunction initBuffers(wgl) {\n  <span class=\"hljs-keyword\">const<\/span> positionBuffer = wgl.createBuffer();\n\n  wgl.bindBuffer(wgl.ARRAY_BUFFER, positionBuffer);\n\n  <span class=\"hljs-keyword\">const<\/span> positions = &#91;\n    <span class=\"hljs-comment\">\/\/ Front face<\/span>\n    <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>,\n\n    <span class=\"hljs-comment\">\/\/ Back face<\/span>\n    <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>,\n\n    <span class=\"hljs-comment\">\/\/ Top face<\/span>\n    <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>,\n\n    <span class=\"hljs-comment\">\/\/ Bottom face<\/span>\n    <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>,\n\n    <span class=\"hljs-comment\">\/\/ Right face<\/span>\n    <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>,\n\n    <span class=\"hljs-comment\">\/\/ Left face<\/span>\n    <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">-1.0<\/span>,\n  ];\n\n  wgl.bufferData(\n    wgl.ARRAY_BUFFER,\n    <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Float32Array<\/span>(positions),\n    wgl.STATIC_DRAW\n  );\n\n  <span class=\"hljs-keyword\">const<\/span> faceColors = &#91;\n    &#91;<span class=\"hljs-number\">0.0<\/span>, <span class=\"hljs-number\">0.6<\/span>, <span class=\"hljs-number\">0.78<\/span>, <span class=\"hljs-number\">1.0<\/span>],\n    &#91;<span class=\"hljs-number\">0.25<\/span>, <span class=\"hljs-number\">0.0<\/span>, <span class=\"hljs-number\">0.0<\/span>, <span class=\"hljs-number\">0.5<\/span>],\n    &#91;<span class=\"hljs-number\">0.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">0.33<\/span>, <span class=\"hljs-number\">1.0<\/span>],\n    &#91;<span class=\"hljs-number\">0.0<\/span>, <span class=\"hljs-number\">0.42<\/span>, <span class=\"hljs-number\">0.74<\/span>, <span class=\"hljs-number\">0.8<\/span>],\n    &#91;<span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">1.0<\/span>, <span class=\"hljs-number\">0.0<\/span>, <span class=\"hljs-number\">0.62<\/span>],\n    &#91;<span class=\"hljs-number\">0.32<\/span>, <span class=\"hljs-number\">0.0<\/span>, <span class=\"hljs-number\">0.55<\/span>, <span class=\"hljs-number\">0.39<\/span>],\n  ];\n\n  <span class=\"hljs-keyword\">let<\/span> colors = &#91;];\n\n  faceColors.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">faceColor<\/span>) =&gt;<\/span> {\n    colors = colors.concat(faceColor, faceColor, faceColor, faceColor);\n  });\n\n  <span class=\"hljs-keyword\">const<\/span> colorBuffer = wgl.createBuffer();\n\n  wgl.bindBuffer(wgl.ARRAY_BUFFER, colorBuffer);\n  wgl.bufferData(wgl.ARRAY_BUFFER, <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Float32Array<\/span>(colors), wgl.STATIC_DRAW);\n\n  <span class=\"hljs-keyword\">const<\/span> indexBuffer = wgl.createBuffer();\n\n  wgl.bindBuffer(wgl.ELEMENT_ARRAY_BUFFER, indexBuffer);\n\n  <span class=\"hljs-keyword\">const<\/span> indices = &#91;\n    <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">2<\/span>,\n    <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">2<\/span>, <span class=\"hljs-number\">3<\/span>, <span class=\"hljs-comment\">\/\/ front<\/span>\n    <span class=\"hljs-number\">4<\/span>, <span class=\"hljs-number\">5<\/span>, <span class=\"hljs-number\">6<\/span>,\n    <span class=\"hljs-number\">4<\/span>, <span class=\"hljs-number\">6<\/span>, <span class=\"hljs-number\">7<\/span>, <span class=\"hljs-comment\">\/\/ back<\/span>\n    <span class=\"hljs-number\">8<\/span>, <span class=\"hljs-number\">9<\/span>, <span class=\"hljs-number\">10<\/span>,\n    <span class=\"hljs-number\">8<\/span>, <span class=\"hljs-number\">10<\/span>, <span class=\"hljs-number\">11<\/span>, <span class=\"hljs-comment\">\/\/ top<\/span>\n    <span class=\"hljs-number\">12<\/span>, <span class=\"hljs-number\">13<\/span>, <span class=\"hljs-number\">14<\/span>,\n    <span class=\"hljs-number\">12<\/span>, <span class=\"hljs-number\">14<\/span>, <span class=\"hljs-number\">15<\/span>, <span class=\"hljs-comment\">\/\/ bottom<\/span>\n    <span class=\"hljs-number\">16<\/span>, <span class=\"hljs-number\">17<\/span>, <span class=\"hljs-number\">18<\/span>,\n    <span class=\"hljs-number\">16<\/span>, <span class=\"hljs-number\">18<\/span>, <span class=\"hljs-number\">19<\/span>, <span class=\"hljs-comment\">\/\/ right<\/span>\n    <span class=\"hljs-number\">20<\/span>, <span class=\"hljs-number\">21<\/span>, <span class=\"hljs-number\">22<\/span>,\n    <span class=\"hljs-number\">20<\/span>, <span class=\"hljs-number\">22<\/span>, <span class=\"hljs-number\">23<\/span>, <span class=\"hljs-comment\">\/\/ left<\/span>\n  ];\n\n  wgl.bufferData(\n    wgl.ELEMENT_ARRAY_BUFFER,\n    <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Uint16Array<\/span>(indices),\n    wgl.STATIC_DRAW\n  );\n\n  <span class=\"hljs-keyword\">return<\/span> {\n    <span class=\"hljs-attr\">position<\/span>: positionBuffer,\n    <span class=\"hljs-attr\">color<\/span>: colorBuffer,\n    <span class=\"hljs-attr\">indices<\/span>: indexBuffer,\n  };\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This looks like a lot is going on, but it\u2019s not as bad as it seems. Most of this function is made of the matrices that define the vertices for the model, which is a cube, and the colors we want on its faces. This adds those model matrices to a WebGL buffer that will be used to show the object in the <code>&lt;canvas&gt;<\/code>. If you aren\u2019t familiar with matrix math, you should check out a few resources on it.<\/p>\n<p>There\u2019s one more function we need to render what\u2019s in our WebGL buffer to the screen and that will be the logic that draws the scene in the canvas element. Below the <code>initBuffers<\/code> function, add this code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ model.js<\/span>\n...\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">drawScene<\/span><span class=\"hljs-params\">(wgl, programInfo, buffers, deltaTime)<\/span> <\/span>{\n  wgl.clearColor(<span class=\"hljs-number\">0.2<\/span>, <span class=\"hljs-number\">0.35<\/span>, <span class=\"hljs-number\">0.15<\/span>, <span class=\"hljs-number\">1.0<\/span>);\n  wgl.clearDepth(<span class=\"hljs-number\">1.0<\/span>);\n  wgl.enable(wgl.DEPTH_TEST);\n  wgl.depthFunc(wgl.LEQUAL);\n\n  wgl.clear(wgl.COLOR_BUFFER_BIT | wgl.DEPTH_BUFFER_BIT);\n\n  <span class=\"hljs-keyword\">const<\/span> fieldOfView = (<span class=\"hljs-number\">45<\/span> * Math.PI) \/ <span class=\"hljs-number\">180<\/span>; <span class=\"hljs-comment\">\/\/ in radians<\/span>\n  <span class=\"hljs-keyword\">const<\/span> aspect = wgl.canvas.clientWidth \/ wgl.canvas.clientHeight;\n  <span class=\"hljs-keyword\">const<\/span> zNear = <span class=\"hljs-number\">0.1<\/span>;\n  <span class=\"hljs-keyword\">const<\/span> zFar = <span class=\"hljs-number\">100.0<\/span>;\n  <span class=\"hljs-keyword\">const<\/span> projectionMatrix = mat4.create();\n\n  mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);\n\n  <span class=\"hljs-keyword\">const<\/span> modelViewMatrix = mat4.create();\n\n  mat4.translate(modelViewMatrix, modelViewMatrix, &#91;<span class=\"hljs-number\">-3.7<\/span>, <span class=\"hljs-number\">-1.0<\/span>, <span class=\"hljs-number\">-16.0<\/span>]);\n  mat4.rotate(modelViewMatrix, modelViewMatrix, cubeRotation, &#91;<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">0<\/span>]);\n  mat4.rotate(modelViewMatrix, modelViewMatrix, cubeRotation * <span class=\"hljs-number\">0.7<\/span>, &#91;<span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">1<\/span>, <span class=\"hljs-number\">1<\/span>]);\n\n  {\n    <span class=\"hljs-keyword\">const<\/span> numComponents = <span class=\"hljs-number\">3<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> type = wgl.FLOAT;\n    <span class=\"hljs-keyword\">const<\/span> normalize = <span class=\"hljs-keyword\">false<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> stride = <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> offset = <span class=\"hljs-number\">0<\/span>;\n    wgl.bindBuffer(wgl.ARRAY_BUFFER, buffers.position);\n    wgl.vertexAttribPointer(\n      programInfo.attribLocations.vertexPosition,\n      numComponents,\n      type,\n      normalize,\n      stride,\n      offset\n    );\n    wgl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);\n  }\n\n  {\n    <span class=\"hljs-keyword\">const<\/span> numComponents = <span class=\"hljs-number\">4<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> type = wgl.FLOAT;\n    <span class=\"hljs-keyword\">const<\/span> normalize = <span class=\"hljs-keyword\">false<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> stride = <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> offset = <span class=\"hljs-number\">0<\/span>;\n    wgl.bindBuffer(wgl.ARRAY_BUFFER, buffers.color);\n    wgl.vertexAttribPointer(\n      programInfo.attribLocations.vertexColor,\n      numComponents,\n      type,\n      normalize,\n      stride,\n      offset\n    );\n    wgl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);\n  }\n\n  wgl.bindBuffer(wgl.ELEMENT_ARRAY_BUFFER, buffers.indices);\n\n  wgl.useProgram(programInfo.program);\n\n  wgl.uniformMatrix4fv(\n    programInfo.uniformLocations.projectionMatrix,\n    <span class=\"hljs-keyword\">false<\/span>,\n    projectionMatrix\n  );\n\n  wgl.uniformMatrix4fv(\n    programInfo.uniformLocations.modelViewMatrix,\n    <span class=\"hljs-keyword\">false<\/span>,\n    modelViewMatrix\n  );\n\n  {\n    <span class=\"hljs-keyword\">const<\/span> vertexCount = <span class=\"hljs-number\">36<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> type = wgl.UNSIGNED_SHORT;\n    <span class=\"hljs-keyword\">const<\/span> offset = <span class=\"hljs-number\">0<\/span>;\n    wgl.drawElements(wgl.TRIANGLES, vertexCount, type, offset);\n  }\n\n  cubeRotation += deltaTime;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This hefty function is what determines what is shown to users. It starts by clearing out the canvas and getting it ready for WebGL. Then we do some math operations to determine where the object is located in space and how big the space should appear. Then we put the model vertices into the view, apply the shader, and draw the elements on the canvas.<\/p>\n<p>The very last thing we need to do so all of these helper functions are put to use is add a bit more code to our <code>main<\/code> function that gets called when the page is loaded. Inside the <code>main<\/code> function, just below the <code>programInfo<\/code> object, add these lines.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ model.js<\/span>\n...\nconst programInfo = {\n  ...\n  <span class=\"hljs-comment\">\/\/ existing code is still there<\/span>\n};\n\n<span class=\"hljs-keyword\">const<\/span> buffers = initBuffers(wgl);\n\n<span class=\"hljs-keyword\">let<\/span> then = <span class=\"hljs-number\">0<\/span>;\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">render<\/span>(<span class=\"hljs-params\">now<\/span>) <\/span>{\n  now *= <span class=\"hljs-number\">0.001<\/span>; <span class=\"hljs-comment\">\/\/ convert to seconds<\/span>\n  <span class=\"hljs-keyword\">const<\/span> deltaTime = now - then;\n  then = now;\n\n  drawScene(wgl, programInfo, buffers, deltaTime);\n\n  requestAnimationFrame(render);\n}\n\nrequestAnimationFrame(render);\n...\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Finally, this is where we initialize the WebGL buffer and create a <code>render<\/code> function that slowly rotates the cube in space and displays it on the canvas. This is a simple model, but once you see it in action, it\u2019s surprisingly smooth.<\/p>\n<h2>Finished code<\/h2>\n<p>You can check out the complete code for this project in the <a href=\"https:\/\/github.com\/flippedcoder\/media-projects\/tree\/main\/webgl-3d-model\"><code>webgl-3d-model<\/code> folder of this repo<\/a>. You can also check it out in <a href=\"https:\/\/codesandbox.io\/s\/admiring-hellman-ise7zf\">this Code Sandbox<\/a>.<\/p>\n<p>&lt;CodeSandBox\ntitle=\u201cadmiring-hellman-ise7zf\u201d\nid=\u201cadmiring-hellman-ise7zf\u201d\n\/&gt;<\/p>\n<h2>Conclusion<\/h2>\n<p>Now that you\u2019ve created a basic model, you can start playing around with fancier models. Maybe try to make a WebGL version of your favorite video game character. It\u2019s fun because it\u2019s always wonky when you get started, but once you really get the vertices and shaders as you want, it can look pretty good.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":27911,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,177,374,371],"class_list":["post-27910","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-javascript","tag-performance","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Create 3D Models with WebGL<\/title>\n<meta name=\"description\" content=\"WebGL is an underlying technology for a lot of high-performance graphics and animations on the web. Probably the most famous library built on it is three.js. We&#039;re going to dive into the inner workings of WebGL just a bit to see what&#039;s happening under the hood.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Create 3D Models with WebGL\" \/>\n<meta property=\"og:description\" content=\"WebGL is an underlying technology for a lot of high-performance graphics and animations on the web. Probably the most famous library built on it is three.js. We&#039;re going to dive into the inner workings of WebGL just a bit to see what&#039;s happening under the hood.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-06-16T06:11:09+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"3500\" \/>\n\t<meta property=\"og:image:height\" content=\"6000\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Create 3D Models with WebGL\",\"datePublished\":\"2022-06-16T06:11:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/\"},\"wordCount\":5,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"Javascript\",\"Performance\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/\",\"name\":\"Create 3D Models with WebGL\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA\",\"datePublished\":\"2022-06-16T06:11:09+00:00\",\"description\":\"WebGL is an underlying technology for a lot of high-performance graphics and animations on the web. Probably the most famous library built on it is three.js. We're going to dive into the inner workings of WebGL just a bit to see what's happening under the hood.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA\",\"width\":3500,\"height\":6000},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Create 3D Models with WebGL\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Create 3D Models with WebGL","description":"WebGL is an underlying technology for a lot of high-performance graphics and animations on the web. Probably the most famous library built on it is three.js. We're going to dive into the inner workings of WebGL just a bit to see what's happening under the hood.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/","og_locale":"en_US","og_type":"article","og_title":"Create 3D Models with WebGL","og_description":"WebGL is an underlying technology for a lot of high-performance graphics and animations on the web. Probably the most famous library built on it is three.js. We're going to dive into the inner workings of WebGL just a bit to see what's happening under the hood.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-06-16T06:11:09+00:00","og_image":[{"width":3500,"height":6000,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/"},"author":{"name":"","@id":""},"headline":"Create 3D Models with WebGL","datePublished":"2022-06-16T06:11:09+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/"},"wordCount":5,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA","keywords":["Guest Post","Javascript","Performance","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/","name":"Create 3D Models with WebGL","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA","datePublished":"2022-06-16T06:11:09+00:00","description":"WebGL is an underlying technology for a lot of high-performance graphics and animations on the web. Probably the most famous library built on it is three.js. We're going to dive into the inner workings of WebGL just a bit to see what's happening under the hood.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA","width":3500,"height":6000},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/create-3d-models-with-webgl\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Create 3D Models with WebGL"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925918\/Web_Assets\/blog\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5\/ab136c7ab2db9de03870c8e9ba24dde11d1b29d7-3500x6000-1_27911c0fc5.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27910","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=27910"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27910\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/27911"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=27910"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=27910"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=27910"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}