Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
403 lines (278 sloc) 9.06 KB
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - instancing - lambert shader</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
color: #ffffff;
font-family: Monospace;
font-size: 13px;
text-align: center;
font-weight: bold;
background-color: #000000;
margin: 0px;
overflow: hidden;
}
#info {
position: absolute;
top: 0px;
width: 100%;
padding: 5px;
}
a {
color: #ffffff;
}
#notSupported {
width: 50%;
margin: auto;
border: 2px red solid;
margin-top: 20px;
padding: 10px;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info">
<a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - instancing - lambert shader
<div id="notSupported" style="display:none">Sorry your graphics card + browser does not support hardware instancing</div>
</div>
<script src="../build/three.js"></script>
<script src="js/WebGL.js"></script>
<script src="js/libs/stats.min.js"></script>
<script src="js/controls/OrbitControls.js"></script>
<script src="js/CurveExtras.js"></script>
<script>
if ( WEBGL.isWebGLAvailable() === false ) {
document.body.appendChild( WEBGL.getWebGLErrorMessage() );
}
THREE.ShaderLib.customDepthRGBA = { // this is a cut-and-paste of the depth shader -- modified to accommodate instancing for this app
uniforms: THREE.ShaderLib.depth.uniforms,
vertexShader:
`
// instanced
#ifdef INSTANCED
attribute vec3 instanceOffset;
attribute float instanceScale;
#endif
#include <common>
#include <uv_pars_vertex>
#include <displacementmap_pars_vertex>
#include <morphtarget_pars_vertex>
#include <skinning_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
void main() {
#include <uv_vertex>
#include <skinbase_vertex>
#ifdef USE_DISPLACEMENTMAP
#include <beginnormal_vertex>
#include <morphnormal_vertex>
#include <skinnormal_vertex>
#endif
#include <begin_vertex>
// instanced
#ifdef INSTANCED
transformed *= instanceScale;
transformed = transformed + instanceOffset;
#endif
#include <morphtarget_vertex>
#include <skinning_vertex>
#include <displacementmap_vertex>
#include <project_vertex>
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
}
`,
fragmentShader: THREE.ShaderChunk.depth_frag
};
THREE.ShaderLib.lambert = { // this is a cut-and-paste of the lambert shader -- modified to accommodate instancing for this app
uniforms: THREE.ShaderLib.lambert.uniforms,
vertexShader:
`
#define LAMBERT
#ifdef INSTANCED
attribute vec3 instanceOffset;
attribute vec3 instanceColor;
attribute float instanceScale;
#endif
varying vec3 vLightFront;
#ifdef DOUBLE_SIDED
varying vec3 vLightBack;
#endif
#include <common>
#include <uv_pars_vertex>
#include <uv2_pars_vertex>
#include <envmap_pars_vertex>
#include <bsdfs>
#include <lights_pars_begin>
#include <color_pars_vertex>
#include <fog_pars_vertex>
#include <morphtarget_pars_vertex>
#include <skinning_pars_vertex>
#include <shadowmap_pars_vertex>
#include <logdepthbuf_pars_vertex>
#include <clipping_planes_pars_vertex>
void main() {
#include <uv_vertex>
#include <uv2_vertex>
#include <color_vertex>
// vertex colors instanced
#ifdef INSTANCED
#ifdef USE_COLOR
vColor.xyz = instanceColor.xyz;
#endif
#endif
#include <beginnormal_vertex>
#include <morphnormal_vertex>
#include <skinbase_vertex>
#include <skinnormal_vertex>
#include <defaultnormal_vertex>
#include <begin_vertex>
// position instanced
#ifdef INSTANCED
transformed *= instanceScale;
transformed = transformed + instanceOffset;
#endif
#include <morphtarget_vertex>
#include <skinning_vertex>
#include <project_vertex>
#include <logdepthbuf_vertex>
#include <clipping_planes_vertex>
#include <worldpos_vertex>
#include <envmap_vertex>
#include <lights_lambert_vertex>
#include <shadowmap_vertex>
#include <fog_vertex>
}
`,
fragmentShader: THREE.ShaderLib.lambert.fragmentShader
};
//
var mesh, renderer, scene, camera, controls;
var stats;
init();
animate();
function init() {
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.shadowMap.enabled = true;
document.body.appendChild( renderer.domElement );
renderer.gammaOutput = true;
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2( 0x000000, 0.004 );
renderer.setClearColor( scene.fog.color, 1 );
camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 1000 );
camera.position.set( 80, 40, 80 );
scene.add( camera );
controls = new THREE.OrbitControls( camera, renderer.domElement );
controls.enableZoom = false;
controls.maxPolarAngle = Math.PI / 2;
scene.add( new THREE.AmbientLight( 0xffffff, 0.7 ) );
var light = new THREE.DirectionalLight( 0xffffff, 0.4 );
light.position.set( 50, 40, 0 );
light.castShadow = true;
light.shadow.camera.left = - 40;
light.shadow.camera.right = 40;
light.shadow.camera.top = 40;
light.shadow.camera.bottom = - 40;
light.shadow.camera.near = 10;
light.shadow.camera.far = 180;
light.shadow.bias = - 0.001;
light.shadow.mapSize.width = 512;
light.shadow.mapSize.height = 512;
scene.add( light );
// light shadow camera helper
//light.shadowCameraHelper = new THREE.CameraHelper( light.shadow.camera );
//scene.add( light.shadowCameraHelper );
// instanced buffer geometry
var geometry = new THREE.InstancedBufferGeometry();
geometry.copy( new THREE.TorusBufferGeometry( 2, 0.5, 8, 128 ) );
const INSTANCES = 256;
var knot = new THREE.Curves.TorusKnot( 10 );
var positions = knot.getSpacedPoints( INSTANCES );
var offsets = new Float32Array( INSTANCES * 3 ); // xyz
var colors = new Float32Array( INSTANCES * 3 ); // rgb
var scales = new Float32Array( INSTANCES * 1 ); // s
for ( var i = 0, l = INSTANCES; i < l; i ++ ) {
var index = 3 * i;
// per-instance position offset
offsets[ index ] = positions[ i ].x;
offsets[ index + 1 ] = positions[ i ].y;
offsets[ index + 2 ] = positions[ i ].z;
// per-instance color tint - optional
colors[ index ] = 1;
colors[ index + 1 ] = 1;
colors[ index + 2 ] = 1;
// per-instance scale variation
scales[ i ] = 1 + 0.5 * Math.sin( 32 * Math.PI * i / INSTANCES );
}
geometry.addAttribute( 'instanceOffset', new THREE.InstancedBufferAttribute( offsets, 3 ) );
geometry.addAttribute( 'instanceColor', new THREE.InstancedBufferAttribute( colors, 3 ) );
geometry.addAttribute( 'instanceScale', new THREE.InstancedBufferAttribute( scales, 1 ) );
// material
var envMap = new THREE.TextureLoader().load( `textures/metal.jpg`, function ( texture ) {
texture.mapping = THREE.SphericalReflectionMapping;
texture.encoding = THREE.sRGBEncoding;
if ( mesh ) mesh.material.needsUpdate = true;
} );
var material = new THREE.MeshLambertMaterial( {
color: 0xffb54a,
envMap: envMap,
combine: THREE.MultiplyOperation,
reflectivity: 0.8,
vertexColors: THREE.VertexColors,
fog: true
} );
material.defines = material.defines || {};
material.defines[ 'INSTANCED' ] = "";
// custom depth material - required for instanced shadows
var shader = THREE.ShaderLib[ 'customDepthRGBA' ];
var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
var customDepthMaterial = new THREE.ShaderMaterial( {
defines: {
'INSTANCED': "",
'DEPTH_PACKING': THREE.RGBADepthPacking
},
uniforms: uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
} );
//
mesh = new THREE.Mesh( geometry, material );
mesh.scale.set( 1, 1, 2 );
mesh.castShadow = true;
mesh.receiveShadow = true;
mesh.customDepthMaterial = customDepthMaterial;
mesh.frustumCulled = false;
scene.add( mesh );
//
var ground = new THREE.Mesh(
new THREE.PlaneBufferGeometry( 800, 800 ).rotateX( - Math.PI / 2 ),
new THREE.MeshPhongMaterial( { color: 0x888888 } )
);
ground.position.set( 0, - 40, 0 );
ground.receiveShadow = true;
scene.add( ground );
//
stats = new Stats();
document.body.appendChild( stats.dom );
//
window.addEventListener( 'resize', onWindowResize, false );
}
function onWindowResize() {
renderer.setSize( window.innerWidth, window.innerHeight );
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame( animate );
mesh.rotation.y += 0.005;
stats.update();
renderer.render( scene, camera );
}
</script>
</body>
</html>