着色器語言GLSL ES和相關的WebGL API、
OpenGL ES Shader相關API —— GLSL 語法
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - indexed instancing (single box), dynamic updates</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
a {color: #08f;}
</style>
</head>
<body>
<div id="container"></div>
<script src="js/three.js"></script>
<script src="js/WebGL.js"></script>
<script id="vertexShader" type="x-shader/x-vertex">
// 頂點着色器(vertexShader)
precision highp float;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
attribute vec3 jinold_position;
attribute vec3 jinold_offset;
attribute vec2 jinold_uv;
attribute vec4 jinold_orientation;
varying vec2 vUv;
// http://www.geeks3d.com/20141201/how-to-rotate-a-vertex-by-a-quaternion-in-glsl/
vec3 applyQuaternionToVector( vec4 q, vec3 v ){
return v + 2.0 * cross( q.xyz, cross( q.xyz, v ) + q.w * v );
}
void main() {
vec3 vPosition = applyQuaternionToVector( jinold_orientation, jinold_position );
vUv = jinold_uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( jinold_offset + vPosition, 1.0 );
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
// 片段着色器(fragmentShader)
precision highp float;
uniform sampler2D map;
varying vec2 vUv;
void main() {
gl_FragColor = texture2D( map, vUv );
}
</script>
<script>
if ( WEBGL.isWebGLAvailable() === false ) {
document.body.appendChild( WEBGL.getWebGLErrorMessage() );
}
var container;
var camera, scene, renderer, mesh;
var offsetAttribute, orientationAttribute;
init();
animate();
function init() {
container = document.getElementById( 'container' );
camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
scene = new THREE.Scene();
scene.background = new THREE.Color( 0x101010 );
// geometry
var shuliang = 30;
var bufferGeometry = new THREE.BoxBufferGeometry( 2, 2, 2 );
var geometry = new THREE.InstancedBufferGeometry();
geometry.index = bufferGeometry.index;
// geometry.attributes.position = bufferGeometry.attributes.position;
/* UV 數據
前面的學習中瞭解到每個原始正方形平面由兩個三角形組成,
所以每一面都有兩組UV數據,每一組對應一個三角形
x, y, z, w
0, 1, 1, 1, // 面1-1 UV
0, 0, 1, 0, // 面1-2 UV
0, 1, 1, 1, // 面2-1 UV
0, 0, 1, 0, // 面2-2 UV
0, 1, 1, 1, // 面3-1 UV
0, 0, 1, 0, // 面3-2 UV
0, 1, 1, 1, // 面4-1 UV
0, 0, 1, 0, // 面4-2 UV
0, 1, 1, 1, // 面5-1 UV
0, 0, 1, 0, // 面5-2 UV
0, 1, 1, 1, // 面6-1 UV
0, 0, 1, 0 // 面6-2 UV
*/
// geometry.attributes.uv = bufferGeometry.attributes.uv;
// Box位置
var offsets = getOffsets();
// Box轉向角度
var orientations = getOrientations();
offsetAttribute = new THREE.InstancedBufferAttribute( new Float32Array( offsets ), 3 );
orientationAttribute = new THREE.InstancedBufferAttribute( new Float32Array( orientations ), 4 ).setDynamic( true );
geometry.addAttribute( 'position', bufferGeometry.attributes.position ); // position又是Threejs的關鍵詞,需要保留
geometry.addAttribute( 'jinold_position', bufferGeometry.attributes.position );
geometry.addAttribute( 'jinold_uv', bufferGeometry.attributes.uv );
geometry.addAttribute( 'jinold_offset', offsetAttribute );
geometry.addAttribute( 'jinold_orientation', orientationAttribute );
// material
var material = new THREE.RawShaderMaterial( {
uniforms: {
map: { value: new THREE.TextureLoader().load( 'textures/brick_diffuse.jpg' ) }
},
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent
} );
mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
/*
var geometry = new THREE.BoxBufferGeometry(1, 1, 1); // 創建一個長方體,用來定義物體的形狀
var material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); // 創建一個材質,用來定義物體的顏色
var mesh = new THREE.Mesh(geometry, material); // 使用形狀和素材,來定義物體
scene.add(mesh);
*/
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
}
function getOffsets() {
var offsets = [];
var x, y, z;
/*
* vector
*/
var vector = new THREE.Vector4();
x = 0;
y = 0;
z = -5;
vector.set( x, y, z, 0 ).normalize();
//vector.multiplyScalar( 5 ); // move out at least 5 units from center in current direction
/*
* 從當前方向的中心向外移動至少5個單位
* multiplyScalar越大,物體離中心點越遠,物體看起來越來越小
*/
vector.multiplyScalar( 1 );
offsets.push( x + vector.x, y + vector.y, z + vector.z );
return offsets
}
function getOrientations() {
var x, y, z, w;
var orientations = [];
/*
* vector
*/
var vector = new THREE.Vector4();
// orientations
x = Math.random();
y = Math.random();
z = Math.random();
w = Math.random();
vector.set( x, y, z, w ).normalize();
orientations.push( vector.x, vector.y, vector.z, vector.w );
return orientations
}
function onWindowResize( event ) {
camera.aspect = window.innerWidth / window.innerHeight;
// 更新相機投影矩陣,必須在參數發生變化後調用。
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
renderer.render( scene, camera );
}
</script>
</body>
</html>