关于WebGL
WebGL 是基于 OpenGL ES 2.0 的 Web 标准,可以通过 HTML5 Canvas 元素作为 DOM 接 口访问。
什么是 THREE.js
Three.js是JavaScript编写的WebGL第三方库。 Three.js 封装了WebGL底层的图形接口,开发人员无需掌握图形学知识即可以用简单的js代码实现三维场景的渲染。 渲染3d模型的时候,其实 是 很多个三角形拼接出来的。如下:
左边是 一个 立方体,右侧的是 一个 球体(球体的话,切分出的 三角形 越多 网格模型更加 贴近 球体);
核心代码如下
//立方体 (x轴宽度,y轴高度,z轴深度,沿宽面分段数,沿高度面分段数,沿深度面分段数)
object = new THREE.Mesh(
new THREE.BoxGeometry(100, 100, 100, 1, 1, 1),
material
);
object.position.set(-200, 0, -200);
scene.add(object);
//立方体 (x轴宽度,y轴高度,z轴深度,沿宽面分段数,沿高度面分段数,沿深度面分段数)
object = new THREE.Mesh(
new THREE.BoxGeometry(100, 100, 100, 2, 2, 2),
material
);
object.position.set(-200, 0, 200);
scene.add(object);
//球形网格 (半径长度,水平块的密度,垂直块的密度)
var object = new THREE.Mesh(new THREE.SphereGeometry(75, 5, 5), material);
object.position.set(200, 0, -200);
scene.add(object);
//球形网格 (半径长度,水平块的密度,垂直块的密度)
var object = new THREE.Mesh(new THREE.SphereGeometry(75, 50, 50), material);
object.position.set(200, 0, 200);
scene.add(object);
一个three.js 项目中 三个重要对象,场景scene、camera 、 renderer
一个典型的 Three.js 程序至少要包括渲染器(Renderer)、场景(Scene)、照相机 (Camera),以及你在场景中创建的物体。
- scene: 在 Three.js 中添加的物体都是添加到场景中的,因此它相当于一个大容器。
- renderer: 渲染器,挂载了一个canvas 标签,用来最终渲染的
- camera:摄像机,相当于在三维场景中人的眼睛。
设置好各个对象的配置信息后,最终渲染的方法就是: renderer.render(scene, camera);
看这三个对象前,需要先了解一下 three.js的坐标系
WebGL 和 Three.js 使用的坐标系是右手坐标系,看起来就是这样的:
创建一个three.js 项目的基本步骤如下
1.创建场景 scene
var scene;
function initScene(){
scene = new THREE.Scene();
}
2.创建相机 camera
两种相机,
正交相机和透视投影相机
一般说来,对于制图、建模软件通常使用正交投影,这样不会因为投影而改变物体比例; 而对于其他大多数应用,通常使用透视投影,因为这更接近人眼的观察效果。
下面图a是透视投影(近大远小,更真实),图b是正交投影
正交相机
构造函数: THREE.OrthographicCamera(left, right, top, bottom, near, far)
- 这六个参数分别代表正交投影照相机拍摄到的空间的六个面的位置,这两个面围成一个长 方体,我们称其为视景体(Frustum)。只有在视景体内部(下图中的灰色部分)的物体才 可能显示在屏幕上,而视景体外的物体会在显示之前被裁减掉。
- 为了保持照相机的横竖比例,需要保证 (right - left) 与 (top - bottom) 的比例与 Canvas 宽度与高度的比例一致。
创建方式如下:
var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);
透视投影相机
构造函数:THREE.PerspectiveCamera(fov, aspect, near, far)
- fov 是视景体竖直方向上的张角(是角度制而非弧度制),如侧视图所示。
- aspect 等于 width / height ,是照相机水平方向和竖直方向长度的比值,通常设为 Canvas 的横纵比例。
- near 和 far 分别是照相机到视景体最近、最远的距离,均为正值,且 far 应大于 near 。
透视图中,灰色的部分是视景体,是可能被渲染的物体所在的区域。
创建方式如下
var camera;
function initCamera(){
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
}
3.创建渲染器 renderer
var renderer
function initScene(){
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
}
4.创建网格模型
var geometry = new THREE.BoxGeometry(1,1,1);
var matrial = new THREE.MeshBasicMaterial({color:0x00ff00});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
5.一个简单的demo
知道了以上关键的即可以动手渲染一个简单的 3d场景
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
// 创建一个渲染器
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(windowWidth, windowHeight);
document.body.appendChild(renderer.domElement);
// 创建一个场景,所有的 3d模型都需要添加到 场景中才可以渲染
var scene = new THREE.Scene();
// 创建一个 camera
var camera = new THREE.PerspectiveCamera(
45,
windowWidth / windowHeight,
1,
4000
);
camera.position.set(0, 0, 3);
// 创建一个光找模型
var light = new THREE.AmbientLight("#ffffff");
light.position.set(0, 0, 1);
scene.add(light);
var map = new THREE.TextureLoader().load("./img/lala.jpg");
// 创建材质,在模型上需要用到
var material = new THREE.MeshPhongMaterial({
map: map
});
// 一个立方体
var geometry = new THREE.CubeGeometry(1, 1, 1);
// 创建一个 由 3d模型 和 材质组成 的 网格模型
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
(function animate() {
// 渲染
renderer.render(scene, camera);
cube.rotation.x += 0.02;
cube.rotation.y += 0.02;
requestAnimationFrame(animate);
})();
常用的几个 配置对象:
材质
基本的材质MeshBasicMaterial
使用基本材质的物体,渲染后的颜色始终为设置的颜色,也就是说不受光照影响,例如 设置太阳就很有用,当没有设置颜色的,颜色将是随机的
构造函数是:THREE.MeshBasicMaterial(opt);
//例子(创建一个 颜色为黄色,不透明度为0.75的材质)
var geometry = new THREE.SphereGeometry(3,30,30);
var map = new THREE.TextureLoader().load('./img/lala.jpg');
var material = new THREE.MeshBasicMaterial({
color:0xffff00,
opacity:0.75
})
var cube = new THREE.Mesh(geometry, material)
MeshLambert材质 和 MeshPhong材质
THREE.MeshLambertMaterial(opt) 与 THREE.MeshPhongMaterial(opt) 和 基本材质 THREE.MeshBasicMaterial(opt) 的是用方法一致。 他们的几个常用属性(逗号后面的为默认值)
- visible:是否可见 ,true
- side: 渲染面片 正面还是反面,默认为 THREE.FrontSide
- wireframe: 是否渲染为 线 而不是 面,默认为 false,
- color: 十六进制颜色(0xffffff)
- map: 使用纹理贴图,如(new THREE.TextureLoader().load('./img/lala.jpg');
区别就是 在光照下,Lambert 模型 是漫反射,更加适合用生活中的大部分情况,而Phong模型则适合用在 金属 和镜面 相对反射率 比较高的物体上
-
Phong材质
-
Lambert材质
Light(光源)
// 环境光,各个角度观察无差别
var light = new THREE.AmbientLight("#0000ff");
light.position.set(0, 0, 1);
scene.add(light);
// 点光源,顾名思义
spotLight = new THREE.PointLight("#ffffff");
spotLight.position.set(0, 0, 0);
scene.add(spotLight);
// 平行光,顾名思义
directionalLight = new THREE.DirectionalLight("#ffffff");
directionalLight.position.set(-40, 60, -10);
//告诉平行光需要开启阴影投射
directionalLight.castShadow = true;
scene.add(directionalLight);
加载外部模型,比如 stl格式
<!--需要先引入STL加载器,其他的类似-->
<script src="./lib/STLLoader.js"></script>
function initModel() {
//辅助工具
var loader = new THREE.STLLoader();
loader.load("./model/aixiaofei.stl", function(geometry) {
//创建纹理
new THREE.TextureLoader().load("./img/lala.jpg", function(map) {
var material = new THREE.MeshPhongMaterial({
color:0xffffff,
map: map
});
var mesh = new THREE.Mesh(geometry, material);
mesh.rotation.x = -0.5 * Math.PI; //将模型摆正
mesh.scale.set(0.1, 0.1, 0.1); //缩放
geometry.center(); //居中显示
scene.add(mesh);
});
});
}