3D on the Web

About Me

Shiya Luo

Developer Advocate at Autodesk

@ShiyaLuo

(Web)GL 101

  • Based on OpenGL ES
  • Meant for browsers

WebGL
programmable

graphics pipeline

Drawing stuff with WebGL

Setting up the scene with a canvas and a background

var canvas = document.getElementById('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

var gl = canvas.getContext('webgl'); // vs 2D

// background color
gl.clearColor(1, 1, 0, 0.5);
gl.clear(gl.COLOR_BUFFER_BIT);

Vertex Shader

// vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, [
  'attribute vec2 position;', // pass in attribute
  'void main() {', // every shader needs a main func
    'gl_Position = vec4(position, 0.1, 1.0);', // set a position
  '}'
].join('\n'));
gl.compileShader(vertexShader);

Fragment Shader

// fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, [
  'precision highp float;',
  'uniform vec4 color;',
  'void main() {',
    'gl_FragColor = color;',
  '}'
].join('\n'));
gl.compileShader(fragmentShader);

Bind the shaders together, draw vertices, and call all those functions

var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);

var vertices = new Float32Array([
  0, 0.6,
  0.3, 0,
  -0.3, 0
]);

var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

gl.useProgram(program);
program.color = gl.getUniformLocation(program, 'color');
gl.uniform4fv(program.color, [0, 0, 0, 0.5]);

program.position = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(program.position);
gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0);

gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 2);
Effect

WebGL: 从入门到放弃

An Easier Way of

3D on the web

Different libraries to choose from...

three.js, babylon.js, A-frame

Game engines like Unity exports to WebGL

three.js

Abtracts away triangles in GL programming

Into actual objects and things in space

var cylinder = new THREE.Mesh(
  new THREE.CylinderGeometry( 100, 100, 200, 32 ),
  new THREE.MeshBasicMaterial( {color: 0x2194ce} )
);

Getting Started

  • scene, camera, renderer, controls
  • put stuff in the scene
  • animate
init();
fillScene();
animate();
function init() {
  scene = new THREE.Scene();

  camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 );
  camera.position.z = 1000;

  renderer = new THREE.WebGLRenderer();
  renderer.setClearColor( 0x31AED1, 1);
  renderer.setSize( window.innerWidth, window.innerHeight );

	// reference OrbitControls.js
  controls = new THREE.OrbitControls( camera, renderer.domElement );
  controls.enableDamping = true;
  controls.dampingFactor = 0.25;
  controls.enableZoom = false;

  canvas.appendChild( renderer.domElement );
  renderer.render( scene, camera );
}
function fillScene() {
  // create a random set of particles
  for (var i = 0; i < particleCount; i++) {

    particles[i] = new THREE.Mesh( particleGeometry, particleMaterial );

    //randomize positions
    var px = Math.random() * window.innerWidth * 2 - window.innerWidth;
    var py = Math.random() * window.innerHeight * 2 - window.innerHeight;
    var pz = Math.random() * window.innerWidth * 2 - window.innerWidth;

    particles[i].position.x = px;
    particles[i].position.y = py;
    particles[i].position.z = pz;

    particles[i]. direction = {
      x: Math.random(),
      y: Math.random()
    }

    scene.add(particles[i]);
  }
}

Animate

  • requestAnimationFrame();
  • Computer rendered animation needs to be 60fps to be seamless for human eye (contrary to 24fps for film)
  • Call animate() every time browser refreshes
function animate() {
    requestAnimationFrame( animate );
    controls.update();

    for (var i = 0; i < particleCount; i++) {
      particles[i].position.x += particles[i].direction.x;
      particles[i].position.y += particles[i].direction.y;

      // if edge is reached, bounce back
      if (particles[i].position.x < -window.innerWidth ||
      particles[i].position.x > window.innerWidth) {
        particles[i].direction.x = -particles[i].direction.x;
      }
      if (particles[i].position.y < -window.innerHeight ||
      particles[i].position.y > window.innerHeight) {
        particles[i].direction.y = -particles[i].direction.y;
      }
    }

    renderer.render( scene, camera );
}
Source

VR

Replace the camera and controls code with

camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 1100 );
controls = new THREE.DeviceOrientationControls( camera );

Demos

Viewer

Viewer with Toolbar

Project Play

Thank You