专栏目录请点击
简介
- 顶点一般使我们在创建模型的时候使用的,他一般对应buffer类型的几何体,使用
BufferGeometry
创建 点击 - 我们还会用到
BufferAttribute
来设置相应的属性,如顶点位置向量,面片索引,法向量,颜色值,UV坐标以及任何自定义 attribute 点击
构成
顶点是由两个元素组成的
- 顶点的位置
- 顶点的颜色
代码
顶点构成图形
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>第一个three.js文件_WebGL三维场景</title>
<style>
body {
margin: 0;
overflow: hidden;
/* 隐藏body窗口区域滚动条 */
}
</style>
<!--引入three.js三维引擎-->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
<script src="http://www.yanhuangxueyuan.com/threejs/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<script>
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
/**
* 创建网格模型
*/
var geometry = new THREE.BufferGeometry(); //创建一个Buffer类型几何体对象
//类型数组创建顶点数据
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;
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
// 辅助坐标系 参数250表示坐标系大小,可以根据场景大小去设置
var axisHelper = new THREE.AxisHelper(250);
scene.add(axisHelper);
/**
* 光源设置
*/
//点光源
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对象
// 渲染函数
function render() {
renderer.render(scene, camera);//执行渲染操作
}
render();
var controls = new THREE.OrbitControls(camera, renderer.domElement);//创建控件对象
controls.addEventListener('change', render);//监听鼠标、键盘事件
</script>
</body>
</html>
核心代码
var geometry = new THREE.BufferGeometry(); //创建一个Buffer类型几何体对象
//类型数组创建顶点数据
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;
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
顶点的位置与颜色
var geometry = new THREE.BufferGeometry(); //声明一个缓冲几何体对象
//类型数组创建顶点位置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); //点对象添加到场景
// 辅助坐标系 参数250表示坐标系大小,可以根据场景大小去设置
var axisHelper = new THREE.AxisHelper(250);
scene.add(axisHelper);
我们会发现他是一一对应的关系
- 这里的材质的颜色设置,我们使用的是
VertexColors
这个属性,并不是使用的color
属性- 他的默认值是
THREE.NoColor
,也就是说模型的颜色渲染效果取决于材质属性.color
,如果把材质属性VertexColors
的值设置为THREE.VertexColors
,那么他进行渲染的时候就会使用几何体顶点的颜色数据geometry.attributes.color
- 他的默认值是
BufferAttribute
这个属性是为了提供各种各样符合顶点的数据,比如顶点的颜色,顶点的位置数据,提供顶点属性的值,如geometry.attributes.position
颜色差值
当我们把下面代码
//材质对象
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.MeshBasicMaterial({vertexColors: THREE.VertexColors,});
// 点渲染模式 点模型对象Points
var points = new THREE.Mesh(geometry, material); //点模型对象
scene.add(points); //点对象添加到场景
我们会发现他的渲染效果如下
- 他呈现出一种渐变效果,之所以成年初渐变效果,是因为webgl进行渲染的时候会对于颜色数据进行差值计算
- 比如端点1设置为红色,端点2设置为蓝色,那么整个线条会呈现出点1到点2红色到蓝色的渐变
- 对于网格模型Mesh来说,就是餐侥幸的三个顶点分别设置一个颜色,三角形内部的区域像素会根据这三个顶点的颜色进行渲染计算
- 插值计算示意图
法向量
- webgl中为了计算光线与物体表面入射角,首先要计算物体表面每个位置的法线方向
- 在网格模型中,曲面是有一个一个三角形构成,为了表示物体表面各个位置的发现方向,我们可以给几何体的每个顶点定义一个方向向量
不设置法向量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>顶点法向量光照计算</title>
<style>
body {
margin: 0;
overflow: hidden;
/* 隐藏body窗口区域滚动条 */
}
</style>
<!--引入three.js三维引擎-->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
<!-- 引入threejs扩展控件OrbitControls.js -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<script>
/**
* 创建场景对象Scene
*/
var scene = new THREE.Scene();
/**
* 创建网格模型
*/
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 material = new THREE.MeshLambertMaterial({
color: 0x0000ff, //三角面颜色
side: THREE.DoubleSide //两面可见
});
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
// 辅助坐标系
var axisHelper = new THREE.AxisHelper(250);
scene.add(axisHelper);
/**
* 光源设置
*/
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
/**
* 相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
var k = width / height; //窗口宽高比
var s = 150; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
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对象
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
}
render();
//创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性
var controls = new THREE.OrbitControls(camera, renderer.domElement);
//监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
controls.addEventListener('change', render);
</script>
</body>
</html>
上面的代码没有设置法向量,他渲染的图形是下面这个样子的
- 我们可以看到,整个图形就像是没有光照一样,但是当我们加上了下面的代码
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个为一组,表示一个顶点的法向量数据
他的渲染就是下面这个样子的
这样就有了光的散射
- 所以,我们在集合体中,常用的属性如下
// 访问几何体顶点位置数据
BufferGeometry.attributes.position
// 访问几何体顶点颜色数据
BufferGeometry.attributes.color
// 访问几何体顶点法向量数据
BufferGeometry.attributes.normal
顶点索引
使用顶点索引的目的是用来复用顶点数据,什么是复用顶点数据呢,比如,下面这个矩形
- 这个矩形是用两个三角形拼凑而成,如果要定义顶点的话,那么需要定义6个顶点
- 但是我们会发现两个三角形有两个顶点的位置是重合的,而对于这些重合的顶点,我们可以值定义一次
不复用顶点
如果不复用顶点的话,我们需要定义6个顶点
/**
* 创建网格模型
*/
var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
//类型数组创建顶点位置position数据
var vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 0, 0, //顶点4坐标 和顶点1位置相同
80, 80, 0, //顶点5坐标 和顶点3位置相同
0, 80, 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, 0, 1, //顶点4法向量
0, 0, 1, //顶点5法向量
0, 0, 1, //顶点6法向量
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的xyz坐标
渲染如下
复用顶点
我们先定义顶点
var geometry = new THREE.BufferGeometry(); //声明一个空几何体对象
//类型数组创建顶点位置position数据
var vertices = new Float32Array([
0, 0, 0, //顶点1坐标
80, 0, 0, //顶点2坐标
80, 80, 0, //顶点3坐标
0, 80, 0, //顶点4坐标
]);
// 创建属性缓冲区对象
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, 0, 1, //顶点4法向量
]);
// 设置几何体attributes属性的位置normal属性
geometry.attributes.normal = new THREE.BufferAttribute(normals, 3); //3个为一组,表示一个顶点的xyz坐标
然后我们去定义复用的索引
// Uint16Array类型数组创建顶点索引数据
var indexes = new Uint16Array([
// 0对应第1个顶点位置数据、第1个顶点法向量数据
// 1对应第2个顶点位置数据、第2个顶点法向量数据
// 索引值3个为一组,表示一个三角形的3个顶点
0, 1, 2,
0, 2, 3,
])
// 索引数据赋值给几何体的index属性
geometry.index = new THREE.BufferAttribute(indexes, 1); //1个为一组
我们可以看注释,也可以看下面的解释
- 在数组中一个数字代表一个顶点,三个数字代表一个三角形数据
- 0表示第一个顶点数据,1表示第二个顶点的数据,一次类推
- 我们可以看到一个数组中有两个重复的数据即 0和2,也就是说第一个和第三个顶点被复用
- 在创建顶点索引的时候,可以根据顶点的数量选择类型数组
- 对于顶点索引而言要选择整形类的数组,非索引的顶点数据,可以选择浮点类型的数组,如
Float32Array
类型数组 | 位数 | 字节 | 类型描述 | C语言等价类型 |
---|---|---|---|---|
Int8Array | 8 | 1 | 有符号8位整型 | int8_t |
Uint8Array | 8 | 1 | 无符号8位整型 | uint8_t |
Int16Array | 16 | 2 | 有符号16位整型 i | nt16_t |
Uint16Array | 16 | 2 | 无符号16位整型 | int16_t |
Int32Array | 32 | 4 | 有符号32位整型 | int32_t |
Uint32Array | 32 | 4 | 无符号32位整型 | uint32_t |
Float32Array | 32 | 4 | 单精度(32位)浮点数 | float |
Float64Array | 64 | 8 | 双精度(64位)浮点数 | double |