基础知识
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
/**
* 创建网格模型
*/
// var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
var geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff
}); //材质对象Material
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
/**
* 光源设置
*/
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
// console.log(scene)
// console.log(scene.children)
/**
* 相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
/**
* 创建渲染器对象
*/
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height); //设置渲染区域尺寸
renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
//执行渲染操作 指定场景、相机作为参数
renderer.render(scene, camera);
对于某个3D场景的一个瞬间,是决定于当前场景和拍摄位置的。所以一方面,我们需要设置拍摄的素材(物质材质,光源),另一方面我们需要设置相机的位置(远近,方向),这样我们可以得到一张在两个场景共同作用下的图像。
如图,Mesh为素材的几何(形状)和属性(颜色,大小)共同生成的抽象素材概念,称为网络模型。网络模型收到光源后,共同生成了场景Scene。场景和相机共同作用,经过render,变成了最后的渲染结果,即投影图。
定点概念及基础结构
几何体->多个三角形->多个点
可以这么理解,几何体Geometry标识的是一种3D物体的点形成方式,材质Material标识的是如何根据这些点进行渲染。具体解释,首先Threejs中,绘制一个3d图形是通过很多个三角形来完成轮廓的绘制的,我们可以使用Buffer来手动输入所有点来绘制三角形,也可以通过new BoxGeometry(100,100,100)用封装好的接口生成这样的一系列点的轮廓。一旦获取这些点的轮廓,我们可以用轮廓绘制一个几何体,可以是一个面,可以是几个点,也可以是几条线,这些事由材质Material来赋予的。
// var material = new THREE.MeshBasicMaterial({
// color: 0x0000ff, //三角面颜色
// side: THREE.DoubleSide, //两面可见
// }); //材质对象
var material = new THREE.PointsMaterial({
color: 0xff0000,
size: 10.0, //点对象像素尺寸
}); //材质对象
var mesh = new THREE.Points(geometry, material); //网格模型对象Mesh
var material = new THREE.LineBasicMaterial({
color: 0xff0000, //线条颜色
}); //材质对象
var line = new THREE.Line(geometry, material); //线条模型对象
scene.add(line);//线条对象添加到场景中
scene.add(mesh); //网格模型添加到场景中
顶点->线->面
以顶点作为颜色计算的根本,线和面都是根据插值进行计算
var geometry = new THREE.BufferGeometry(); //创建一个Buffer类型几何体对象
//类型数组创建顶点数据
//类型数组创建顶点位置position数据
var vertices = new Float32Array([
0,
0,
0, //顶点1坐标
50,
0,
0, //顶点2坐标
0,
100,
0, //顶点3坐标
0,
0,
10, //顶点4坐标
0,
0,
100, //顶点5坐标
50,
0,
10, //顶点6坐标
]);
// 创建属性缓冲区对象
var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组,作为一个顶点的xyz坐标
// 设置几何体attributes属性的位置position属性
geometry.attributes.position = attribue;
//类型数组创建顶点颜色color数据
var colors = new Float32Array([
1,
0,
0, //顶点1颜色
0,
1,
0, //顶点2颜色
0,
0,
1, //顶点3颜色
1,
1,
0, //顶点4颜色
0,
1,
1, //顶点5颜色
1,
0,
1, //顶点6颜色
]);
// 设置几何体attributes属性的颜色color属性
geometry.attributes.color = new THREE.BufferAttribute(colors, 3); //3个为一组,表示一个顶点的颜色数据RGB
//材质对象
var material = new THREE.PointsMaterial({
// 使用顶点颜色数据渲染模型,不需要再定义color属性
// color: 0xff0000,
vertexColors: THREE.VertexColors, //以顶点颜色为准
size: 10.0, //点对象像素尺寸
});
// 点渲染模式 点模型对象Points
var points = new THREE.Points(geometry, material); //点模型对象
scene.add(points); //点对象添加到场景
var material = new THREE.LineBasicMaterial({
vertexColors: THREE.VertexColors, //以顶点颜色为准
});
// 点渲染模式 点模型对象Points
var line = new THREE.Line(geometry, material);
scene.add(line);
// 辅助坐标系 参数250表示坐标系大小,可以根据场景大小去设置
var axisHelper = new THREE.AxisHelper(250);
scene.add(axisHelper);
法向量
作为区分2d,3d比如同样一个矩形,如果它左边和右边的光反射方向不同,就会被认为是发生了弯折,这是由光的镜面反射影响造成的3d效果。而这种镜面反射的直接反应是通过点的法向量决定的。
即如果上图为一个平面图,所有法向量同方向。这也是区分2d,3d的重要点。
顶点索引复用顶点数据
一个矩形会用到两个三角形,6个点进行绘图,但是其中两个点是重复的,这样可以通过index来对已有的不重复点变化为全部的要用的重复点。
几何体数据
BoxGeometry
、PlaneGeometry
、SphereGeometry
等几何体类的基类是Geometry
,所以访问这些几何体的顶点数据,不知道具体属性名称,可以查问threejs文档GeometryBoxBufferGeometry
、PlaneBufferGeometry
、SphereBufferGeometry
等几何体类的基类是BufferGeometry
,所以访问这些几何体的顶点数据,不知道具体属性名称,可以查问threejs文档BufferGeometry
访问外部模型几何体顶点数据
Threejs加载外部模型的时候,会把几何体解析为缓冲类型几何体BufferGeometry
,所以访问外部模型几何体顶点数据,可以查看文档BufferGeometry。关于外部模型加载的讲解可以查看课程第14章。
几何体旋转、缩放、平移变换
注意
注意网格模型Mesh
进行缩放旋转平移变换和几何体Geometry
可以实现相同的渲染效果,但是网格模型Mesh
进行这些变换不会影响几何体的顶点位置坐标,网格模型缩放旋转平移变换改变的是模型的本地矩阵、世界矩阵。
材质
几何体材质,side属性控制渲染哪一面;transparent控制是否由透明度,配合opacity属性,设置透明度,transprent为false时,opacity设置无效。
点,线模型
要查看模型的三角形渲染形式 可以通过设置wireframe属性为true查看
var geometry = new THREE.BoxGeometry(100, 100, 100);
// 三角形面渲染模式
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff, //三角面颜色
wireframe:true,//网格模型以线条的模式渲染
});
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
// computeLineDistances方法 计算LineDashedMaterial所需的距离数组
scene.add(mesh)
光源对象
- 光照计算算法 计算颜色片
Threejs在渲染的时候网格模型材质的颜色值mesh.material.color
和光源的颜色值light.color
会进行相乘,简单说就是RGB三个分量分别相乘。
平行光漫反射简单数学模型:漫反射光的颜色 = 网格模型材质颜色值 x 光线颜色 x 光线入射角余弦值
漫反射数学模型RGB分量表示:(R2,G2,B2) = (R1,G1,B1) x (R0,G0,B0) x cosθ
R2 = R1 * R0 * cosθ
G2 = G1 * G0 * cosθ
B2 = B1 * B0 * cosθ
举个例子,蓝色几何体在红光照射下会呈现黑色,原因是各个点颜色都正交,算出来必定#000000,即黑色。
投影
Three.js物体投影模拟计算主要设置三部分,一个是设置产生投影的模型对象,一个是设置接收投影效果的模型,最后一个是光源对象本身的设置,光源如何产生投影。
产生投影对象
var geometry = new THREE.BoxGeometry(40, 100, 40);
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff
});
var mesh = new THREE.Mesh(geometry, material);
// mesh.position.set(0,0,0)
scene.add(mesh);
// 设置产生投影的网格模型
mesh.castShadow = true;
接受投影对象
//创建一个平面几何体作为投影面
var planeGeometry = new THREE.PlaneGeometry(300, 200);
var planeMaterial = new THREE.MeshLambertMaterial({
color: 0x999999
});
// 平面网格模型作为投影面
var planeMesh = new THREE.Mesh(planeGeometry, planeMaterial);
scene.add(planeMesh); //网格模型添加到场景中
planeMesh.rotateX(-Math.PI / 2); //旋转网格模型
planeMesh.position.y = -50; //设置网格模型y坐标
// 设置接收阴影的投影面
planeMesh.receiveShadow = true;
光源
// 方向光
var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源位置
directionalLight.position.set(60, 100, 40);
scene.add(directionalLight);
// 设置用于计算阴影的光源对象
directionalLight.castShadow = true;
如何投影
// 设置计算阴影的区域,最好刚好紧密包围在对象周围
// 计算阴影的区域过大:模糊 过小:看不到或显示不完整
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 300;
directionalLight.shadow.camera.left = -50;
directionalLight.shadow.camera.right = 50;
directionalLight.shadow.camera.top = 200;
directionalLight.shadow.camera.bottom = -100;
// 设置mapSize属性可以使阴影更清晰,不那么模糊
// directionalLight.shadow.mapSize.set(1024,1024)
console.log(directionalLight.shadow.camera);
阴影对象基类LightShadow
平行光阴影对象DirectionalLightShadow
和聚光源阴影对象SpotLightShadow
两个类的基类是LightShadow
LightShadow
属性.camera
观察光源的相机对象. 从光的角度来看,以相机对象的观察位置和方向来判断,其他物体背后的物体将处于阴影中。
// 聚光源设置
spotLight.shadow.camera.near = 1;
spotLight.shadow.camera.far = 300;
spotLight.shadow.camera.fov = 20;
层级模型
任何画布概念中,都有层级概念。如画一个机器人,不可能直接完全画出所有组件然后组合在一个对象中,而是分拆为手,脚,头,手又分割为手掌,指头,这样增强了组件的复用性和整体性。即我们很多时候需要去管理的是手这个抽象概念,而非一堆指头,因此层级划分很重要。
add方法创造一个子对象,remove方法移出一个子对象。
对象命名,查找,遍历
见http://www.webgl3d.cn/Three.js/
相对坐标与世界坐标
简而言之,相对坐标为子类与父类的相对位置坐标,世界坐标标识相对于坐标系的坐标位置。比如group相对位置为y=+50,mesh为group的children,相对位置为y=+50,那么mesh的世界坐标为(0, 100, 0)
同样的,除了位置,放缩系数和角度,也有类似机制,使用矩阵进行变换。
var geometry = new THREE.BoxGeometry(20, 20, 20);
var material = new THREE.MeshLambertMaterial({color: 0x0000ff});
var mesh = new THREE.Mesh(geometry, material);
// mesh的本地坐标设置为(50, 0, 0)
mesh.position.set(50, 0, 0);
var group = new THREE.Group();
// group本地坐标设置和mesh一样设置为(50, 0, 0)
// mesh父对象设置position会影响得到mesh的世界坐标
group.position.set(50, 0, 0);
group.add(mesh);
scene.add(group);
// .position属性获得本地坐标
console.log('本地坐标',mesh.position);
// getWorldPosition()方法获得世界坐标
//该语句默认在threejs渲染的过程中执行,如果渲染之前想获得世界矩阵属性、世界位置属性等属性,需要通过代码更新
scene.updateMatrixWorld(true);
var worldPosition = new THREE.Vector3();
mesh.getWorldPosition(worldPosition);
console.log('世界坐标',worldPosition);
纹理图与uv映射
https://www.cnblogs.com/yanan-boke/p/7815018.html
首先,纹理贴图维护uv,即左边的坐标系,根据图片大小,分布为四点(0,0),…,(1,1),而uv映射是指将这样一张2d纹理图映射到Matrial的Faces的三角形上。
除了基本的纹理图,还可以加载法线贴图,阴影贴图,高光贴图等。http://www.webgl3d.cn/Three.js/