着色器glsl基础
shader中的各种数据类型
RawShaderMaterial 和 ShaderMaterial
shader是什么?
shader是一个用GLSL编写的小程序,也就是着色器语言,我们可以通过shader来编写顶点着色器和片元着色器,在WEBGL编程一书中 25-26页有详细说明。
threejs提供了关于shader的材质 RawShaderMaterial 和 ShaderMaterial 两种编写shader的材质。
RawShaderMaterial:不内置uniforms和attributes
ShaderMaterial:内置一些需要的参数,后期的使用都为此材质
这里的教程使用的教程为ShaderMaterial
?浏览器的渲染图
顶点着色器代码运行在GPU的顶点着色器单元,片元着色器代码运行在片元着色器单元。
欧拉角
欧拉角分为以x、y、z方向做旋转,其中分为外中内三个方向,外面的方向旋转,里面的方向会跟着旋转,但是x、y、z各自方向独立,会造成万向节死锁。
四元数
WebGL和canvas渲染方式
三者的关系是 JavaScript -> WebGL -> OpenGL ->… -> 显卡 并把最终渲染出来图形 呈现到Canvas。
所以,能使用WebGL的前提是浏览器支持WebGL,且显卡支持OpenGL ES2.0才可以。
canvas是一个H5标签,作用是在网页上画图,但是只支持2D,不支持3D。WebGL是一种3D绘图标准,WebGL支持3D,且性能优于canvas。所以现在能用WebGL的都用WebGL,有些项目用canvas是因为部分手机不支持WebGL。
OpenGL是 底层的驱动级的图形接口(是显卡有直接关系的) 类似于 DirectX
但是这种底层的OpenGL是 寄生于浏览器的JavaScript无法涉及的
但是为了让Web拥有更强大的 图形处理能力 2010年时候WebGL被推出来
WebGL允许工程师使用JS去调用部分封装过的 OpenGL ES2.0标准接口去 提供硬件级别的3D图形加速功能。
使用three.js里的各种光源
PointLight 点光源 常用
聚光灯 距离越远,光越弱
DirectionalLight(方向光源) 类似太阳光则不会这样
旋转平移放到
// 几何体xyz三个方向都放大2倍
// geometry.scale(2, 2, 2);
// 几何体沿着x轴平移50
// geometry.translate(50, 0, 0);
// 几何体绕着x轴旋转45度
// geometry.rotateX(Math.PI / 4);
// 居中:偏移的几何体居中
// geometry.center();
-----------
// 网格模型xyz方向分别缩放0.5,1.5,2倍
// mesh.scale.set(0.5, 1.5, 2)
// 直接设置网格模型的位置
// mesh.position.set(100, 100, 100)
// 网格模型沿着x轴方向平移100
// mesh.translateX(100);
//沿着axis轴表示方向平移100
// mesh.translateOnAxis(axis, 100);
// 绕着Y轴旋转90度
// mesh.rotateY(Math.PI / 2);
// 绕axis轴旋转90度
// mesh.rotateOnAxis ( axis, Math.PI / 2 )
// console.log(mesh.rotation);//控制台查看:旋转方法,改变了rotation属性
面法线跟顶点法线的区别
一般情况下,面的法向量和顶点的法向量是相同的。
三角形的顶点计算,面的法向量
假设一个三角形由顶点 po、p1 和 p2 组成,我们需要计算每个顶点 n0、n1 和 n2 的顶点法线。
首先计算位于三角形上的两个向量:
p1 - p0 = a
p2 - p0 = b
求得面法线:
n = a * b (* 是叉乘运算)
// 所以同一个顶点可以有不同的法线
面法线跟顶点法线的区别
three.js(3):点、线、面(颜色插值,几何体三种渲染方式)
face 法向量,颜色两种设置设置
三个点的法向量如何求出面的法向量
Three.js几何体顶点颜色和材质颜色区别
设置模型的几何体顶点颜色时候,
对于Geometry几何体,如果是点Points或线Line模型,可以直接设置几何体对象的.colors属性,
如果是网格模型Mesh,需要通过三角形属性.faces来设置顶点颜色,Face3.color或Face3.vertexColors。
对于BufferGeometry几何体而言,直接设置attributes.color属性就可以,一般加载的外部模型都是BufferGeometry几何体。
--------
// 定点设置颜色的时候不需要关心material的颜色,这里有参数看选择材质渲染还是定点颜色渲染
var material = new THREE.MeshBasicMaterial({
// 使用顶点颜色数据渲染模型,不需要再定义color属性
// color: 0xff0000,
vertexColors: THREE.VertexColors, //以顶点颜色为准
// vertexColors:THREE.FaceColors
});
// Mesh
光照,法向量,Material的颜色
clone 和 copy方法
mesh clone方法 复制所有属性
mesh copy 方法 复制mesh的位置、旋转、矩阵等属性(不包含geometry和material属性)
Vector3 clone方法 返回一个新的对象
Vector3 copy 向量p1三个分量xyz的值覆盖向量p2三个分量
texture
// uv两个方向纹理重复数量
texture.repeat.set(4, 2);
// 不设置重复 偏移范围-1~1
texture.offset = new THREE.Vector2(0.3, 0.1)
// 设置纹理旋转角度
texture.rotation = Math.PI/4;
// 设置纹理的旋转中心,默认(0,0)
texture.center.set(0.5,0.5);
geometry和buffergeometry有啥区别
和geometry一样,BufferGeometry存储顶点、面索引、法线、颜色、纹理坐标和自定义的一些几何体数据
BufferGeometry更高效的秘密:将数据放在一块连续的内存空间中
连续的存储空间能够节省传递数据到cpu的时间(把数据放到显卡GPU中的时间)
一 旋转动画,requestAnimationFrame周期性渲染
// 渲染函数
function render() {
renderer.render(scene,camera);//执行渲染操作
mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
requestAnimationFrame(render);//请求再次执行渲染函数render,渲染下一帧
}
render();
旋转缩放
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
}
render();
//创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性
var controls = new THREE.OrbitControls(camera);
//监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
controls.addEventListener('change', render);
多个几何体
/**
* 创建网格模型
*/
//长方体 参数:长,宽,高
// var geometry = new THREE.BoxGeometry(100, 100, 100);
// 球体 参数:半径60 经纬度细分数40,40
// var geometry = new THREE.SphereGeometry(60, 40, 40);
// 圆柱 参数:圆柱面顶部、底部直径50,50 高度100 圆周分段数
// var geometry = new THREE.CylinderGeometry( 50, 50, 100, 25 );
// 正八面体
// var geometry = new THREE.OctahedronGeometry(50);
// 正十二面体
// var geometry = new THREE.DodecahedronGeometry(50);
// 正二十面体
var geometry = new THREE.IcosahedronGeometry(50);
多个几何体的偏移
mesh2.translateY(120); //球体网格模型沿Y轴正方向平移120
// mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
mesh3.position.set(120,0,0);//设置mesh3模型对象的xyz坐标为120,0,0
辅助坐标系
var axisHelper = new THREE.AxisHelper(250);
scene.add(axisHelper);
不同材质
//基础网格材质对象 不受光照影响 没有棱角感
// var material = new THREE.MeshBasicMaterial({
// color: 0x0000ff,
// wireframe:true,//线条模式渲染
// });
// 与光照计算 漫反射 产生棱角感
// var material = new THREE.MeshLambertMaterial({
// color: 0x00ff00,
// });
// 与光照计算 高光效果(镜面反射) 产生棱角感
var material = new THREE.MeshPhongMaterial({
color: 0xff0000,
specular:0x444444, // 高光部分的颜色
shininess:30, // 高光部分的亮度,默认30
emissive: 30 // 这是该材质的发射的颜色。它其实并不像一个光源,只是一种纯粹的、不受其它光照影响的颜色。默认值为黑色
wireframe:true
});
半透明
var material1 = new THREE.MeshLambertMaterial({
color: 0x0000ff,//材质颜色
transparent:true,//开启透明度
opacity:0.5,//设置透明度具体值
}); //材质对象Material
点光源与位置设置
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
// 点光源2 位置和point关于原点对称
var point2 = new THREE.PointLight(0xffffff);
point2.position.set(-400, -200, -300); //点光源位置
scene.add(point2); //点光源添加到场景中
//环境光 环境光颜色与网格模型的颜色进行RGB进行乘法运算
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
二 顶点概念,集合体
顶点位置,几何体
//类型数组创建顶点数据
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属性的位置属性
geometry.attributes.position = attribue;
顶点颜色数据差值计算
//类型数组创建顶点位置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 vertices = new Float32Array([
0, 0, 0, //顶点1坐标
100, 100, 100, //顶点2坐标
]);
var colors = new Float32Array([
1, 0, 0, //顶点1颜色
0, 0, 1, //顶点2颜色
]);
//材质对象
var material = new THREE.LineBasicMaterial({
// 使用顶点颜色数据渲染模型,不需要再定义color属性
// color: 0xff0000,
vertexColors: THREE.VertexColors, //以顶点颜色为准
});
//类型数组创建顶点位置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.MeshBasicMaterial({
// 使用顶点颜色数据渲染模型,不需要再定义color属性
// color: 0xff0000,
vertexColors: THREE.VertexColors, //以顶点颜色为准
});
顶点法向量光照计算
var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
//类型数组创建顶点位置position数据
var vertices = new Float32Array([
0, 0, 0, //顶点1坐标
50, 0, 0, //顶点2坐标
0, 100, 0, //顶点3坐标
0, 0, 0, //顶点4坐标
0, 0, 100, //顶点5坐标
50, 0, 0, //顶点6坐标
]);
// 创建属性缓冲区对象
var attribue = new THREE.BufferAttribute(vertices, 3); //3个为一组
// 设置几何体attributes属性的位置position属性
geometry.attributes.position = attribue
var normals = new Float32Array([
0, 0, 1, //顶点1法向量
0, 0, 1, //顶点2法向量
0, 0, 1, //顶点3法向量
0, 1, 0, //顶点4法向量
0, 1, 0, //顶点5法向量
0, 1, 0, //顶点6法向量
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的法向量数据
//材质对象
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff, //三角面颜色
side: THREE.DoubleSide //两面可见
});
设置顶点位置和颜色
// Vector3向量对象表示顶点位置数据
var p1 = new THREE.Vector3(50, 0, 0); //顶点1坐标
var p2 = new THREE.Vector3(0, 70, 0); //顶点2坐标
var p3 = new THREE.Vector3(80, 70, 0); //顶点3坐标
//顶点坐标添加到geometry对象
geometry.vertices.push(p1, p2, p3);
// Color对象表示顶点颜色数据
var color1 = new THREE.Color(0x00ff00); //顶点1颜色——绿色
var color2 = new THREE.Color(0xff0000); //顶点2颜色——红色
var color3 = new THREE.Color(0x0000ff); //顶点3颜色——蓝色
//顶点颜色数据添加到geometry对象
geometry.colors.push(color1, color2, color3);
Face3对象定义Geometry的三角面
var geometry = new THREE.Geometry(); //声明一个几何体对象Geometry
var p1 = new THREE.Vector3(0, 0, 0); //顶点1坐标
var p2 = new THREE.Vector3(0, 100, 0); //顶点2坐标
var p3 = new THREE.Vector3(50, 0, 0); //顶点3坐标
var p4 = new THREE.Vector3(0, 0, 100); //顶点4坐标
//顶点坐标添加到geometry对象
geometry.vertices.push(p1, p2, p3, p4);
// Color对象表示顶点颜色数据
var color1 = new THREE.Color(0x00ff00); //顶点1颜色——绿色
var color2 = new THREE.Color(0xff0000); //顶点2颜色——红色
var color3 = new THREE.Color(0x0000ff); //顶点3颜色——蓝色
var color4 = new THREE.Color(0xffff00); //顶点3颜色——黄色
//顶点颜色数据添加到geometry对象
geometry.colors.push(color1, color2, color3, color4);
// Face3构造函数创建一个三角面
var face1 = new THREE.Face3(0, 1, 2);
//设置三角面face1每个顶点的法向量
var n1 = new THREE.Vector3(0, 0, -1);
var n2 = new THREE.Vector3(0, 0, -1);
var n3 = new THREE.Vector3(0, 0, -1);
// 设置三角面Face3三个顶点的法向量
face1.vertexNormals.push(n1, n2, n3);
// 设置三角面face1三个顶点的颜色
// face1.vertexColors = [
// new THREE.Color(0xffff00),
// new THREE.Color(0xff00ff),
// new THREE.Color(0x00ffff),
// ]
// 三角面2
var face2 = new THREE.Face3(0, 2, 3);
// 设置三角面法向量
face2.normal = new THREE.Vector3(0, -1, 0);
// face2.color = new THREE.Color(0x00ff00);
//三角面face1、face2添加到几何体中
geometry.faces.push(face1, face2);
//材质对象
var material = new THREE.MeshLambertMaterial({
// color: 0xffff00,
vertexColors: THREE.VertexColors, //以顶点颜色为准
// vertexColors: THREE.FaceColors,
side: THREE.DoubleSide, //两面可见
});
设置立方体的颜色
var geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry
// 遍历几何体的face属性
geometry.faces.forEach(face => {
// 设置三角面face三个顶点的颜色
face.vertexColors = [
new THREE.Color(0xffff00),
new THREE.Color(0xff00ff),
new THREE.Color(0x00ffff),
]
});
旋转平移变换
// 几何体xyz三个方向都放大2倍
// geometry.scale(2, 2, 2);
// 几何体沿着x轴平移50
// geometry.translate(50, 0, 0);
// 几何体绕着x轴旋转45度
// geometry.rotateX(Math.PI / 4);
// 居中:偏移的几何体居中
// geometry.center();
材质对象
点>网格> 线
/**
* 创建网格模型
*/
var geometry = new THREE.BoxGeometry(100, 100, 100);//立方体几何体
// var geometry = new THREE.SphereGeometry(100, 25, 25);//立方体几何体
// 直线基础材质对象
// var material = new THREE.LineBasicMaterial({
// color: 0x0000ff
// });
// 虚线材质对象:产生虚线效果
var material = new THREE.LineDashedMaterial({
color: 0x0000ff,
dashSize: 10,//显示线段的大小。默认为3。
gapSize: 5,//间隙的大小。默认为1
});
var line = new THREE.Line(geometry, material); //线模型对象
材质常用属性
var material = new THREE.MeshPhongMaterial({
color: 0xdd00ff,
// wireframe:true,//将几何图形渲染为线框
// transparent:true,//开启透明
// opacity:0.5,//透明度0.5
// 前面FrontSide 背面:BackSide 双面:DoubleSide
// side:THREE.DoubleSide,
}); //材质对象Material
网格类型的平移和缩放
// 网格模型xyz方向分别缩放0.5,1.5,2倍
// mesh.scale.set(0.5, 1.5, 2)
// 直接设置网格模型的位置
// mesh.position.set(100, 100, 100)
// 网格模型沿着x轴方向平移100
// mesh.translateX(100);
//向量Vector3对象表示方向
// var axis = new THREE.Vector3(1, 1, 1);
// axis.normalize(); //向量归一化
//沿着axis轴表示方向平移100
// mesh.translateOnAxis(axis, 100);
// 绕着Y轴旋转90度
// mesh.rotateY(Math.PI / 2);
// 绕axis轴旋转90度
// mesh.rotateOnAxis ( axis, Math.PI / 2 )
// console.log(mesh.rotation);//控制台查看:旋转方法,改变了rotation属性
模型对象的克隆复制
// var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
// for (let i = 0; i < 10; i++) {
// // 执行clone方法克隆mesh,注意不能var newMesh = mesh;
// var newMesh = mesh.clone();
// newMesh.translateX(i * 25);
// scene.add(newMesh)
// }
var newMesh = new THREE.Mesh(geometry2, material2);
// 复制mesh的位置、旋转、矩阵等属性(不包含geometry和material属性)
newMesh.copy(mesh);
//相比mesh而言,在平移
newMesh.translateX(-50);
scene.add(newMesh)
层级模型树结构
var group1 = new THREE.Group();
-------
// 头部网格模型和组
var headMesh = sphereMesh(10, 0, 0, 0);
headMesh.name = "脑壳"
var leftEyeMesh = sphereMesh(1, 8, 5, 4);
leftEyeMesh.name = "左眼"
var rightEyeMesh = sphereMesh(1, 8, 5, -4);
rightEyeMesh.name = "右眼"
var headGroup = new THREE.Group();
headGroup.name = "头部"
headGroup.add(headMesh, leftEyeMesh, rightEyeMesh);
// 身体网格模型和组
var neckMesh = cylinderMesh(3, 10, 0, -15, 0);
neckMesh.name = "脖子"
var bodyMesh = cylinderMesh(14, 30, 0, -35, 0);
bodyMesh.name = "腹部"
var leftLegMesh = cylinderMesh(4, 60, 0, -80, -7);
leftLegMesh.name = "左腿"
var rightLegMesh = cylinderMesh(4, 60, 0, -80, 7);
rightLegMesh.name = "右腿"
var legGroup = new THREE.Group();
legGroup.name = "腿"
legGroup.add(leftLegMesh, rightLegMesh);
var bodyGroup = new THREE.Group();
bodyGroup.name = "身体"
bodyGroup.add(neckMesh, bodyMesh, legGroup);
// 人Group
var personGroup = new THREE.Group();
personGroup.name = "人"
personGroup.add(headGroup, bodyGroup)
personGroup.translateY(50)
scene.add(personGroup);
// 遍历场景对象scene obj:每次遍历的对象
scene.traverse(function(obj) {
// if (obj.type === "Group") {
// console.log(obj.name);
// }
// if (obj.type === "Mesh") {
// console.log(' ' + obj.name);
// obj.material.color.set(0xffff00);
// }
// if (obj.name === "左眼" | obj.name === "右眼") {
// obj.material.color.set(0x000000)
// }
// 打印id属性
// console.log(obj.id);
// 打印该对象的父对象
// console.log(obj.parent);
// 打印该对象的子对象
// console.log(obj.children);
})
// 打印场景id号 id号和创建对象的顺序有关
// console.log(scene.id);
// console.log(headMesh.id);
// console.log(leftEyeMesh.id);
// console.log(rightEyeMesh.id);
// 遍历查找对象的子对象,返回name对应的对象(name是可以重名的,返回第一个)
// var nameNode = scene.getObjectByName ( "左腿" );
// nameNode.material.color.set(0xff0000);
// 遍历查找对象的子对象,并返回id对应的对象
// var idNode = scene.getObjectById ( 4 );
// console.log(idNode);
本地坐标与世界坐标
var worldPosition = new THREE.Vector3();
mesh.getWorldPosition(worldPosition)
console.log('世界坐标',worldPosition);
console.log('本地坐标',mesh.position);
三维世界最必要的三(四)个元素?
scene 场景,camera 成像,renderer 渲染器,物体
编写程序,设置场景的天空盒子(textureCube即可)
var name = [xpos.jpg, xneg.jpg, ypos.jpg, yneg.jpg, zpos.jpg, zneg.jpg]
var path = "***/texture/skybox/"
var textureCube = new THREE.CubeTextureLoader()
.setPath(path)
.load(name)
scene.background = textureCube
常用的相机及其特征和区别?
透视相机(近大远小,视锥)
正交相机(距离不会影响结果,适合绘制二维图形)
决定透视相机成像范围的参数,改变far的距离,看到的图像是否会变大(或者变小)
fov 视景体竖直方向上的张角
aspect 宽度/高度
near 近面
far 远面
Note: 改变far不会改变图像大小
程序】画一个在原点,半径为radius的球,设定相机为透视相机,视角为fov,canvas宽高分别为width和height,编写程序设定Camera的位置,使得球刚好撑满canvas的高度和宽度中最小的那个
var newRadius = width >= height ? radius : radius / width * height
var halfFovRadian = fov / 180 * Math.PI / 2
var distance = newRadius / Math.tan(halfFovRadian)
camera.position.z = distance
现有场景如程序,在不移动相机及球的位置的前提下,如何使得相机看到更多球上的纹理。
答案:改变fov的角度更大
######材质及光源
* 光源及其特征
* 环境光 影响整个场景,颜色平均,没有衰减
* 点光源 朝向四面八方,亮度线性递减
* 聚光灯 锥形,产生阴影
* 平行光 只有方向,亮度与位置无关,产生阴影
材质及其特征
* 基本材质 不会与光照发生反应
* Lambert材质 只考虑漫反射,不考虑镜面反射,磨砂质地,可以产生阴影,需要光照
* Phong材质 考虑了漫反射和镜面反射,金属质地,有高光,需要光照
* Shader材质 着色器材质,与全局光照等无关
如何产生阴影
渲染器的shadowMapEnabled属性设为true
* 光源和产生反射的物体的castShadow属性设为true
* 接收阴影的物体receiveShadow属性设为true
如何设置材质为透明
transparent属性设置为true
* opacity设置为0至1
材质的depthTest和depthWrite属性分别是什么意思?
depthTest表示是否开启深度检测,如果为否,则表示在渲染过程中,远处的点不会被近处遮挡
* depthWrite表示是否允许向深度缓冲区写入数据,如果为否,该物体的深度信息不会影响其他物体的渲染
几何物体都有哪些类型
网格
* 粒子
* 线
* 骨骼等
如何利用现有几何体生成粒子系统
三维世界的考点
1. 三维世界最必要的三(四)个元素
scene 场景,camera 成像,renderer 渲染器,物体
2.编写程序,设置场景的天空盒子(textureCube即可)
var name = [xpos.jpg, xneg.jpg, ypos.jpg, yneg.jpg, zpos.jpg, zneg.jpg]
var path = "***/texture/skybox/"
var textureCube = new THREE.CubeTextureLoader()
.setPath(path)
.load(name)
scene.background = textureCube
2. 常用的相机及其特征和区别
透视相机(近大远小,视锥)
正交相机(距离不会影响结果,适合绘制二维图形)
决定透视相机成像范围的参数,改变far的距离,看到的图像是否会变大(或者变小)
fov 视景体竖直方向上的张角
aspect 宽度/高度
near 近面
far 远面
Note: 改变far不会改变图像大小
3. 【程序】画一个在原点,半径为radius的球,设定相机为透视相机,视角为fov,canvas宽高分别为width和height,编写程序设定Camera的位置,使得球刚好撑满canvas的高度和宽度中最小的那个。
var newRadius = width >= height ? radius : radius / width * height
var halfFovRadian = fov / 180 * Math.PI / 2
var distance = newRadius / Math.tan(halfFovRadian)
camera.position.z = distance
4. 现有场景如程序,在不移动相机及球的位置的前提下,如何使得相机看到更多球上的纹理。
答案:改变fov的角度更大
5. 材质及光源
* 光源及其特征
* 环境光 影响整个场景,颜色平均,没有衰减
* 点光源 朝向四面八方,亮度线性递减
* 聚光灯 锥形,产生阴影
* 平行光 只有方向,亮度与位置无关,产生阴影
* 材质及其特征
* 基本材质 不会与光照发生反应
* Lambert材质 只考虑漫反射,不考虑镜面反射,磨砂质地,可以产生阴影,需要光照
* Phong材质 考虑了漫反射和镜面反射,金属质地,有高光,需要光照
* Shader材质 着色器材质,与全局光照等无关
6. 如何产生阴影
* 渲染器的shadowMapEnabled属性设为true
* 光源和产生反射的物体的castShadow属性设为true
* 接收阴影的物体receiveShadow属性设为true
7. 如何设置材质为透明
* transparent属性设置为true
* opacity设置为0至1
8. 材质的depthTest和depthWrite属性分别是什么意思
* depthTest表示是否开启深度检测,如果为否,则表示在渲染过程中,远处的点不会被近处遮挡
* depthWrite表示是否允许向深度缓冲区写入数据,如果为否,该物体的深度信息不会影响其他物体的渲染
9. 几何形状相关,几何物体都有哪些类型
* 网格
* 粒子
* 线
* 骨骼等
10. 如何利用现有几何体生成粒子系统
粒子系统取的是geometry中的顶点信息,与面无关,所以任意一种geometry,都可以使用粒子系统绘制出来。
11. 网格几何体的构成
* 几何形状,决定了物体的顶点位置
* 顶点
* 线段
* 三角形面
* 材质,决定了物体的颜色和纹理
12. 如何用原始Geometry绘制一个长宽高分别为2,中心在原点的立方体
var geometry = new THREE.Geometry();
// step1 生成点
geometry.vertices = [
new THREE.Vector3(1, 1, 1),
new THREE.Vector3(1, 1, -1),
new THREE.Vector3(1, -1, 1),
new THREE.Vector3(1, -1, -1),
new THREE.Vector3(-1, 1, -1),
new THREE.Vector3(-1, 1, 1),
new THREE.Vector3(-1, -1, -1),
new THREE.Vector3(-1, -1, 1)
]
// step2 生成面
geometry.faces = [
// 右面
new THREE.Face3(0, 2, 1),
new THREE.Face3(2, 3, 1),
// 左面
new THREE.Face3(4, 6, 5),
new THREE.Face3(6, 7, 5),
// 上面
new THREE.Face3(4, 5, 1),
new THREE.Face3(5, 0, 1),
// 下面
new THREE.Face3(7, 6, 2),
new THREE.Face3(6, 3, 2),
// 正面
new THREE.Face3(5, 7, 0),
new THREE.Face3(7, 2, 0),
// 后面
new THREE.Face3(1, 3, 4),
new THREE.Face3(3, 6, 4),
]
// step3 计算面法线和点法线
geometry.computeFaceNormals()
geometry.computeVertexNormals()
13.如何用Shape绘制多边形几何体
// step1 拥有多边形路径,路径也可以在有了shape之后,动态调用moveTo等函数生成
var path = coordinates.map((cd) => new THREE.Vector2(...cd))
// step2 生成shape二维平面
var shape = new THREE.Shape(path)
// step3 生成 geometry
var geometry = new THREE.ShapeGeometry(shape)
######如何使用Tube绘制路径
// step1 生成路径
var path = coordinates.map((cd) => new THREE.Vector2(...cd))
// step2 生成curve
var curve = new THREE.SplineCurve3(points)
// step3 最终TubeGeometry 接收的是一个curve函数
var geometry = new THREE.TubeGeometry(curve, segments, radius, radiusSegments, closed)
14. UV映射相关
* 纹理映射关系
* UV坐标
15. 坐标相关
* 如何实现动画
* 通过requestAnimationFrame不断渲染renderer中的场景,改变物体位置、形状等熟悉。
16. 动画相关
17. 【程序】一个物体围绕点(0, 0, 0),做与xy平面平行的旋转运动,其中旋转半径为R
function render () {
animate()
requestAnimationFrame(render)
}
function animate () {
var t = +new Date ()
var x = R * Math.cos(t)
var y = R * Math.sin(t)
mesh.position.x = x
mesh.position.y = y
}
三维世界的进阶考点
1. 渲染管线
* CPU - GPU - 顶点着色器 - 图元装配 - 光栅化插值- 片段着色器 - 像素运算 - 帧缓存,其中顶点着色器和片段着色器为可编程部分。
* 顶点着色器 顶点变换和顶点相关数据处理
* 图元装配 根据顶点序列的几何图元分类装配成几何图元即:线、点、三角形,并根据CVV裁剪,和多边形剔除。
* 光栅化 将顶点和图元插值对应到像素
* 片段着色器 给像素赋予颜色
* 像素运算 深度测试 遮挡面消除 混色蒙版(着色)
2 仿射变换的矩阵们
* 世界坐标 = 模型矩阵 * 物体坐标
* 相机坐标 = 视图矩阵 * 世界坐标
* 投影坐标 = 投影矩阵 * 相机坐标
* 屏幕坐标 = 屏幕映射 * 投影坐标
注意: 视图模型矩阵由平移、旋转、缩放组成
2. 齐次坐标,为什么用齐次坐标,如何区分点和向量
* 平移需要加一维实现
* 可以区分点和向量,即(wx, wy, wz, w),当w 为0的时候,表示是向量
* 着色器的两个阶段输出是什么,循环次数根据什么决定
* 顶点着色器根据顶点数量循环,输出是顶点坐标及大小,以及varying类型变量
* 片段着色器根据插值后的像素值进行循环,输出是像素颜色值
3. 着色器输入的三种类型数据
* uniform 统一变量,两个着色器都可以使用
* attributes 跟顶点绑定,根据顶点做循环,只能在顶点着色器中使用
* varying 在顶点着色器中输出,在片段着色器中输入,输入的为插值结果
* 三维对象拾取的原理
* 纹理地形的原理
* 在着色器中读取颜色值,根据颜色明亮决定高度值
* 环境贴图
* 渲染管线中多边形裁剪的时机
* 全部变换到CVV的之后,进行图元裁剪,因为此时CVV是一个矩形,方便做判断
* 数学和图形学
* 如何求面的法向
根据顶点连线的叉乘
* 如何求顶点的法向
* 深度检测
* 局部理想光照反射模型
Lambert模型
Phong模型
* 四元数和欧拉角
* 欧拉角分为以x、y、z方向做旋转,其中分为外中内三个方向,外面的方向旋转,里面的方向会跟着旋转,但是x、y、z各自方向独立,会造成万向节死锁。
* 四元数是表示点P以向量为轴,旋转θ角得到的坐标。
郭老师的threejs 1、three.js快速入门
/**
* 创建场景对象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);
三种材质的区别和联系
不同光源的意义和点光源的位置影响
相机
透视投影:使用透视投影照相机获得的结果是类似人眼在真实世界中看到的有“近大远小”的效果
正交投影:使用正交投影照相机获得的结果就像我们在数学几何学课上老师教我们画的效果,对于在三维空间内平行的线,投影到二维空间中也一定是平行的
一般说来,对于制图、建模软件通常使用正交投影,这样不会因为投影而改变物体比例;
对于其他大多数应用,通常使用透视投影,因为这更接近人眼的观察效果;