If you have a project based on Three.js with bundler like webpack you can skip to Adding Leia WebGL SDK
Prerequisites: you will need node installed. You can get it on https://nodejs.org/ or use your package installer.
NPM and Webpack Setup
Open a terminal, cd to a new dir and initialize a new project:
mkdirmyprojectcdmyprojectnpminit
You can press Enter multiple times to fill default values for your project. A file named package.json would be created, feel free to examine it.
Make a dir for your source files, named src:
mkdirsrc
Make a dir for the "build" of your project, named dist:
mkdir dist
This directory would be used by server to serve files.
Install dependencies: a bundler that will resolve imports and update dist dir, a server and popular webgl framework three.js.
npminstallwebpackexpressthree
Create empty main script file src/index.js and run webpack:
npxwebpack
It will ask you about installation of webpack-cli but only first time.
Notice that dist dir got new file: dist/main.js, it's empty just like the src/index.js
You will write your code in src/index.js, running npx webpack will transform it into dist/main.js (do not edit it!) while resolving dependencies. The server you will configure will serve files from the dist directory. Let's configure the server now.
In the root of your project create a file named app.js with next content:
var express =require('express');var app =express();app.use(express.static(__dirname +'/dist'));app.listen(3000);console.log('open 127.0.0.1:3000 in your browser');
Since there's nothing to serve yet, create index.html under dist directory with some basic content like:
<h1>Hello, world!</h1>
Now run the server:
nodeapp.js
After opening http://127.0.0.1:3000/ in your browser you will see a "Hello, world!" message. Press Ctrl+C to stop the server.
Creating A Rotating Cube
Let's reference our script, put these lines into dist/index.html:
A canvas is the place where you will be rendering something using WebGL.
Let's write our src/index.js now, start from importing three.js:
import*as THREE from'three';functionmain() {// setup:constcanvas=document.querySelector('#myCanvas');constrenderer=newTHREE.WebGLRenderer({canvas});constfov=60,aspect=1.6,near=0.1,far=100;constcamera=newTHREE.PerspectiveCamera(fov, aspect, near, far);constscene=newTHREE.Scene();scene.background =newTHREE.Color("rgb(0, 128, 256)");// creating example textured cube constloader=newTHREE.TextureLoader();constgeometry=newTHREE.BoxGeometry(1,1,1);constmaterial=newTHREE.MeshBasicMaterial({ map:loader.load('texture.jpg'), });constcube=newTHREE.Mesh(geometry, material);cube.position.z =-2; // important, cube and camera must not be at same placescene.add(cube);// render loopfunctionrender(time) {// rotation animation:cube.rotation.x = time *0.001;cube.rotation.y = time *0.003;// actual rendering:renderer.render(scene, camera);// asking for next frame:requestAnimationFrame(render); }// asking for initial frame:requestAnimationFrame(render);}window.onload = main
Build it with
npxwebpack
And run server:
nodeapp.js
In browser you will see a black spinning cube on blue background:
You can see we are referencing texture.jpg but not providing any. Put some jpeg image named texture.jpg into dist/ and reload browser page. Cube should be textured now:
Configuring Webpack
Sometimes errors are hard to track due to obfuscation. To avoid this, you'll need to create webpack.config.js file and disable "minimize" parameter:
You will see that canvas is enlarged but the rendering is pixelated. This is because it needs to be resized. In the src/index.js add a function before the render function
if (resizeRendererToDisplaySize(renderer)) {constcanvas=renderer.domElement;camera.aspect =canvas.clientWidth /canvas.clientHeight;camera.updateProjectionMatrix();}
Now after calling npx webpack and node app.js you can refresh your browser page and see that it's not pixelated anymore.
Note: you must do npx webpack each time you are changing src/index.js.
For your convenience you can edit package.json by adding scripts for frequently used actions:
Changes to be committed:
new file: .gitignore
new file: app.js
new file: dist/index.html
new file: dist/texture.jpg
new file: package-lock.json
new file: package.json
new file: src/index.js
new file: webpack.config.js
gitcommit-m'Add rotating cube project'
Testing The Page
Before proceeding it's also good to test this page on your device. You can do this by accessing same WiFi point, knowing your PC/laptop IP address you do something like (requires adb):
That's only one option to organize backlight/full-screen control.
When you request a new backlight mode, onBlur (focus lost) and onFocus events happen. So if you are writing your handlers for onBlur and onFocus events you should ignore these events if you have been invoking requestBacklightMode recently (<500ms ago).
When backlight is OFF it is better to show regular rendering.
Important: LeiaWeb GL SDK requires separate canvas.
Canvas for Three.js is now accessed by searching for hidden canvas id and used only to initialize Three.js. A new mainCanvas will be used for Leia WebGL SDK.
functionmain() {// setup:constcanvas=document.querySelector('#hiddenCanvas'); // for three.jsconstmainCanvas=document.querySelector("#myCanvas"); // for leia webgl sdk
Now there's no rendering visible and you need to change code that deals with renderer and camera (you will need to use multiple cameras). Leia WebGL SDK RenderController will provide required settings for these cameras.
Initialization
After the onClick handler declaration, put initialization code:
var gl =mainCanvas.getContext("webgl", { preserveDrawingBuffer :true });constcontroller= RenderController;var convergenceDistance =20; // distance from camera to the focus pointcontroller.initialize(mainCanvas, gl, window);controller.setConvergence(convergenceDistance);
Note the distance here is 20. While in our scene we set cube position to 2. We need to update cube position (and scaling, to make it bigger):
If scaling of your scene is small, in other words if you have small objects, small distances this will create huge disparity because default baseline in RenderController is 1.
You can setConvergence but you'll need to invoke camera recalculations updateProjMats() in order to see effect of changing convergence.
Instead of a single camera declaration (comment or remove that line), use RenderController to create multiple cameras (and also place scene declaration above it):
//const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);constscene=newTHREE.Scene(); controller.setupCanvas(gl); constrtWidth=controller.getRenderTextureWidth(); constrtHeight=controller.getRenderTextureHeight(); constrenderTarget=newTHREE.WebGLRenderTarget(rtWidth,rtHeight);var cameras = []functionupdateProjMats() {let projectionMatrices =controller.getProjectionMatrices("perspective");for (let i =0; i <projectionMatrices.length; i++) {let matrix =newTHREE.Matrix4();matrix.elements = projectionMatrices[i]; cameras[i].projectionMatrix =matrix.clone(); cameras[i].projectionMatrixInverse =matrix.clone().invert(); }}var cameraPositions =controller.getCameraPositions();for (var i =0 ; i <cameraPositions.length ; i++) {// note, fov, aspect, near, far will be ignored, // you need to set them through controller:constcamera=newTHREE.PerspectiveCamera(fov, aspect, near, far);// all cameras centered around zero: camera.position.set(cameraPositions[i],0,0);cameras.push(camera); scene.add(camera); }screen.orientation.addEventListener("change",function(e) { controller.adaptToOrientation(screen.orientation.type); updateProjMats(); },false);controller.adaptToOrientation(screen.orientation.type);updateProjMats();controller.setupTextures(gl, rtWidth, rtHeight);
Rendering
Continuing to set up Leia WebGL SDK, you'll need to change your renderer function, comment renderer.render line and add:
Because or canvas is now hidden, only mainCanvas will receive clicks, change canvas.onclick = () => { to:
mainCanvas.onclick= () => {
Disable canvas fullscreen as it is currently unsupported. This is a known issue in the WebGL SDK.
//else// canvas.requestFullscreen()
At top of your html file add:
<metaname="viewport"content="...">
And in your main function set scaling once and disable user scaling to prevent 3D effect from the damage:
functionmain() {// ensure pixel perfect scaling for different display settingsdocument.querySelector("meta[name=viewport]").setAttribute ('content','initial-scale='+ (1.0/window.devicePixelRatio) +', minimum-scale=0.01, user-scalable=0');...
Result
That's it, rendering must change now (visible interlacing lines) and after clicking on your page with rotating cube you'll see Leia backlight in action.