<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.soft8soft.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Yuri</id>
	<title>Verge3D Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://www.soft8soft.com/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Yuri"/>
	<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php/Special:Contributions/Yuri"/>
	<updated>2026-04-21T14:42:56Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.44.2</generator>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=536</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=536"/>
		<updated>2021-12-02T08:34:39Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Building the pipeline */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, then code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better — Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on GitHub (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
# For anything beyond loading a mere model you can refer to myriad of [https://threejs.org/examples/#webgl_animation_keyframes Three.js examples].&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. As a result, this toolkit puts artists, instead of programmers, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but you can experiment with a trial version the only limitation of which is that shows a watermark. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server — Verge3D does this all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is usually consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, i.e. it first exports the scene to a glTF 2.0 asset, and then loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how can we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — it&#039;s free! Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or sell your work without paying a buck first.&lt;br /&gt;
&lt;br /&gt;
On the other hand, if paying some money for a [https://www.soft8soft.com/licensing/ license] is not a big deal for you (or your company), you might consider Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=516</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=516"/>
		<updated>2021-11-24T11:19:02Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Approach #2: Verge3D */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, then code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better — Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on GitHub (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. As a result, this toolkit puts artists, instead of programmers, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but you can experiment with a trial version the only limitation of which is that shows a watermark. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server — Verge3D does this all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is usually consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, i.e. it first exports the scene to a glTF 2.0 asset, and then loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how can we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — it&#039;s free! Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or sell your work without paying a buck first.&lt;br /&gt;
&lt;br /&gt;
On the other hand, if paying some money for a [https://www.soft8soft.com/licensing/ license] is not a big deal for you (or your company), you might consider Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=515</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=515"/>
		<updated>2021-11-24T11:17:04Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Creating the main HTML file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, then code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better — Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on GitHub (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. As a result, this toolkit puts artists, instead of programmers, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but you can experiment with a trial version the only limitation of which is that shows a watermark. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does this all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is usually consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, i.e. it first exports the scene to a glTF 2.0 asset, and then loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how can we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — it&#039;s free! Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or sell your work without paying a buck first.&lt;br /&gt;
&lt;br /&gt;
On the other hand, if paying some money for a [https://www.soft8soft.com/licensing/ license] is not a big deal for you (or your company), you might consider Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=514</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=514"/>
		<updated>2021-11-24T11:14:25Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Approach #1: Vanilla Three.js */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, then code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better — Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. As a result, this toolkit puts artists, instead of programmers, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but you can experiment with a trial version the only limitation of which is that shows a watermark. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does this all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is usually consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, i.e. it first exports the scene to a glTF 2.0 asset, and then loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how can we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — it&#039;s free! Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or sell your work without paying a buck first.&lt;br /&gt;
&lt;br /&gt;
On the other hand, if paying some money for a [https://www.soft8soft.com/licensing/ license] is not a big deal for you (or your company), you might consider Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=513</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=513"/>
		<updated>2021-11-24T11:12:23Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, then code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. As a result, this toolkit puts artists, instead of programmers, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but you can experiment with a trial version the only limitation of which is that shows a watermark. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does this all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is usually consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, i.e. it first exports the scene to a glTF 2.0 asset, and then loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how can we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — it&#039;s free! Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or sell your work without paying a buck first.&lt;br /&gt;
&lt;br /&gt;
On the other hand, if paying some money for a [https://www.soft8soft.com/licensing/ license] is not a big deal for you (or your company), you might consider Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=512</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=512"/>
		<updated>2021-11-24T11:09:25Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Which approach to choose? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. As a result, this toolkit puts artists, instead of programmers, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but you can experiment with a trial version the only limitation of which is that shows a watermark. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does this all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is usually consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, i.e. it first exports the scene to a glTF 2.0 asset, and then loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how can we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — it&#039;s free! Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or sell your work without paying a buck first.&lt;br /&gt;
&lt;br /&gt;
On the other hand, if paying some money for a [https://www.soft8soft.com/licensing/ license] is not a big deal for you (or your company), you might consider Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=511</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=511"/>
		<updated>2021-11-24T11:08:39Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Which approach to choose? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. As a result, this toolkit puts artists, instead of programmers, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but you can experiment with a trial version the only limitation of which is that shows a watermark. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does this all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is usually consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, i.e. it first exports the scene to a glTF 2.0 asset, and then loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how can we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — it&#039;s free! Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or sell your work without paying a buck first.&lt;br /&gt;
&lt;br /&gt;
On the other hand, if paying some money for a [https://www.soft8soft.com/licensing/ license] license is not a big deal for you or your company, you might consider Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=510</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=510"/>
		<updated>2021-11-24T11:06:24Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Approach #2: Verge3D */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. As a result, this toolkit puts artists, instead of programmers, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but you can experiment with a trial version the only limitation of which is that shows a watermark. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does this all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is usually consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, i.e. it first exports the scene to a glTF 2.0 asset, and then loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how can we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=505</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=505"/>
		<updated>2021-11-24T11:03:33Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Approach #2: Verge3D */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, instead of programmers, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but you can experiment with a trial version the only limitation of which is that shows a watermark. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does this all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is usually consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, i.e. it first exports the scene to a glTF 2.0 asset, and then loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=503</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=503"/>
		<updated>2021-11-24T10:58:16Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Building the pipeline */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the starter project to quickly create and deploy your apps. Feel free to upgrade that template - it&#039;s all open-source.&lt;br /&gt;
# It&#039;s much easier to load a single HDR map for environment lighting, than to tweak multiple light sources with JavaScript. And it works faster!&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender. This will save you a great deal of coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, so that you fully understand the limitations and constraints of this format.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=502</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=502"/>
		<updated>2021-11-24T10:32:06Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Running a web server */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it as &#039;&#039;&#039;server.py&#039;&#039;&#039;. In Blender, switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, locate and open that script, then click the &#039;Play&#039; icon to launch the server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
This server will be running in the background until you close Blender. Cool, yeah?&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=501</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=501"/>
		<updated>2021-11-24T10:29:31Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Running a web server */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
If we have Python in Blender, why not use it? Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=500</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=500"/>
		<updated>2021-11-24T10:27:10Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Running a web server */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we must use it! Let&#039;s create a basic Python script with the following content (or just copy the file from the starter project):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=499</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=499"/>
		<updated>2021-11-24T10:22:45Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Creating the main HTML file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can find this file in the starter project on Github (linked above). So, what is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=498</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=498"/>
		<updated>2021-11-24T10:18:33Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Creating the Blender scene */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems to be pretty straightforward for a Blender artist, right? Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
* And so on. Other things come on the need-to-know basis.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=497</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=497"/>
		<updated>2021-11-24T10:16:09Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Approach #1: vanilla Three.js */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems pretty straightforward. Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=496</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=496"/>
		<updated>2021-11-24T10:15:37Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Approach #1: Vanilla Three.js */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems pretty straightforward. Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=495</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=495"/>
		<updated>2021-11-24T10:14:51Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Creating the Blender scene */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems pretty straightforward. Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. Again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=494</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=494"/>
		<updated>2021-11-24T10:14:08Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Creating the Blender scene */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This step seems pretty straightforward. Well, you must get familiar with the limitations of the glTF 2.0 format, and WebGL in general! Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=493</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=493"/>
		<updated>2021-11-24T10:11:53Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach #2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=492</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=492"/>
		<updated>2021-11-24T10:11:03Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]{{#seo:&lt;br /&gt;
|description=This tutorial discusses how to use Blender and Three.js to create interactive 3D web applications.&lt;br /&gt;
|keywords=Three.js, Blender, 3D, WebGL, 3DWeb, Web3D&lt;br /&gt;
|image=blender_plus_threejs.png&lt;br /&gt;
}}&lt;br /&gt;
[[File:blender_plus_threejs.png|right|thumb]]&lt;br /&gt;
It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
This tutorial mostly covers the vanilla Three.js approach. In the end, some info about Verge3D will be provided as well.&lt;br /&gt;
&lt;br /&gt;
== Approach #1: Vanilla Three.js ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
We suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=489</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=489"/>
		<updated>2021-11-24T09:56:49Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Approach 1: glTF + Coding */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to reproduce it step by step for yourself, you can proceed to downloading the complete [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=488</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=488"/>
		<updated>2021-11-24T09:53:20Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Approach 1: glTF + Coding */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Intro ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. You will have to use the command-line interpreter to operate all these. This tool chain looks familiar to seasoned web developers. Still, using it with Three.js can turn out to be quite non-trivial, especially for people with little or no coding skills (e.g. for Blender artists who might even have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
An easier way is to just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. &lt;br /&gt;
&lt;br /&gt;
This latter approach is exactly what we are discussing in this tutorial. If you don&#039;t want to read it, you can proceed to downloading the [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender starter project]. Ok, let&#039;s begin!&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=487</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=487"/>
		<updated>2021-11-24T09:39:37Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Prerequisites */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. And the last but not least, you will have to use the command-line interpreter to operate these tools. This tool chain looks familiar to seasoned web developers. Still, using them with Three.js can turn out to be quite non-trivial, especially for people with limited or no coding skills (e.g. for Blender artists who might have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. This is exactly how we did with this [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender template].&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s discuss the next steps to compose and run your first Three.js app.&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=486</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=486"/>
		<updated>2021-11-24T09:39:10Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. And the last but not least, you will have to use the command-line interpreter to operate these tools.&lt;br /&gt;
&lt;br /&gt;
This tool chain looks familiar to seasoned web developers. Still, using them with Three.js can turn out to be quite non-trivial, especially for people with limited or no coding skills (e.g. for Blender artists who might have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
Alternatively, you can just copy the static Three.js build into your project folder, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run some web server to open the app. Even better - Blender has Python, so you can just launch the standard web server that comes with Python. This is exactly how we did with this [https://github.com/Soft8Soft/threejs-blender-template Three.js-Blender template].&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s discuss the next steps to compose and run your first Three.js app.&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=485</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=485"/>
		<updated>2021-11-24T09:31:55Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from [https://www.blender.org/download/ here] and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official Three.js [https://threejs.org/docs/#manual/en/introduction/Installation installation guide] recommends using the NPM package manager, as well as the JS module bundling tool called &#039;&#039;webpack&#039;&#039;. Also, you&#039;re gonna need to run a local web server to test your apps. And the last but not least, you will have to use the command-line interpreter to operate these tools.&lt;br /&gt;
&lt;br /&gt;
This tool chain looks familiar to seasoned web developers. Still, using them with Three.js can turn out to be quite non-trivial, especially for people with limited or no coding skills (e.g. for Blender artists who might have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
Another approach is just include the static Three.js build into your project directory, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run the Python-based web server to open the app. The latter is simplified due to the fact that Python is already included in Blender.&lt;br /&gt;
&lt;br /&gt;
Check out [https://github.com/Soft8Soft/threejs-blender-template this Three.js-Blender template] to which we bundled everything we mentioned above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s discuss the next steps to compose and run your first Three.js app.&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=484</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=484"/>
		<updated>2021-11-24T09:26:04Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender. Code a Three.js application to load the scene into it.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from here — [https://www.blender.org/download/ Blender Download] - and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official [https://threejs.org/docs/#manual/en/introduction/Installation Three.js Installation] guide recommends using the NPM package manager, as well as the JS module bundling tool called webpack. Also, you&#039;re gonna need to run a local web server to test your apps. And the last but not least, you will have to use the command-line interpreter to operate these 3 tools.&lt;br /&gt;
&lt;br /&gt;
This set of tools looks familiar for seasoned web developers. Still, using them to develop with Three.js can be quite non-trivial, especially for people who have limited coding skills (e.g for Blender artists who have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
Another approach is just include the static Three.js build into your project directory, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run the Python-based web server to open the app. The latter is simplified due to the fact that Python is already included in Blender.&lt;br /&gt;
&lt;br /&gt;
Check out [https://github.com/Soft8Soft/threejs-blender-template this Three.js-Blender template] to which we bundled everything we mentioned above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s discuss the next steps to compose and run your first Three.js app.&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=483</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=483"/>
		<updated>2021-11-24T09:22:59Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. So, how can we make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, and load the scene into a Three.js application.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from here — [https://www.blender.org/download/ Blender Download] - and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official [https://threejs.org/docs/#manual/en/introduction/Installation Three.js Installation] guide recommends using the NPM package manager, as well as the JS module bundling tool called webpack. Also, you&#039;re gonna need to run a local web server to test your apps. And the last but not least, you will have to use the command-line interpreter to operate these 3 tools.&lt;br /&gt;
&lt;br /&gt;
This set of tools looks familiar for seasoned web developers. Still, using them to develop with Three.js can be quite non-trivial, especially for people who have limited coding skills (e.g for Blender artists who have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
Another approach is just include the static Three.js build into your project directory, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run the Python-based web server to open the app. The latter is simplified due to the fact that Python is already included in Blender.&lt;br /&gt;
&lt;br /&gt;
Check out [https://github.com/Soft8Soft/threejs-blender-template this Three.js-Blender template] to which we bundled everything we mentioned above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s discuss the next steps to compose and run your first Three.js app.&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=482</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=482"/>
		<updated>2021-11-24T09:20:46Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. Ok, how we can make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, and create a new Three.js application from scratch.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from here — [https://www.blender.org/download/ Blender Download] - and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official [https://threejs.org/docs/#manual/en/introduction/Installation Three.js Installation] guide recommends using the NPM package manager, as well as the JS module bundling tool called webpack. Also, you&#039;re gonna need to run a local web server to test your apps. And the last but not least, you will have to use the command-line interpreter to operate these 3 tools.&lt;br /&gt;
&lt;br /&gt;
This set of tools looks familiar for seasoned web developers. Still, using them to develop with Three.js can be quite non-trivial, especially for people who have limited coding skills (e.g for Blender artists who have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
Another approach is just include the static Three.js build into your project directory, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run the Python-based web server to open the app. The latter is simplified due to the fact that Python is already included in Blender.&lt;br /&gt;
&lt;br /&gt;
Check out [https://github.com/Soft8Soft/threejs-blender-template this Three.js-Blender template] to which we bundled everything we mentioned above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s discuss the next steps to compose and run your first Three.js app.&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Under the hood, these blocks are converted to JavaScript that calls Verge3D APIs. You still can write your own JavaScript, or even add new visual blocks as plugins. In any case, Verge3D remains compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many other useful features, including the App Manager, AR/VR integration, WordPress plugin, Cordova/Electron builders, a physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to these [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach to choose? ==&lt;br /&gt;
&lt;br /&gt;
Three.js offers a feature that is quite convincing — its free. Blender is free too, and if you got plenty of time, you are all set! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other hand, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you might stick to Verge3D. And this is not only because it&#039;s a more powerful variant of Three.js that will help you meet a deadline. Verge3D is designed to be an artist-friendly tool that is worth looking into if you&#039;re using Blender in your pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=481</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=481"/>
		<updated>2021-11-24T09:07:31Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. Ok, how we can make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, and create a new Three.js application from scratch.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from here — [https://www.blender.org/download/ Blender Download] - and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official [https://threejs.org/docs/#manual/en/introduction/Installation Three.js Installation] guide recommends using the NPM package manager, as well as the JS module bundling tool called webpack. Also, you&#039;re gonna need to run a local web server to test your apps. And the last but not least, you will have to use the command-line interpreter to operate these 3 tools.&lt;br /&gt;
&lt;br /&gt;
This set of tools looks familiar for seasoned web developers. Still, using them to develop with Three.js can be quite non-trivial, especially for people who have limited coding skills (e.g for Blender artists who have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
Another approach is just include the static Three.js build into your project directory, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run the Python-based web server to open the app. The latter is simplified due to the fact that Python is already included in Blender.&lt;br /&gt;
&lt;br /&gt;
Check out [https://github.com/Soft8Soft/threejs-blender-template this Three.js-Blender template] to which we bundled everything we mentioned above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s discuss the next steps to compose and run your first Three.js app.&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
A typical approach for creating web apps with Three.js and Blender is recommended below:&lt;br /&gt;
&lt;br /&gt;
# Use the template to deploy your apps quickly. Feel free to upgrade the template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting, than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender comes first, Three.js goes second. This means you should try to design as much as possible in Blender to reduce the amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn more about glTF 2.0, to get its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is kinda Three.js on steroids. It includes a bunch of tools to sweeten the creation of 3D web content based on Blender scenes. Basically, this toolkit puts artists, and not coders, in charge of a project.&lt;br /&gt;
&lt;br /&gt;
The toolkit costs some money, but there is a trial version without time or feature limitations. Installation is fairly simple: [https://www.soft8soft.com/get-verge3d get] the installer (Windows) or zip archive (macOS, Linux), then enable the Blender add-on that is shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a convenient preview feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
This magic button exports the Blender scene in a temporary location and immediately opens it in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
There is no need to create a project from scratch, write any JavaScript, or care about the web server - Verge3D does it all for you.&lt;br /&gt;
&lt;br /&gt;
The WebGL rendering is consistent with Blender viewport (especially if you switch to the real-time renderer Eevee). This is because Verge3D tries to accurately reproduce most Blender features, such as native node-based materials, lighting, shadows, animation, morphing, etc. It works similar to vanilla Three.js, that is it exports to the glTF 2.0 asset and loads it in the browser via JavaScript... except you don&#039;t need to write any code.&lt;br /&gt;
&lt;br /&gt;
But how we make the app interactive, if not by JavaScript code? Verge3D does it differently as it comes with a Scratch-like scripting environment called Puzzles. For example, to convert the default Blender cube to a nice spinning Utah teapot you can employ the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Behind the scene, these blocks are converted to JavaScript which in turn trigger Verge3D APIs. If you need it, you can write your own JavaScript logic or create your own visual blocks. Also, Verge3D is compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many useful features, including App Manager, AR/VR, WordPress integration, Cordova/Electron builders, physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to the [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach is better? ==&lt;br /&gt;
&lt;br /&gt;
Three.js has one feature that is quite convincing — its free. Basically, if Blender is free, Three.js is free, and your time is free you are just great! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other side, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you better stick to Verge3D. Not only because its more powerful yet compatible with Three.js. Verge3D is designed to be an artist-friendly tool, so it will be very helpful if you already use or going to use Blender in your development pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=480</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=480"/>
		<updated>2021-11-24T08:51:11Z</updated>

		<summary type="html">&lt;p&gt;Yuri: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. Ok, how we can make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, and create a new Three.js application from scratch.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
Suppose you already have Blender installed. If not, you can get from here — [https://www.blender.org/download/ Blender Download] - and just run the installer.&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official [https://threejs.org/docs/#manual/en/introduction/Installation Three.js Installation] guide recommends using the NPM package manager, as well as the JS module bundling tool called webpack. Also, you&#039;re gonna need to run a local web server to test your apps. And the last but not least, you will have to use the command-line interpreter to operate these 3 tools.&lt;br /&gt;
&lt;br /&gt;
This set of tools looks familiar for seasoned web developers. Still, using them to develop with Three.js can be quite non-trivial, especially for people who have limited coding skills (e.g for Blender artists who have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
Another approach is just include the static Three.js build into your project directory, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run the Python-based web server to open the app. The latter is simplified due to the fact that Python is already included in Blender.&lt;br /&gt;
&lt;br /&gt;
Check out [https://github.com/Soft8Soft/threejs-blender-template this Three.js-Blender template] to which we bundled everything we mentioned above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s discuss the next steps to compose and run your first Three.js app.&lt;br /&gt;
&lt;br /&gt;
=== Creating the Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, but you must be familiar with the limitations of the glTF 2.0 format, and WebGL in general. Particularly:&lt;br /&gt;
&lt;br /&gt;
* Models must be low-poly to middle-poly so that the entire scene does not exceed several hundreds of thousands polygons. Usually 100k-500k polys is fine.&lt;br /&gt;
&lt;br /&gt;
* Cameras should be assigned explicitly in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shader nodes are not supported. again, you&#039;ll need to use JavaScript to setup proper lighting.&lt;br /&gt;
&lt;br /&gt;
* Materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Only limited set of textures is supported, namely Color, Metallic, Roughness, AO, Normal Map, and Emissive.&lt;br /&gt;
&lt;br /&gt;
* Maximum two UV maps are supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can adjust the offset, rotation and scale for your textures via a [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can only animate a limited set of params: object position, rotation, scale, the influence value for shape keys, and bone transformations. Again, all animations are initialized and controlled with JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting the scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
The procedure is as follows. First, you open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu. That&#039;s it.&lt;br /&gt;
&lt;br /&gt;
=== Adding Three.js builds and dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download the pre-built version of Three.js from [https://github.com/mrdoob/three.js/ GitHub]. Select the latest release, then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating the main HTML file ===&lt;br /&gt;
&lt;br /&gt;
Create the file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity, it includes everything (HTML, CSS, and JavaScript):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just edit this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What is going on in this code snippet? Well...&lt;br /&gt;
&lt;br /&gt;
# Initializing the canvas, scene and camera, as well as WebGL renderer.&lt;br /&gt;
# Creating &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading an HDR map for image-based lighting.&lt;br /&gt;
# Finally, loading the glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you merely open this HTML file with the browser you&#039;ll see.... nothing! This is a security measure that is imposed by the browsers. Without a properly configured web server you won&#039;t be able to launch this web application. So let&#039;s run a server!&lt;br /&gt;
&lt;br /&gt;
=== Running a web server ===&lt;br /&gt;
&lt;br /&gt;
As we have Python in Blender, we can just leverage it. Let&#039;s create (or just copy the ready-to-use file from the template) a basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then in Blender switch to the &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open that server script, then click the right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server will be running in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. Surely there are some issues with the rendering: namely it does not look exactly as in Blender viewport. There are some things we can do to improve this situation but don&#039;t expect much: Three.js is Three.js and Blender is Blender.&lt;br /&gt;
&lt;br /&gt;
=== Building the pipeline ===&lt;br /&gt;
&lt;br /&gt;
Here is a typical approach in creating apps with Three.js and Blender:&lt;br /&gt;
&lt;br /&gt;
# Use template to deploy your apps quickly. Feel free to take our template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender first, Three.js second. Basically, try to design as much as possible in Blender to reduce amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn glTF 2.0, including its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is a kind of Three.js on steroids. It includes various convenient tools to simplify creating 3D interactive content from Blender scenes. The idea behind it quite simple — 3D web apps should be designed by artists, not coders.&lt;br /&gt;
&lt;br /&gt;
The tool cost some money, however you can use the full-featured trial version as long as you wish.  Installation is simple: [https://www.soft8soft.com/get-verge3d download] installer (Windows) or zip archive (macOS, Linux), then follow the installation procedure by enabling the Blender add-on that shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a handy feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
By clicking on this &amp;quot;magic&amp;quot; button you can export and preview your Blender scene right in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Basically you won&#039;t need to create any projects, write any JavaScript logic or launch a web server. It&#039;s all done by Verge3D.&lt;br /&gt;
&lt;br /&gt;
If you compare the rendering you get in the browser with Blender viewport you won&#039;t see much difference (switch to real-time Eevee renderer to get better results). Verge3D tries to reproduce many Blender features including native node-based materials, lighting, shadows, animation, morphing, etc. Like with vanilla Three.js, it exports to the glTF 2.0 asset and load it in the browser via JavaScript... except you don&#039;t need to write any code by yourself.&lt;br /&gt;
&lt;br /&gt;
So how to make your app interactive, if not by JavaScript logic? For that Verge3D comes with visual scripting environment called Puzzles. For example, to convert default Blender cube to nice and spinning Utah teapot you can write the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Behind the scene, these blocks are converted to JavaScript which in turn trigger Verge3D APIs. If you need it, you can write your own JavaScript logic or create your own visual blocks. Also, Verge3D is compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many useful features, including App Manager, AR/VR, WordPress integration, Cordova/Electron builders, physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to the [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach is better? ==&lt;br /&gt;
&lt;br /&gt;
Three.js has one feature that is quite convincing — its free. Basically, if Blender is free, Three.js is free, and your time is free you are just great! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other side, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you better stick to Verge3D. Not only because its more powerful yet compatible with Three.js. Verge3D is designed to be an artist-friendly tool, so it will be very helpful if you already use or going to use Blender in your development pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=479</id>
		<title>Making 3D web apps with Blender and Three.js</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Making_3D_web_apps_with_Blender_and_Three.js&amp;diff=479"/>
		<updated>2021-11-24T08:29:51Z</updated>

		<summary type="html">&lt;p&gt;Yuri: someedits&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is well known that Blender is the most popular open-source 3D modeling suite. On the other hand, Three.js is the most popular WebGL library. Both have millions of users on their own, yet rarely used in combo for making interactive 3D visualizations that work on the Web. This is because such projects require very different sets of skills to cooperate.&lt;br /&gt;
&lt;br /&gt;
Here we are discussing ways to overcome these difficulties. Ok, how we can make fancy 3D web interactives based on Blender scenes? Basically, you got two options:&lt;br /&gt;
&lt;br /&gt;
# Use the glTF exporter, that comes with Blender, and create a new Three.js application from scratch.&lt;br /&gt;
# Use a framework to provide that integration without coding, such as the upgraded version of Three.js called Verge3D.&lt;br /&gt;
&lt;br /&gt;
== Approach 1: glTF + Coding ==&lt;br /&gt;
&lt;br /&gt;
Let&#039;s say you have Blender installed. If not, you can get from here — [https://www.blender.org/download/ Blender Download].&lt;br /&gt;
&lt;br /&gt;
With Three.js however, it&#039;s not that easy! The official [https://threejs.org/docs/#manual/en/introduction/Installation Three.js Installation] guide recommends using the NPM package manager, as well as the JS module bundling tool called webpack. Also, you&#039;re gonna need to run a local web server to test your apps. And the last but not least, you will have to use the command-line interpreter to operate these 3 tools.&lt;br /&gt;
&lt;br /&gt;
This set of tools looks familiar for seasoned web developers. Still, using them to develop with Three.js can be quite non-trivial, especially for people who have limited coding skills (e.g for Blender artists who have some experience in Python scripting).&lt;br /&gt;
&lt;br /&gt;
Another approach is just include the static Three.js build into your project directory, add some external dependencies (such as the glTF 2.0 loader), compose a basic HTML page to link all these, and finally run the Python-based web server to open the app. The latter is simplified due to the fact that Python is already included in Blender.&lt;br /&gt;
&lt;br /&gt;
Check out [https://github.com/Soft8Soft/threejs-blender-template this Three.js-Blender template] to which we bundled everything we mentioned above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s discuss the next steps to compose and run your first Three.js app.&lt;br /&gt;
&lt;br /&gt;
=== Creating Blender scene ===&lt;br /&gt;
&lt;br /&gt;
This one is pretty straightforward, considering you know limitations of the glTF 2.0 format and 3D web graphics. Among them:&lt;br /&gt;
&lt;br /&gt;
* Make your models low-poly so the complexity of your entire scene does not exceed several hundreds of thousands  polygons. 100K-500K polys is good enough.&lt;br /&gt;
&lt;br /&gt;
* Cameras are supported, however you should explicitly assign them in your app via JavaScript.&lt;br /&gt;
&lt;br /&gt;
* Lights and world shaders nodes are not supported. We&#039;re going to use JavaScript to setup lighting.&lt;br /&gt;
&lt;br /&gt;
* Your materials should be based on a single &#039;&#039;&#039;Principled BSDF&#039;&#039;&#039; node. Refer to the [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#materials Blender Manual] for more info.&lt;br /&gt;
&lt;br /&gt;
[[File:suzanne_blender.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
* Limited set of textures supported: Color, Metallic, Roughness, AO, Normal Map, Emissive.&lt;br /&gt;
&lt;br /&gt;
* In general, only two UV maps supported. Metallic and Roughness textures should use the same UV map.&lt;br /&gt;
&lt;br /&gt;
* You can assign offset, rotation and scale for your textures via [https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html#uv-mapping single Mapping node]. All other UV modifications are not supported.&lt;br /&gt;
&lt;br /&gt;
* You can animate limited set of params: object position, rotation, scale, influence value for shape keys, and bone transformations. Animations should be assigned and controlled via JavaScript.&lt;br /&gt;
&lt;br /&gt;
=== Exporting scene to glTF 2.0 ===&lt;br /&gt;
&lt;br /&gt;
First, open Blender preferences, click &#039;&#039;&#039;Add-ons&#039;&#039;&#039;, then make sure that &#039;&#039;&#039;Import-Export: glTF 2.0 format&#039;&#039;&#039; addon is enabled:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_stock_gltf_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
After that you can export your scene to glTF via &#039;&#039;&#039;File -&amp;gt; Export -&amp;gt; glTF 2.0 (.glb/.gltf)&#039;&#039;&#039; menu.&lt;br /&gt;
&lt;br /&gt;
=== Copying Three.js builds and external dependencies ===&lt;br /&gt;
&lt;br /&gt;
You can download pre-built version of Three.js on [https://github.com/mrdoob/three.js/ GitHub]. Select latest release then scroll down to download &#039;&#039;&#039;*.zip&#039;&#039;&#039;(Windows) or &#039;&#039;&#039;tar.gz&#039;&#039;&#039; (macOS, Linux) version. In our first app we&#039;re going to use the following files from that archive:&lt;br /&gt;
&lt;br /&gt;
* three.module.js — base Three.js module&lt;br /&gt;
* GLTFLoader.js — loader for our glTF files.&lt;br /&gt;
* OrbitControls.js — to rotate our camera with mouse/touchscreen.&lt;br /&gt;
* RGBELoader.js — to load fancy HDRI map used as environment lighting.&lt;br /&gt;
&lt;br /&gt;
=== Creating main HTML file with your app ===&lt;br /&gt;
&lt;br /&gt;
Create file &#039;&#039;&#039;index.html&#039;&#039;&#039; with the following content. For simplicity we will include HTML, CSS, and JavaScript code there:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;html&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE html&amp;gt;&lt;br /&gt;
&amp;lt;html lang=&amp;quot;en&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;title&amp;gt;Blender-to-Three.js App Template&amp;lt;/title&amp;gt;&lt;br /&gt;
    &amp;lt;meta charset=&amp;quot;utf-8&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;meta name=&amp;quot;viewport&amp;quot; content=&amp;quot;width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      body {&lt;br /&gt;
        margin: 0px;&lt;br /&gt;
      }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
    &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
      import * as THREE from &#039;./three.module.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      import { OrbitControls } from &#039;./OrbitControls.js&#039;;&lt;br /&gt;
      import { GLTFLoader } from &#039;./GLTFLoader.js&#039;;&lt;br /&gt;
      import { RGBELoader } from &#039;./RGBELoader.js&#039;;&lt;br /&gt;
&lt;br /&gt;
      let camera, scene, renderer;&lt;br /&gt;
&lt;br /&gt;
      init();&lt;br /&gt;
      render();&lt;br /&gt;
&lt;br /&gt;
      function init() {&lt;br /&gt;
&lt;br /&gt;
        const container = document.createElement( &#039;div&#039; );&lt;br /&gt;
        document.body.appendChild( container );&lt;br /&gt;
&lt;br /&gt;
        camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 0.25, 20 );&lt;br /&gt;
        camera.position.set( - 1.8, 0.6, 2.7 );&lt;br /&gt;
&lt;br /&gt;
        scene = new THREE.Scene();&lt;br /&gt;
&lt;br /&gt;
        new RGBELoader()&lt;br /&gt;
          .load( &#039;environment.hdr&#039;, function ( texture ) {&lt;br /&gt;
&lt;br /&gt;
            texture.mapping = THREE.EquirectangularReflectionMapping;&lt;br /&gt;
&lt;br /&gt;
            scene.background = texture;&lt;br /&gt;
            scene.environment = texture;&lt;br /&gt;
&lt;br /&gt;
            render();&lt;br /&gt;
&lt;br /&gt;
            // model&lt;br /&gt;
&lt;br /&gt;
            const loader = new GLTFLoader();&lt;br /&gt;
            loader.load( &#039;suzanne.gltf&#039;, function ( gltf ) {&lt;br /&gt;
&lt;br /&gt;
              scene.add( gltf.scene );&lt;br /&gt;
&lt;br /&gt;
              render();&lt;br /&gt;
&lt;br /&gt;
            } );&lt;br /&gt;
&lt;br /&gt;
          } );&lt;br /&gt;
&lt;br /&gt;
        renderer = new THREE.WebGLRenderer( { antialias: true } );&lt;br /&gt;
        renderer.setPixelRatio( window.devicePixelRatio );&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;&lt;br /&gt;
        renderer.toneMappingExposure = 1;&lt;br /&gt;
        renderer.outputEncoding = THREE.sRGBEncoding;&lt;br /&gt;
        container.appendChild( renderer.domElement );&lt;br /&gt;
&lt;br /&gt;
        const controls = new OrbitControls( camera, renderer.domElement );&lt;br /&gt;
        controls.addEventListener( &#039;change&#039;, render ); // use if there is no animation loop&lt;br /&gt;
        controls.minDistance = 2;&lt;br /&gt;
        controls.maxDistance = 10;&lt;br /&gt;
        controls.target.set( 0, 0, - 0.2 );&lt;br /&gt;
        controls.update();&lt;br /&gt;
&lt;br /&gt;
        window.addEventListener( &#039;resize&#039;, onWindowResize );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      function onWindowResize() {&lt;br /&gt;
&lt;br /&gt;
        camera.aspect = window.innerWidth / window.innerHeight;&lt;br /&gt;
        camera.updateProjectionMatrix();&lt;br /&gt;
&lt;br /&gt;
        renderer.setSize( window.innerWidth, window.innerHeight );&lt;br /&gt;
&lt;br /&gt;
        render();&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      //&lt;br /&gt;
&lt;br /&gt;
      function render() {&lt;br /&gt;
&lt;br /&gt;
        renderer.render( scene, camera );&lt;br /&gt;
&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you want to write any code, just take this file from the template we mentioned earlier.&lt;br /&gt;
&lt;br /&gt;
What we do in this HTML snippet?&lt;br /&gt;
&lt;br /&gt;
# Initializing Three.js: preparing canvas, scene/camera as well as WebGL renderer.&lt;br /&gt;
# Creating fancy &amp;quot;orbit&amp;quot; camera controls by using the external OrbitControls.js script.&lt;br /&gt;
# Loading HDR map to achieve decent quality of the scene lighting.&lt;br /&gt;
# Final step is loading glTF 2.0 model we exported previously.&lt;br /&gt;
&lt;br /&gt;
If you run this HTML file in your file manager you&#039;ll get .... nothing! Without a properly configured web server you won&#039;t be able to launch this web application. Since this is a security measure that imposed by browsers, there is no easy way to overcome this restriction. So let&#039;s write some server!&lt;br /&gt;
&lt;br /&gt;
=== Running web server ===&lt;br /&gt;
&lt;br /&gt;
Let&#039;s create (or just copy the ready-to-use file from the template) basic HTTP server script with the following content:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
import http.server&lt;br /&gt;
import os&lt;br /&gt;
import bpy&lt;br /&gt;
&lt;br /&gt;
from threading import Thread, current_thread&lt;br /&gt;
from functools import partial&lt;br /&gt;
&lt;br /&gt;
def ServeDirectoryWithHTTP(directory=&#039;.&#039;):&lt;br /&gt;
    hostname = &#039;localhost&#039;&lt;br /&gt;
    port = 8000&lt;br /&gt;
    directory = os.path.abspath(directory)&lt;br /&gt;
    handler = partial(http.server.SimpleHTTPRequestHandler, directory=directory)&lt;br /&gt;
    httpd = http.server.HTTPServer((hostname, port), handler, False)&lt;br /&gt;
    httpd.allow_reuse_address = True&lt;br /&gt;
&lt;br /&gt;
    httpd.server_bind()&lt;br /&gt;
    httpd.server_activate()&lt;br /&gt;
&lt;br /&gt;
    def serve_forever(httpd):&lt;br /&gt;
        with httpd:&lt;br /&gt;
            httpd.serve_forever()&lt;br /&gt;
&lt;br /&gt;
    thread = Thread(target=serve_forever, args=(httpd, ))&lt;br /&gt;
    thread.setDaemon(True)&lt;br /&gt;
    thread.start()&lt;br /&gt;
&lt;br /&gt;
app_root = os.path.dirname(bpy.context.space_data.text.filepath)&lt;br /&gt;
ServeDirectoryWithHTTP(app_root)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save it under &#039;&#039;&#039;server.py&#039;&#039;&#039; name, then go to Blender, switch to &#039;&#039;&#039;Text Editor&#039;&#039;&#039; area:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_open_text_block.jpg|657px]]&lt;br /&gt;
&lt;br /&gt;
Click &#039;&#039;&#039;Open&#039;&#039;&#039;, find and open your server script, then press right arrow icon to launch the HTTP server:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_run_script.jpg|843px]]&lt;br /&gt;
&lt;br /&gt;
The server should run in the background until you close Blender.&lt;br /&gt;
&lt;br /&gt;
=== Running the app ===&lt;br /&gt;
&lt;br /&gt;
Open the following page in your browser [http://localhost:8000/ http://localhost:8000/]. You should see the following page:&lt;br /&gt;
&lt;br /&gt;
[[File:three_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Try to rotate or zoom the model. There are some issues with its look, basically it does not look exactly like in Blender viewport. There are some measures how this situation can be improved but don&#039;t expect much: Three.js is still Three.js and Blender is still Blender.&lt;br /&gt;
&lt;br /&gt;
=== Organizing pipeline ===&lt;br /&gt;
&lt;br /&gt;
Here is a typical approach in creating apps with Three.js and Blender:&lt;br /&gt;
&lt;br /&gt;
# Use template to deploy your apps quickly. Feel free to take our template - it&#039;s free and open-source.&lt;br /&gt;
# It&#039;s much easier to just load and apply a single HDR-based environment lighting than tweaking multiple light sources with JavaScript.&lt;br /&gt;
# Blender first, Three.js second. Basically, try to design as much as possible in Blender to reduce amount of complex graphics coding.&lt;br /&gt;
# Take some time to learn glTF 2.0, including its limitations and constraints.&lt;br /&gt;
&lt;br /&gt;
== Approach 2: Verge3D ==&lt;br /&gt;
&lt;br /&gt;
Verge3D is a kind of Three.js on steroids. It includes various convenient tools to simplify creating 3D interactive content from Blender scenes. The idea behind it quite simple — 3D web apps should be designed by artists, not coders.&lt;br /&gt;
&lt;br /&gt;
The tool cost some money, however you can use the full-featured trial version as long as you wish.  Installation is simple: [https://www.soft8soft.com/get-verge3d download] installer (Windows) or zip archive (macOS, Linux), then follow the installation procedure by enabling the Blender add-on that shipped with Verge3D:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_verge3d_plugin.jpg|708px]]&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with a handy feature called &#039;&#039;&#039;Sneak Peek&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
[[File:blender_sneak_peek.jpg|929px]]&lt;br /&gt;
&lt;br /&gt;
By clicking on this &amp;quot;magic&amp;quot; button you can export and preview your Blender scene right in the web browser:&lt;br /&gt;
&lt;br /&gt;
[[File:v3d_app.jpg|1000px]]&lt;br /&gt;
&lt;br /&gt;
Basically you won&#039;t need to create any projects, write any JavaScript logic or launch a web server. It&#039;s all done by Verge3D.&lt;br /&gt;
&lt;br /&gt;
If you compare the rendering you get in the browser with Blender viewport you won&#039;t see much difference (switch to real-time Eevee renderer to get better results). Verge3D tries to reproduce many Blender features including native node-based materials, lighting, shadows, animation, morphing, etc. Like with vanilla Three.js, it exports to the glTF 2.0 asset and load it in the browser via JavaScript... except you don&#039;t need to write any code by yourself.&lt;br /&gt;
&lt;br /&gt;
So how to make your app interactive, if not by JavaScript logic? For that Verge3D comes with visual scripting environment called Puzzles. For example, to convert default Blender cube to nice and spinning Utah teapot you can write the following &amp;quot;code&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
This logic is quite self-explanatory. Behind the scene, these blocks are converted to JavaScript which in turn trigger Verge3D APIs. If you need it, you can write your own JavaScript logic or create your own visual blocks. Also, Verge3D is compatible with Three.js, so you can use Three.js snippets, examples, or apps found on the web.&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with many useful features, including App Manager, AR/VR, WordPress integration, Cordova/Electron builders, physics engine, tons of plugins, materials, and asset packs, as well as ready-to-use solutions for e-commerce and e-learning industries. Discussing all these is beyond the scope of this article, so refer to the [https://youtu.be/KIq2Q-DFCT0 beginner-level tutorial series] to learn more about this toolkit.&lt;br /&gt;
&lt;br /&gt;
== Which approach is better? ==&lt;br /&gt;
&lt;br /&gt;
Three.js has one feature that is quite convincing — its free. Basically, if Blender is free, Three.js is free, and your time is free you are just great! You can make something really big, share it, get some recognition, or even sell your work without paying a buck!&lt;br /&gt;
&lt;br /&gt;
On the other side, if [https://www.soft8soft.com/licensing/ paying some money] for a license is not a big deal — you better stick to Verge3D. Not only because its more powerful yet compatible with Three.js. Verge3D is designed to be an artist-friendly tool, so it will be very helpful if you already use or going to use Blender in your development pipeline.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Verge3D_for_Maya_Tutorials&amp;diff=308</id>
		<title>Verge3D for Maya Tutorials</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Verge3D_for_Maya_Tutorials&amp;diff=308"/>
		<updated>2021-10-13T11:38:42Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Official */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]&lt;br /&gt;
== Official ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/playlist?list=PLMnTV0uuRMhS89ra_kYqKPYbpCv2Eh5GO Verge3D for Maya Basics video course]&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=KVSB3vFmv8M Using Light Probes]&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
* [https://youtu.be/Os9skozlm6M So you want a cool Maya plugin?] — Verge3D for Maya review by Mike Hermes.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Verge3D_for_3ds_Max_Tutorials&amp;diff=307</id>
		<title>Verge3D for 3ds Max Tutorials</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Verge3D_for_3ds_Max_Tutorials&amp;diff=307"/>
		<updated>2021-10-13T11:37:52Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Official */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]&lt;br /&gt;
== Official ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/playlist?list=PLMnTV0uuRMhR2zhXxPqAD8G9wp_LNIXZc Verge3D for 3ds Max Basics video course]&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=J3gV2zpvgwo Using Light Probes]&lt;br /&gt;
&lt;br /&gt;
* [https://youtu.be/t4RCYBMn-8I Converting AutoCAD drawing to WebGL-based interactives].&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=U6aGboR_sHE Verge3D with 3ds Max] — creating interactive car visualization in 3ds Max (by Jamie Cardoso).&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Verge3D_for_Blender_Tutorials&amp;diff=306</id>
		<title>Verge3D for Blender Tutorials</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Verge3D_for_Blender_Tutorials&amp;diff=306"/>
		<updated>2021-10-13T11:37:08Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Official */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Tutorials]]&lt;br /&gt;
== Official ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/playlist?list=PLMnTV0uuRMhRH6p4DSW-AEcQZEulzm461 Verge3D for Blender Basics video course]&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=V39heuWD_vo Using Light Probes]&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=VEliwmiEn9s Baking and Using Ambient Occlusion in Verge3D for Blender]&lt;br /&gt;
&lt;br /&gt;
* [[Baking_cloth_simulation_in_Blender_for_exporting_to_Verge3D|Baking cloth simulation in Blender for exporting to Verge3D]]&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=ihu_IR7b6xo Building HTML-Based User Interfaces for 3D Web Apps]&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=nQB6FfC7C7Y Exporting models from FreeCAD to WebGL]&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=Y-VUwoDL0qo Making interactive parametric models with Verge3D, Blender, and WebGL]&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=dJdUKwSxA8c Making 3D Product Configurators for WooCommerce]&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=_0Q2SmxROuk Timelapse - Creating Ring Configurator]&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
* [https://www.youtube.com/watch?v=U6aGboR_sHE Creating interactive interior visualization] — by Dorian Zgraggen.&lt;br /&gt;
* [https://www.youtube.com/playlist?list=PLvH2ejcv0wjRA4K6pQ6mUZgLTueIGSMe2 Creating Asteroids game] — by Dariusz Dzwonkowski.&lt;br /&gt;
* [https://youtu.be/ddRRNwBvNk0 Manual animation control, text objects and GIFT] — by CyberFox studio.&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Why_Verge3D_if_we_have_Three.js%3F&amp;diff=238</id>
		<title>Why Verge3D if we have Three.js?</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Why_Verge3D_if_we_have_Three.js%3F&amp;diff=238"/>
		<updated>2021-09-10T03:32:36Z</updated>

		<summary type="html">&lt;p&gt;Yuri: minor fixes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Personal}}&lt;br /&gt;
It&#039;s no secret that Verge3D is based on the cool and really popular WebGL framework called [https://threejs.org/ Three.js]. Three.js is open-source, so you can download and use it completely free of charge. So what makes Verge3D worth the money?&lt;br /&gt;
&lt;br /&gt;
== Way better Blender, 3ds Max, or Maya integration ==&lt;br /&gt;
&lt;br /&gt;
Older versions of Three.js included exporters for these modelling suits, but it&#039;s not the case anymore. Instead, you should rely on third-party exporters to the glTF 2.0 format and GLTFLoader plugin which should be attached to your application by hand (it&#039;s not part of the Three.js core library). Basically, to make something you need to constrain your scene features to fit into glTF 2.0 standard and be a JavaScript coder to be able to render something with Three.js.&lt;br /&gt;
&lt;br /&gt;
With Verge3D it&#039;s a completely different story. The framework was designed to be an artist-friendly tool. You just need to have some Blender, 3ds Max, or Maya skills to make any kind of 3D web content with Verge3D. Moreover, it supports features of these modelling suites (cameras, lights, shadows, constraints, animation, etc) natively and strives to make Verge3D renderings look exactly the same.&lt;br /&gt;
&lt;br /&gt;
[[File:blender_3ds_max_maya.png|1060px]]&lt;br /&gt;
&lt;br /&gt;
== Code-Less Programming ==&lt;br /&gt;
&lt;br /&gt;
Three.js requires you to have good programming skills. Since it&#039;s quite rare for a person be a good artist and a good coder at the same time, you need at least two specialists to make a non-trivial 3D web application with Three.js. Basically, the artist creates content compatible with glTF 2.0 standard, and then the coder creates an interactive app based on this content.&lt;br /&gt;
&lt;br /&gt;
A typical Verge3D user is an artist. He or she can design content, create an app, and then do &amp;quot;programming&amp;quot; using the visual logic tool called [https://www.soft8soft.com/docs/manual/en/introduction/Puzzles-Visual-Logic-Editor.html Puzzles]. Puzzles is both powerful and easy-to-use.&lt;br /&gt;
&lt;br /&gt;
See it for yourself. The following example makes default Cube clickable and replaces it by a spinning Utah Teapot: &lt;br /&gt;
&lt;br /&gt;
[[File:Puzzles_example.jpg|907px]]&lt;br /&gt;
&lt;br /&gt;
== Beyond glTF 2.0 ==&lt;br /&gt;
&lt;br /&gt;
glTF 2.0 is a great format. The major drawback is lack of many features which are absolutely required to create full-featured 3D web applications. This includes lights, shadows, complex node-based materials, post-processing effects, features to control animation playback, constraints, and many more. Of course, there are dozens of [https://github.com/KhronosGroup/glTF/tree/master/extensions glTF 2.0 extensions] which improve the situation. However, they are required to be supported in the modelling suit exporters and sometimes you need even more JavaScript coding to make them work. But what&#039;s even worse, these extensions are made to be modelling-suite independent. So, integration with Blender, 3ds Max, or Maya is not that good.&lt;br /&gt;
&lt;br /&gt;
Verge3D is based on glTF 2.0 standard but it&#039;s more than that! Thanks to the custom S8S-prefixed extensions, you can make your assets feature-rich right away. There is no need for third-party extensions and complex JavaScript coding to make your scene look awesome out-of-the-box.&lt;br /&gt;
&lt;br /&gt;
[[File:Scooter.jpg|982px]]&lt;br /&gt;
&lt;br /&gt;
== Enterprise-grade Technical Support ==&lt;br /&gt;
&lt;br /&gt;
Three.js is an open-source project developed by more than a thousand people! Most of them write code in their spare time, and do not get paid for their work. Officially, Three.js does not belong to any company and there are no &amp;quot;customers&amp;quot;, only &amp;quot;users&amp;quot;. As such, you can&#039;t get direct technical support from Three.js developers. You can ask in community groups for help, however there is no guarantee that your issue will be resolved.&lt;br /&gt;
&lt;br /&gt;
Contrary to that, Verge3D is developed by Soft8Soft, the company that offers official technical support for their enterprise-grade customers.&lt;br /&gt;
&lt;br /&gt;
== It&#039;s not a by-product of large multinational corporations ==&lt;br /&gt;
&lt;br /&gt;
Earlier we said that Three.js does not belong to any company officially. Still, the lead developer and main contributor to this software is an employee at Google. Same story is with Babylon.js, another popular WebGL toolkit, which is developed by two Microsoft employees. Of course, there are benefits of being under the umbrella of large corporations. Still there are risks, since the both products are non-profitable and do not affect Google/Microsoft income directly. This situation does not allow to say about stable development, since any activity that does not generate enough cash may get cut at any time.&lt;br /&gt;
&lt;br /&gt;
[[File:umbrella.png|Biohazard!|512px]]&lt;br /&gt;
&lt;br /&gt;
On the other hand, Verge3D is Soft8Soft&#039;s flagship product, and this small enterprise invests all its resources in development and promotion.&lt;br /&gt;
&lt;br /&gt;
== App Manager ==&lt;br /&gt;
&lt;br /&gt;
Verge3D comes with the App Manager, a tool which offers many important features:&lt;br /&gt;
&lt;br /&gt;
* Creating ready-to-use applications based on templates.&lt;br /&gt;
* Running apps, opening models, using Puzzles editor, working with project files from one place.&lt;br /&gt;
* Creating Desktop and Mobile apps.&lt;br /&gt;
* Updating apps.&lt;br /&gt;
* Getting informed when new Verge3D version is out.&lt;br /&gt;
* Uploading files to Verge3D Network.&lt;br /&gt;
&lt;br /&gt;
== Verge3D Network ==&lt;br /&gt;
&lt;br /&gt;
Three.js is just a library. It does not include any services to help you make your app available online. With Verge3D Network, an easy-to-use hosting and CDN platform, you can get the job done in seconds. Still, hosting on Verge3D Network is optional, so there is no vendor lock-in and other nasty stuff.&lt;br /&gt;
&lt;br /&gt;
== More ==&lt;br /&gt;
&lt;br /&gt;
There is more. Verge3D comes with:&lt;br /&gt;
&lt;br /&gt;
* Cooler [https://www.soft8soft.com/docs/manual/en/index.html documentation].&lt;br /&gt;
* Official [https://www.soft8soft.com/get-verge3d/ tutorial videos] to help you get started.&lt;br /&gt;
* Nice [https://www.soft8soft.com/forums forums] and [https://discord.com/invite/vGMAAED Discord channel].&lt;br /&gt;
* [[:Category:Plugins|Plugins]]!&lt;br /&gt;
* Out-of-the-box asset compression.&lt;br /&gt;
* Ready-to-use material libraries.&lt;br /&gt;
* Easy integration with HTML builders, such as WebFlow.&lt;br /&gt;
&lt;br /&gt;
... and of course this [[Main Page|Community Wiki]] that everyone can edit!&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
	<entry>
		<id>https://www.soft8soft.com/wiki/index.php?title=Main_Page&amp;diff=42</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.soft8soft.com/wiki/index.php?title=Main_Page&amp;diff=42"/>
		<updated>2021-08-03T08:32:16Z</updated>

		<summary type="html">&lt;p&gt;Yuri: /* Getting started */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;strong&amp;gt;Welcome to Verge3D Wiki!&amp;lt;/strong&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here is a community-driven source of information that will help you to become a Verge3D expert!&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
&lt;br /&gt;
Welcome to Verge3D community wiki that everyone can edit!&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
&lt;br /&gt;
{{Special:AllPages}}&lt;br /&gt;
&lt;br /&gt;
== Contribute ==&lt;br /&gt;
&lt;br /&gt;
Feel free to create a new page by searching for its name or by following the link:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;https://www.soft8soft.com/wiki/index.php/NEW_ARTICLE_NAME&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Yuri</name></author>
	</entry>
</feed>