效果图如下:代码如下(代码还需要优化,暂时能实现效果就行)
<!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>