效果圖如下:代碼如下(代碼還需要優化,暫時能實現效果就行)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>160萬個幾何體</title>
<style>
body{
color: #cccccc;
font-family: monospace;
font-size: 13px;
text-align: center;
background-color: #FF8C00;
margin: 0px;
overflow: hidden;
}
#info{
position: absolute;
top: 0px;
width: 100%;
padding: 5px;
}
a{
color: cornflowerblue;
}
</style>
</head>
<body>
<div id="container"></div>
<div id="info">WEBGL_ThreeJs:高性能渲染保持高幀數</div>
<script src="../../js/three.js"></script>
<script src="../../js/Stats.js"></script>
<script src="../../js/WEBGL.js"></script>
<script>
//檢測瀏覽器是否支持webgl
if( !WEBGL.isWebGLAvailable() ){
var warning = WEBGL.getWebGLErrorMessage();
document.getElementById('container').appendChild(warning);
}
//執行函數
initAll();
animate();
//聲明常量
var container,states;
var renderer,camera,scene;
var mesh;
//初始化容器
function initContainer() {
container = document.getElementById("container");
}
//初始化相機
function initCamera() {
camera = new THREE.PerspectiveCamera(45,window.innerWidth / window.innerHeight,1,3500);
//相機位置
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 2800;
//相機快門座標
camera.up.x = 0;
camera.up.y = 1;
camera.up.z = 0;
//鏡頭的朝向
camera.lookAt(0,0,1);
}
//初始化場景
function initScene() {
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x050505,2000,3500);
}
//初始化燈光
function initLight() {
//環境光
var lightAm = new THREE.AmbientLight(0x444444,1.0);
scene.add(lightAm);
//方向光
var lightDi1 = new THREE.DirectionalLight(0xffffff,0.5);
lightDi1.position.set(1,1,1);
scene.add(lightDi1);
var lightDi2 = new THREE.DirectionalLight(0xffffff,1.5);
lightDi2.position.set(0,-1,0);
scene.add(lightDi2);
}
function initObject() {
//定義三角形
var triangles = 160000;
//模型多,使用buffer更高效
var geometry = new THREE.BufferGeometry();
//形成三角形的點的個數,
var positions = new Float32Array(triangles*3*3);
//每個頂點一個法向量,也可以每個面一個法向量
var normals = new Float32Array(triangles*3*3);
//每個頂點一個顏色
var colors = new Float32Array(triangles*3*3);
//實例化顏色
var color = new THREE.Color();
//正方體的邊長爲800
var n = 800;
//正方體邊長的一半
var n2 = n/2;
//三角形邊長
var d = 12;
//三角形邊長的一半
var d2 = d / 2;
//聲明三角形頂點的位置
var pA = new THREE.Vector3();
var pB = new THREE.Vector3();
var pC = new THREE.Vector3();
//a-b\c-b的兩條線
var ab = new THREE.Vector3();
var cb = new THREE.Vector3();
for(var i = 0; i < positions.length; i += 9){
//隨機每個座標的位置
var x = Math.random() * n - n2;
var y = Math.random() * n - n2;
var z = Math.random() * n - n2;
//隨機每個點的位置
var ax = x + Math.random() * d -d2;
var ay = y + Math.random() * d -d2;
var az = z + Math.random() * d -d2;
var bx = x + Math.random() * d -d2;
var by = y + Math.random() * d -d2;
var bz = z + Math.random() * d -d2;
var cx = x + Math.random() * d -d2;
var cy = y + Math.random() * d -d2;
var cz = z + Math.random() * d -d2;
positions[ i ] = ax;
positions[ i + 1] = ay;
positions[ i + 2] = az;
positions[ i + 3] = bx;
positions[ i + 4] = by;
positions[ i + 5] = bz;
positions[ i + 6] = cx;
positions[ i + 7] = cy;
positions[ i + 8] = cz;
//座標放入vector中
pA.set(ax,ay,az);
pB.set(bx,by,bz);
pC.set(cx,cy,cz);
//使用向量的減法算出ab\cb向量
ab.subVectors(pA,pB);
cb.subVectors(pC,pB);
//計算出垂直於屏幕的向量,也稱之爲法線。根據ab、cb計算,返回值會賦給被調用的函數名(用詞不太對)
cb.cross(ab);
//法線的歸一化(按比例縮短到單位長度,方向不變,也就是說不管這條線有多長,都縮短到1,方向不變)
cb.normalize();
//法線
var nx = cb.x;
var ny = cb.y;
var nz = cb.z;
normals[ i ] = nx;
normals[ i + 1 ] = ny;
normals[ i + 2 ] = nz;
normals[ i + 3 ] = nx;
normals[ i + 4 ] = ny;
normals[ i + 5 ] = nz;
normals[ i + 6 ] = nx;
normals[ i + 7 ] = ny;
normals[ i + 8 ] = nz;
//顏色
var vx = ( x / n ) + 0.5;
var vy = ( y / n ) + 0.5;
var vz = ( z / n ) + 0.5;
//設置RGB通道值
color.setRGB(vx , vy , vz);
colors[ i ] = color.r;
colors[ i + 1 ] = color.g;
colors[ i + 2 ] = color.b;
colors[ i + 3 ] = color.r;
colors[ i + 4 ] = color.g;
colors[ i + 5 ] = color.b;
colors[ i + 6 ] = color.r;
colors[ i + 7 ] = color.g;
colors[ i + 8 ] = color.b;
}
//把值添加到geometry中
geometry.addAttribute('position',new THREE.BufferAttribute(positions,3));
geometry.addAttribute('normal',new THREE.BufferAttribute(normals,3));
geometry.addAttribute('color',new THREE.BufferAttribute(colors,3));
//計算幾何體的外邊界球,可用作物體的碰撞或相交
geometry.computeBoundingSphere();
var material = new THREE.MeshPhongMaterial({
color:0xaaaaaa , specular:0xffffff , shininess:250,
side:THREE.DoubleSide , vertexColors:THREE.VertexColors
});
mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
}
//初始化渲染器
function initRenderer() {
renderer = new THREE.WebGLRenderer({
antialias:false
});
//設置渲染器的大小
renderer.setSize(window.innerWidth,window.innerHeight);
//清理顏色
renderer.setClearColor(scene.fog.color);
//設置設備像素比
renderer.setPixelRatio(container.devicePixelRatio);
//渲染到容器中
container.appendChild(renderer.domElement);
//gamma矯正,使畫面看起來舒服
renderer.gammaInput = true;
renderer.gammaOutput = true;
//性能監視器
states = new Stats();
states.domElement.style.position = 'absolute';
states.domElement.style.top = '0';
container.appendChild(states.domElement);
//容器視圖調整大小時執行函數
window.addEventListener('resize',onContainerResite,false);
}
//視圖改變大小時被執行的函數
function onContainerResite() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth , window.innerHeight);
}
//循環渲染
function animate() {
requestAnimationFrame(animate);
render();
states.update();
}
function render() {
var time = Date.now() * 0.001;
mesh.rotation.x = time * 0.25;
mesh.rotation.y = time * 0.25;
renderer.render(scene , camera);
}
//執行所有函數
function initAll() {
initContainer();
initCamera();
initScene();
initLight();
initObject();
initRenderer();
}
</script>
</body>
</html>