three.js ~ Cylinder + Sphere Impostor Example

2016-14-03

by Ludovic Bailly

HTML

<script src="http://threejs.org/build/three.js"></script>
<script src="http://threejs.org/examples/js/controls/OrbitControls.js"></script>
<script id="shaderCyl-vs" type="x-shader/x-vertex">
// Inherits from Phong Shading in ThreeJS, allows compatibility with chunks
#define PHONG

// Normalize diagonal matrix (1)
const mat4 D = mat4(
    vec4(1.0, 0.0, 0.0, 0.0),
    vec4(0.0, 1.0, 0.0, 0.0),
    vec4(0.0, 0.0, 0.0, 0.0),
    vec4(0.0, 0.0, 0.0, -1.0)
);

const mat4 t1 = mat4(
    vec4(1.0, 0.0, 0.0, 0.0),
    vec4(0.0, 1.0, 0.0, 0.0),
    vec4(0.0, 0.0, 0.0, 0.0),
    vec4(0.0, 0.0, 1.0, 1.0)
);

const mat4 t2 = mat4(
    vec4(1.0, 0.0, 0.0, 0.0),
    vec4(0.0, 1.0, 0.0, 0.0),
    vec4(0.0, 0.0, 0.0, 0.0),
    vec4(0.0, 0.0, -1.0, 1.0)
);

// Create transpose method (not built-in OpenGL ES Shading Language)
highp mat4 transpose(in highp mat4 inMatrix) {
    highp vec4 i0 = inMatrix[0];
    highp vec4 i1 = inMatrix[1];
    highp vec4 i2 = inMatrix[2];
    highp vec4 i3 = inMatrix[3];

    highp mat4 outMatrix = mat4(
        vec4(i0.x, i1.x, i2.x, i3.x),
        vec4(i0.y, i1.y, i2.y, i3.y),
        vec4(i0.z, i1.z, i2.z, i3.z),
        vec4(i0.w, i1.w, i2.w, i3.w)
    );

    return outMatrix;
}

#include <common>
#include <color_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>

attribute float radius;
attribute vec3 dir;

uniform vec4 viewport;
uniform mat4 modelViewMatrixInverse;

varying mat4 MTInverse;
varying mat4 VPInverse;
varying vec4 centernormclip;

// Near, far, width and height
varying float n, f, w, h;
varying float projMatrix11;
varying float projMatrix22;

// Compatibility with threejs chunks
varying vec3 vViewPosition;
varying vec3 vViewDirection;
varying float vLength;

void main() {
    // Chunck to color vertex with vertex color attribute
    #include <color_vertex>

    // Chunck to compute position in world space
    #include <begin_vertex>
    #include <project_vertex>
    #include <logdepthbuf_vertex>
...

JavaScript

var camera, scene, light, renderer, geometryCyl, geometrySphere, material, mesh1, mesh2, gl;

var WIDTH = window.innerWidth - 20;
var HEIGHT = window.innerHeight - 20;

var controls;
var impostorMaterialCyl;
var impostorMaterialSphere;

createImpostorMaterial();
init();
animate();

function init() {
    scene = new THREE.Scene();

		var axisHelper = new THREE.AxisHelper( 1 );
		scene.add( axisHelper );

    camera = new THREE.PerspectiveCamera(50, WIDTH / HEIGHT, 1, 100);
    camera.position.z = 30;
    camera.position.y = 0;
    
    var ambient = new THREE.AmbientLight( 0x404040 );
    scene.add(ambient);
    
    var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.0 );
		directionalLight.position.set( 0, 3, 3 );
		scene.add( directionalLight );
    
    var helper = new THREE.DirectionalLightHelper(directionalLight, 1);
    scene.add(helper);
    
    scene.add(camera);
    
    // controls
    controls = new THREE.OrbitControls( camera );

		var geometry1 = createBufferGeometryCyl();
    mesh1 = new THREE.Points(geometry1, impostorMaterialCyl);
    scene.add(mesh1);
    
    var geometry2 = createBufferGeometrySphere();
    mesh2 = new THREE.Points(geometry2, impostorMaterialSphere);
    scene.add(mesh2);
    
    renderer = new THREE.WebGLRenderer({ antialias: true, preserveDrawingBuffer: true});
    renderer.setSize(WIDTH, HEIGHT);
    renderer.autoClear = false;
    renderer.sortObjects = true;

    document.body.appendChild(renderer.domElement);
}
    
function animate() {
  	requestAnimationFrame(animate);
    render();
}

function render() {
    // Clear renderer
		renderer.clear();

		// Update uniforms for outline
		updateMaterialUniforms(scene, camera);
    
    // Render the scene
    renderer.render(scene, camera);
}

function createBufferGeometryCyl() {
		var geometry = new THREE.BufferGeometry();

		// Creating array buffers
    var positionArray = [];
    var colorArray = [];
    var radiusArray = [];
    var dirArray = [];
    
   ...