Three.js笔记
一 * 基本使用
首先引入three.js
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
1.创建场景对象
var scene = new THREE.Scene();
2.创建网格模型和模型材质(颜色,高光…)
var geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry
var sphereMaterial=new THREE.MeshPhongMaterial({
color:0x0000ff,
});//设置模型材质对象Material
3.根据网格模型和材质生成模型对象
var mesh = new THREE.Mesh(geometry, sphereMaterial); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
4.设置环境光和点光源(只设置环境光会导致模型没有棱角分明的效果)
//点光源
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
5.设置相机(观察模型的位置,类似照相机)
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); //设置相机方向(指向的场景对象)
6.创建渲染器对象(把模型渲染到页面上)
var renderer = new THREE.WebGLRenderer();
renderer.setSize(width, height);//设置渲染区域尺寸
renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
document.body.appendChild(renderer.domElement); //body元素中插入canvas对象
//执行渲染操作 指定场景、相机作为参数
renderer.render(scene, camera);
通过鼠标操作模型
- 首先引入js文件
<script src="http://www.yanhuangxueyuan.com/threejs/examples/js/controls/OrbitControls.js"></script>
- 把渲染操作封装成一个函数
function render() {
renderer.render(scene, camera);
}
- 配置控件(配置完之后就可以通过鼠标和键盘操作模型进行观察)
var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象
controls.addEventListener('change', render);//监听鼠标、键盘事件
添加多个模型
- 通过创建函数创建多个模型(网格模型和模型材质),之后添加到模型对象mesh中(不要忘记设置模型在页面上显示的位置),最后添加到scene对象上
// 球体网格模型
var geometry2 = new THREE.SphereGeometry(60, 40, 40);
var material2 = new THREE.MeshLambertMaterial({
color: 0xff00ff
});
var mesh2 = new THREE.Mesh(geometry2, material2); //网格模型对象Mesh
mesh2.translateY(120); //球体网格模型沿Y轴正方向平移120
scene.add(mesh2);
// 圆柱网格模型
var geometry3 = new THREE.CylinderGeometry(50, 50, 100, 25);
var material3 = new THREE.MeshLambertMaterial({
color: 0xffff00
});
var mesh3 = new THREE.Mesh(geometry3, material3); //网格模型对象Mesh
// mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
mesh3.position.set(120,0,0);//设置mesh3模型对象的xyz坐标为120,0,0
scene.add(mesh3);
创建坐标系
为了更好的观察模型的位置,可以在页面上添加坐标系
// 辅助坐标系 参数250表示坐标系大小,可以根据场景大小去设置
var axisHelper = new THREE.AxisHelper(250);
scene.add(axisHelper);
模型材质效果和光照效果设置
二 * 顶点位置,几何体结构
1)顶点位置
1.每个模型都是通过顶点创建的(比如正方体有8个顶点),几何体本质上就是three.js生成顶点的算法,通过顶点可以自定义几何体模型。
和上面一样,也是创建模型和材质(不同的是需要添加缓冲区对象,设置坐标几个为一组),之后生成模型对象在添加到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;
// 三角面(网格)渲染模式
var material = new THREE.MeshBasicMaterial({
color: 0x0000ff, //三角面颜色
side: THREE.DoubleSide //两面可见
//side: THREE.FrontSide//前面可见(隐藏正方体后面的面)
//side: THREE.BackSide //后面可见(隐藏正房子前面的两个面)
//wireframe:true, //网格模型以线条的模式渲染,把三角形用线条的形式展示
}); //材质对象
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
通过模型的透明度属性.opacity可以设置材质的透明程度,.opacity属性值的范围是0.0~1.0,0.0值表示完全透明, 1.0表示完全不透明,.opacity默认值1.0。
当设置.opacity属性值的时候,需要设置材质属性transparent值为true
var material = new THREE.MeshPhongMaterial({
color: 0x220000,
// transparent设置为true,开启透明,否则opacity不起作用
transparent: true,
// 设置材质透明度
opacity: 0.4,
});
2.除了网格渲染模式外,还有点渲染模式和线渲染模式
2.1 点渲染模式把每个点都渲染成一个方形区域
// 点渲染模式
var material = new THREE.PointsMaterial({
color: 0xff0000,
size: 10.0 //方形区域大小
}); //材质对象
var points = new THREE.Points(geometry, material); //点模型对象
scene.add(points); //点对象添加到场景中
2.2 线渲染模式把每个点按顺序连接形成线状
// 线条渲染模式
var material=new THREE.LineBasicMaterial({
color:0xff0000 //线条颜色
});//材质对象
var line=new THREE.Line(geometry,material);//线条模型对象
scene.add(line);//线条对象添加到场景中
2)顶点颜色
和顶点位置一样,也是模型geometry的属性
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
//材质对象
上面设置模型材质是通过color属性设置模型颜色,但是添加了顶点颜色后,而是设置了材质属性.vertexColors
var material = new THREE.PointsMaterial({
// 使用顶点颜色数据渲染模型,不需要再定义color属性
// color: 0xff0000,
vertexColors: THREE.VertexColors, //以顶点颜色为准
size: 10.0 //点对象像素尺寸
});
vertexColors属性的默认值是THREE.NoColors,这也就是说模型的颜色渲染效果取决于材质属性.color,如果把材质属性.vertexColors的值设置为THREE.VertexColors,渲染模型的时候就会使用几何体的顶点颜色数据geometry.attributes.color。
3)顶点法向量
通过顶点法创建的几何体模型必须设置顶点法向量,否则点光源或者平行光源等带有方向的光源没有效果(模型没有棱角感)
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
4)Geometry 和Vector3
Geometry是设置顶点和颜色和法向量的另一种方法,比缓冲类型BufferGeometry更方便,通过THREE.Geometry()声明一个空白模型,通过THREE.Vector3设置坐标和法向量,通过THREE.Color设置顶点颜色
var geometry = new THREE.Geometry(); //声明一个几何体对象Geometry
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);
注意设置几何体Geometry顶点颜色属性geometry.colors,对网格模型Mesh是无效的,对于点模型Points、线模型Line是有效果。
三 * 模型旋转、缩放、平移变换
沿x轴方向缩放2倍
mesh.scale.x = 2.0;
沿x轴缩放0.5倍,y轴缩放1.5倍,z轴缩放2倍
mesh.scale.set(0.5, 1.5, 2)
设置y轴的位置为80
mesh.position.y = 80;
设置x,y,z轴位置为80,2,10
mesh.position.set(80,2,10);
沿x轴平移100距离
mesh.translateX(100);
可以自定义移动,旋转的轴
//向量Vector3对象表示方向
var axis = new THREE.Vector3(1, 1, 1);
axis.normalize(); //向量归一化
//沿着axis轴表示方向平移100
mesh.translateOnAxis(axis, 100);
//执行.translateX()、.translateY()、.translateOnAxis()等方法本质上改变的都是模型的位置属性.position。
mesh.rotateX(Math.PI/4);
var axis = new THREE.Vector3(0,1,0);//向量axis
mesh.rotateOnAxis(axis,Math.PI/8);//绕axis轴旋转π/8
四 * 常用材质
用什么模型材质,生成模型对象时就用什么材质。例如点模型材质 => 点模型对象
var geometry = new THREE.SphereGeometry(100, 25, 25); //创建一个球体几何对象
// 创建一个点材质对象
var material = new THREE.PointsMaterial({
color: 0x0000ff, //颜色
size: 3, //点渲染尺寸
});
//点模型对象 参数:几何体 点材质
var point = new THREE.Points(geometry, material);
scene.add(point); //网格模型添加到场景中
五 * 模型复制和克隆
var box=new THREE.BoxGeometry(10,10,10);//创建一个立方体几何对象
var material=new THREE.MeshLambertMaterial({color:0x0000ff});//材质对象
var mesh=new THREE.Mesh(box,material);//网格模型对象
var mesh2 = mesh.clone();//克隆网格模型
mesh.translateX(20);//网格模型mesh平移
scene.add(mesh,mesh2);//网格模型添加到场景中
注意当操作box模型的时候,克隆的模型对象也会跟着变化
box.scale(1.5,1.5,1.5);//几何体缩放
六 * 光源对象
1. 点光源
不再赘述
2.平行光源
点光源因为是向四周发散,所以设置好位置属性.position就可以确定光线和物体表面的夹角,对于平行光而言,主要是确定光线的方向,光线方向设定好了,光线的与物体表面入射角就确定了,仅仅设置光线位置是不起作用的。
所以Threejs平行光提供了位置.position和目标.target两个属性来一起确定平行光方向。目标.target的属性值可以是Threejs场景中任何一个三维模型对象,比如一个网格模型Mesh,这样Threejs计算平行光照射方向的时候,会通过自身位置属性.position和.target表示的物体的位置属性.position计算出来。
// 平行光
var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向:通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(80, 100, 50);
// 方向光指向对象网格模型mesh2,可以不设置,默认的位置是0,0,0
directionalLight.target = mesh2;
scene.add(directionalLight);
2.聚光源
聚光源可以认为是一个沿着特定方会逐渐发散的光源,照射范围在三维空间中构成一个圆锥体。通过属性.angle可以设置聚光源发散角度,聚光源照射方向设置和平行光光源一样是通过位置.position和目标.target两个属性来实现。
// 聚光光源
var spotLight = new THREE.SpotLight(0xffffff);
// 设置聚光光源位置
spotLight.position.set(200, 200, 200);
// 聚光灯光源指向网格模型mesh2
spotLight.target = mesh2;
// 设置聚光光源发散角度
spotLight.angle = Math.PI / 6
scene.add(spotLight);//光对象添加到scene场景中
七 * 层级模型
1.组对象Group
//创建两个网格模型mesh1、mesh2
var geometry = new THREE.BoxGeometry(20, 20, 20);
var material = new THREE.MeshLambertMaterial({color: 0x0000ff});
var group = new THREE.Group();
var mesh1 = new THREE.Mesh(geometry, material);
var mesh2 = new THREE.Mesh(geometry, material);
mesh2.translateX(25);
//把mesh1型插入到组group中,mesh1作为group的子对象
group.add(mesh1);
//把mesh2型插入到组group中,mesh2作为group的子对象
group.add(mesh2);
//把group插入到场景中作为场景子对象
scene.add(group);
网格模型mesh1、mesh2作为设置为父对象group的子对象,如果父对象group进行旋转、缩放、平移变换,子对象同样跟着变换
group对象和scene对象都有remove(方法,可以移除添加过的的对象,比如光源对象和模型对象)
scene.remove(light,group)
2.本地坐标和世界坐标
本地坐标就是模型设置的position属性的值,通过mesh.position获取
世界坐标系默认就是对Threejs整个场景Scene建立一个坐标系,一个模型相对世界坐标系的坐标值就是该模型对象所有父对象以及模型本身位置属性.position的叠加(例如下面的mesh的世界坐标为本身的position坐标加上父对象group的position坐标),先创建一个三维向量用来保存世界坐标,之后通过getWorldPosition()获取
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);
八 * 模型文件加载
创建好的模型对象的信息可以导出,比如geometry模型对象的顶点信息,material的模型材质信息,scene场景信息,Light光源信息,可以把这些信息整合到一个JSON文件中,然后通过数据加载器导入,之后在页面上展示。
1. 导出模型信息
1.导出几何体信息
var geometry = new THREE.BoxGeometry(100, 100, 100);
// 控制台查看立方体数据
console.log(geometry);
// 把数据转换成JSON字符转
console.log(JSON.stringify(geometry));
2.导出材质信息
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff,
}); //材质对象Material
console.log(material);
console.log(material.toJSON());
console.log(JSON.stringify(material));
3.导出场景信息
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
console.log(scene);
console.log(JSON.stringify(scene));
2. 加载模型数据
通过各种Loader加载JSON数据
BufferGeometryLoader缓冲几何体数据加载器(加载geometry几何体信息,就是坐标)
var loader = new THREE.BufferGeometryLoader();
loader.load('bufferGeometry.json',function (geometry) {
// 控制台查看加载放回的threejs对象结构
console.log(geometry);
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff,
}); //材质对象Material
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
})
ObjectLoader加载Mesh(包含几何体Geometry和材质Material)
var loader = new THREE.ObjectLoader();
loader.load('model.json',function (obj) {
console.log(obj);
console.log(obj.type);
obj.scale.set(100,100,100)
scene.add(obj)
})
加载组Group对象,模型对象构成的树结构
loader.load('group.json', function(obj) {
console.log(obj);
console.log(obj.type);
scene.add(obj)
})
加载场景对象,场景对象不仅包含模型,还包括光源对象
loader.load('scene.json',function (obj) {
console.log(obj);
console.log(obj.type);
obj.scale.set(100,100,100)
scene.add(obj)
})
3. 加载模型文件(通过3Dmax、blender等软件导出的三维模型文件)
- .stl格式模型文件加载(.stl格式的三维模型不包含材质Material信息,只包含几何体顶点数据的信息)
三个位置坐标和一个三角形面的法线方向向量是一组数据,这一组数据表示一个三角形面的信息,下面是.syl文件里的内容
solid box //文件名字
//三角面1
facet normal 0 0 -1 //三角形面法向量
outer loop
vertex 50 50 -50 //顶点位置
vertex 50 -50 -50 //顶点位置
vertex -50 50 -50 //顶点位置
endloop
endfacet
//三角面2
facet normal 0 0 -1 //三角形面法向量
outer loop
vertex -50 50 -50 //顶点位置
vertex 50 -50 -50 //顶点位置
vertex -50 -50 -50 //顶点位置
endloop
endfacet
facet normal 0 1 0
.....
.....
//三角面12
facet normal -1 0 0
outer loop
vertex -50 -50 -50
vertex -50 50 50
vertex -50 50 -50
endloop
endfacet
endsolid
通过STLLoader.js加载.stl文件
1.首先导入STLLoader的js文件
<script src="http://www.yanhuangxueyuan.com/threejs/examples/js/loaders/STLLoader.js">
2.通过构造函数THREE.STLLoader()可以把.stl文件中几何体顶点信息提取出来转化为Three.js自身格式的几何体对象BufferGeometry
3.加载完成后会返回一个几何体对象BufferGeometry,你可以通过Mesh、Points等方式渲染该几何体
var loader = new THREE.STLLoader();
loader.load('立方体.stl',function (geometry) {
// 加载完成后会返回一个几何体对象BufferGeometry,你可以通过Mesh、Points等方式渲染该几何体
//网格渲染模式
var material = new THREE.MeshLambertMaterial({
color: 0x0000ff,
}); //材质对象Material
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
//点渲染模式
//var material = new THREE.PointsMaterial({
//color: 0x000000,
//size: 0.5//点对象像素尺寸
//}); //材质对象
//var points = new THREE.Points(geometry, material); //点模型对象
//scene.add(points); //点对象添加到场景中
})
- .obj格式模型文件加载(.使用三维软件导出.obj模型文件的时候,会同时导出一个材质文件.mtl, .obj和.stl文件包含的信息一样都是几何体顶点相关数据,材质文件.mtl包含的是模型的材质信息,比如颜色、贴图路径等)
通过OBJLoader.js加载.mtl,.obj文件
1.首先导入OBJLoader和MTLLoader的js文件
<script src="http://www.yanhuangxueyuan.com/threejs/examples/js/loaders/OBJLoader.js"></script>
<script src="http://www.yanhuangxueyuan.com/threejs/examples/js/loaders/MTLLoader.js"></script>
然后通过Loader加载完成之后显示在页面上
/**
* OBJ和材质文件mtl加载
*/
var OBJLoader = new THREE.OBJLoader();//obj加载器
var MTLLoader = new THREE.MTLLoader();//材质文件加载器
MTLLoader.load('./立方体/box.mtl', function(materials) {
// 返回一个包含材质的对象MaterialCreator
console.log(materials);
//obj的模型会和MaterialCreator包含的材质对应起来
OBJLoader.setMaterials(materials);
OBJLoader.load('./立方体/box.obj', function(obj) {
console.log(obj);
obj.scale.set(10, 10, 10); //放大obj组对象
scene.add(obj);//返回的组对象插入场景中
})
})
obj文件可以包含多个网格模型对象,不一定就是一个,这些网格模型对象全部是并列关系,无法通过父子关系构建一个树结构层级模型。
***注意当Loader加载模型文件时,如果没设置材质文件,系统自动设置Phong网格材质***
可以通过.children[index]属性查看某个模型,像数组一样
// 没有材质文件,系统自动设置Phong网格材质
OBJLoader.load('./多个模型/model.obj',function (obj) {
// 控制台查看返回结构:包含一个网格模型Mesh的组Group
console.log(obj);
scene.add(obj);
// 加载后的一些编辑操作
obj.scale.set(20,20,20);//网格模型缩放
// 设置其中一个网格模型的颜色
obj.children[0].material.color.set(0xff0000);
})
.obj文件不包含场景的相机Camera、光源Light等信息,不能导出骨骼动画、变形动画,如果希望导出光照信息、相机信息、骨骼动画信息、变形动画信息,可以选择.fbx、.gltf等格式。
- FBX格式模型文件加载
通过FBXLoader加载.fbx文件(stl、obj都是静态模型,不可以包含动画,fbx除了包含几何、材质信息,可以存储骨骼动画等数据。)
1.首先导入FBXLoader的js文件和辅助文件
2.加载fbx模型文件
3.解析fbx模型骨骼动画
<!-- 引入fbx模型加载库FBXLoader -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/loaders/FBXLoader.js"></script>
<!-- 辅助文件 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/libs/inflate.min.js"></script>
var loader = new THREE.FBXLoader();//创建一个FBX加载器
loader.load("SambaDancing.fbx", function(obj) {
// console.log(obj);//查看加载后返回的模型对象
scene.add(obj)
// 适当平移fbx模型位置
obj.translateY(-80);
})
var mixer=null;//声明一个混合器变量
var loader = new THREE.FBXLoader();//创建一个FBX加载器
loader.load("SambaDancing.fbx", function(obj) {
// console.log(obj)
scene.add(obj)
obj.translateY(-80);
// obj作为参数创建一个混合器,解析播放obj及其子对象包含的动画数据
mixer = new THREE.AnimationMixer(obj);
// 查看动画数据
console.log(obj.animations)
// obj.animations[0]:获得剪辑对象clip
var AnimationAction=mixer.clipAction(obj.animations[0]);
// AnimationAction.timeScale = 1; //默认1,可以调节播放速度
// AnimationAction.loop = THREE.LoopOnce; //不循环播放
// AnimationAction.clampWhenFinished=true;//暂停在最后一帧播放的状态
AnimationAction.play();//播放动画
})
// 创建一个时钟对象Clock
var clock = new THREE.Clock();
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
if (mixer !== null) {
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
mixer.update(clock.getDelta());
}
}
render();
九 * 纹理贴图
1.给模型对象设置纹理贴图
通过TextureLoader加载一张图片后返回一个纹理对象Texture,Texture可以作为模型材质颜色贴图.map属性的值,设置map属性后就不用再设置color属性了
// 纹理贴图映射到一个矩形平面上
var geometry = new THREE.PlaneGeometry(204, 102); //矩形平面
// TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理
var textureLoader = new THREE.TextureLoader();
// 执行load方法,加载纹理贴图成功后,返回一个纹理对象Texture
textureLoader.load('Earth.png', function(texture) {
var material = new THREE.MeshLambertMaterial({
// color: 0x0000ff,
// 设置颜色纹理贴图:Texture对象作为材质map属性的属性值
map: texture,//设置颜色贴图属性值
}); //材质对象Material
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
function render() {
renderer.render(scene, camera);
}
//纹理贴图加载成功后,调用渲染函数执行渲染操作
render();
})
通过图片加载器ImageLoader可以加载一张图片,所谓纹理对象Texture简单地说就是,纹理对象Texture的.image属性值是一张图片。
// 图片加载器
var ImageLoader = new THREE.ImageLoader();
// load方法回调函数,按照路径加载图片,返回一个html的元素img对象
ImageLoader.load('Earth.png', function(img) {
// image对象作为参数,创建一个纹理对象Texture
var texture = new THREE.Texture(img);
// 下次使用纹理时触发更新
texture.needsUpdate = true;
var material = new THREE.MeshLambertMaterial({
map: texture, //设置纹理贴图
});
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
});
2.纹理贴图的平铺,旋转,偏移,动画
1. 平铺
var texture = textureLoader.load('太阳能板.png');
// 设置阵列模式 默认ClampToEdgeWrapping RepeatWrapping:阵列 镜像阵列:MirroredRepeatWrapping
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
// uv两个方向纹理重复数量
texture.repeat.set(4, 2);
2 .偏移
texture.offset = new THREE.Vector2(0.3, 0.1)
2 .旋转
// 设置纹理旋转角度
texture.rotation = Math.PI/4;
// 设置纹理的旋转中心,默认(0,0)
texture.center.set(0.5,0.5);
3 .动画
在渲染函数中周期性的改变纹理贴图的属性,重复执行渲染函数就可以实现动画
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render);
// 使用加减法可以设置不同的运动方向
// 设置纹理偏移
texture.offset.x -= 0.06
}
render();
4.凹凸贴图和法线贴图
这两种贴图都是为了处理模型顶点过多导致贴图不清晰的问题
var geometry = new THREE.SphereGeometry(100, 25, 25); //球体
//法线贴图
// TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理
var textureLoader = new THREE.TextureLoader();
// 加载纹理贴图
var texture = textureLoader.load('./Earth.png');
// 加载法线贴图
var textureNormal = textureLoader.load('./EarthNormal.png');
var material = new THREE.MeshPhongMaterial({
map: texture, // 普通颜色纹理贴图
normalMap: textureNormal, //法线贴图
//设置深浅程度,默认值(1,1)。
normalScale: new THREE.Vector2(1.2, 1.2),
}); //材质对象Material
//凹凸贴图
var textureLoader = new THREE.TextureLoader();
// 加载颜色纹理贴图
var texture = textureLoader.load('./凹凸贴图/diffuse.jpg');
// 加载凹凸贴图
var textureBump = textureLoader.load('./凹凸贴图/bump.jpg');
var material = new THREE.MeshPhongMaterial({
map: texture,// 普通纹理贴图
bumpMap:textureBump,//凹凸贴图
bumpScale:3,//设置凹凸高度,默认值1。
}); //材质对象Material
5.光照贴图(给模型添加阴影)
三维模型加载器可以自动设置,不需要程序员通过代码去设置,但还是操作一下
//创建一个平面几何体作为投影面
var planeGeometry = new THREE.PlaneGeometry(300, 200);
planeGeometry.faceVertexUvs[1] = planeGeometry.faceVertexUvs[0];
var textureLoader = new THREE.TextureLoader();
// 加载光照贴图
var textureLight = textureLoader.load('shadow.png');
var planeMaterial = new THREE.MeshLambertMaterial({
color: 0x999999,
lightMap:textureLight,// 设置光照贴图
// lightMapIntensity:0.5,//烘培光照的强度. 默认 1.
});
var planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); //网格模型对象Mesh
Geometry属性.faceVertexUvs
一般几何体有两套UV坐标,对于Geometry类型几何体而言
Geometry.faceVertexUvs[0]包含的纹理坐标用于颜色贴图map、法线贴图normalMap等,Geometry.faceVertexUvs[1]包含的第二套纹理贴图用于光照贴图
一般通过Threejs几何体API创建的几何体默认只有一组纹理坐标Geometry.faceVertexUvs[0],所以为了设置光照阴影贴图,需要给另一组纹理坐标赋值Geometry.faceVertexUvs[1] = Geometry.faceVertexUvs[0];
BufferGeometry属性.uv和.uv2
一般通过Threejs加载外部模型,解析三维模型数据得到的几何体类型是缓冲类型几何体BufferGeometry,对于BufferGeometry而言两套纹理坐标分别通过.uv和.uv2属性表示。
geometry.attributes.uv2 = geometry.attributes.uv;
6.高光贴图(设置模型不同区域的亮度值)
设置模型不同区域的亮度值,(高光贴图属性.specularMap和高光属性.specular是对应的,也就是说只有高光网格材质对象MeshPhongMaterial才具备高光贴图属性.specularMap)
// 加载纹理贴图
var texture = textureLoader.load('earth_diffuse.png');
// 加载高光贴图
var textureSpecular = textureLoader.load('earth_specular.png');
var material = new THREE.MeshPhongMaterial({
// specular: 0xff0000,//高光部分的颜色
shininess: 30,//高光部分的亮度,默认30
map: texture,// 普通纹理贴图
specularMap: textureSpecular, //高光贴图
}); //材质对象Material
7.环境贴图(给模型的周围环境添加贴图)
首先引入CubeTextureLoader(只有环境贴图用CubeTextureLoader,其他贴图用的是TextureLoader),然后给材质对象设置envMap属性,一般情况下高光网格材质MeshPhongMaterial和物理PBR材质MeshStandardMaterial会使用环境贴图
var geometry = new THREE.BoxGeometry(100, 100, 100); //立方体
var loader = new THREE.CubeTextureLoader();
// 所有贴图在同一目录下,可以使用该方法设置共用路径
loader.setPath('环境贴图/');
// 立方体纹理加载器返回立方体纹理对象CubeTexture
var CubeTexture = loader.load(['px.jpg', 'nx.jpg', 'py.jpg', 'ny.jpg', 'pz.jpg', 'nz.jpg']);
//材质对象Material
var material = new THREE.MeshPhongMaterial({
//网格模型设置颜色,网格模型颜色和环境贴图会进行融合计算
// color:0xff0000,
envMap: CubeTexture, //设置环境贴图
// 环境贴图反射率 控制环境贴图对被渲染三维模型影响程度
// reflectivity: 0.1,
});
console.log(CubeTexture.image);
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
十 * 相机对象
1.正射投影和透视投影
正射投影:一条直线放置的角度不同,投影在投影面上面的长短不同
透视投影:投影的结果除了与几何体的角度有关,还和距离相关, 人的眼睛观察世界就是透视投影
- 正投影相机对象OrthographicCamera
/**
* 正投影相机设置
*/
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); //设置相机方向(指向的场景对象)
- 透视投影相机PerspectiveCamera
/**
* 透视投影相机设置
*/
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
/**透视投影相机对象*/
var camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
2.窗口变化自适应渲染
开发的过程中你可能会遇到这样一个问题,通过鼠标拖动使浏览器的窗口变大,因为Threejs渲染器的渲染尺寸范围没有跟着变化,出现局部空白区域。对于这种情况要做的就是重新获取浏览器窗口新的宽高尺寸,然后通过新的宽高尺寸更新相机Camera和渲染器WebGLRenderer的参数即可。
具体做法为监听window.onresize事件,在回调函数中更新相机和render的参数
- 正投影相机OrthographicCamera自适应渲染
// onresize 事件会在窗口被调整大小时发生
window.onresize=function(){
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth,window.innerHeight);
// 重置相机投影的相关参数
k = window.innerWidth/window.innerHeight;//窗口宽高比
camera.left = -s*k;
camera.right = s*k;
camera.top = s;
camera.bottom = -s;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix ();
};
- 透视投影相机PerspectiveCamera自适应渲染
// onresize 事件会在窗口被调整大小时发生
window.onresize=function(){
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth,window.innerHeight);
// 全屏情况下:设置观察范围长宽比aspect为窗口宽高比
camera.aspect = window.innerWidth/window.innerHeight;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix ();
};
十一 * 精灵模型和粒子系统
精灵模型就是一个模型的标签,标签的内容可以是模型的信息(创建精灵模型对象Sprite和创建网格模型对象一样需要创建一个材质对象,不同的地方在于创建精灵模型对象不需要创建几何体对象Geometry)
- 下面是创建精灵模型的方法
var texture = new THREE.TextureLoader().load("sprite.png");
// 创建精灵材质对象SpriteMaterial
var spriteMaterial = new THREE.SpriteMaterial({
color:0xff00ff,//设置精灵矩形区域颜色
rotation:Math.PI/4,//旋转精灵对象45度,弧度值
map: texture,//设置精灵纹理贴图
});
// 创建精灵模型对象,不需要几何体geometry参数
var sprite = new THREE.Sprite(spriteMaterial);
scene.add(sprite);
// 控制精灵大小,比如可视化中精灵大小表征数据大小
sprite.scale.set(10, 10, 1); 只需要设置x、y两个分量就可以
粒子系统就是用很多个精灵模型组合在一起形成的效果,下面是一个用精灵模型(粒子系统)打造的一个树林模型
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<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>
var scene = new THREE.Scene();
var textureTree=new THREE.TextureLoader().load("./tree.png");
for(let i = 0; i < 100; i++){
var spriteMaterial = new THREE.SpriteMaterial({
map:textureTree,//设置精灵纹理贴图
});
// 创建精灵模型对象
var sprite = new THREE.Sprite(spriteMaterial);
scene.add(sprite);
// 控制精灵大小,
sprite.scale.set(100, 100, 1); 只需要设置x、y两个分量就可以
var k1 = Math.random() - 0.5;
var k2 = Math.random() - 0.5;
// 设置精灵模型位置,在xoz平面上随机分布
sprite.position.set(1000 * k1, 50, 1000 * k2)
}
var geometry = new THREE.PlaneGeometry(1000, 1000); //矩形平面
// 加载草地纹理贴图
var material = new THREE.MeshLambertMaterial({
color: 0x777700,
// map:texture,
});
var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.add(mesh); //网格模型添加到场景中
mesh.rotateX(-Math.PI/2);
//点光源
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 = 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);
}
var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象
controls.addEventListener('change', render);//监听鼠标、键盘事件
</script>
</body>
</html>
十二 * 帧动画
- 编辑帧动画并解析播放
1.创建两个用于动画的网格模型
/**
* 创建两个网格模型并设置一个父对象group
*/
mesh1.name = "Box"; //网格模型1命名
mesh2.name = "Sphere"; //网格模型2命名
group.add(mesh1); //网格模型添加到组中
group.add(mesh2); //网格模型添加到组中
2.编辑关键帧(通过关键帧KeyframeTrack和剪辑AnimationClip两个API来完成,实际开发中复杂的动画是通过3Dmax生成的)
/**
* 编辑group子对象网格模型mesh1和mesh2的帧动画数据
*/
// 创建名为Box对象的关键帧数据
var times = [0, 10]; //关键帧时间数组,离散的时间点序列
var values = [0, 0, 0, 150, 0, 0]; //与时间点对应的值组成的数组
// 创建位置关键帧对象:0时刻对应位置0, 0, 0 10时刻对应位置150, 0, 0
var posTrack = new THREE.KeyframeTrack('Box.position', times, values);
// 创建颜色关键帧对象:10时刻对应颜色1, 0, 0 20时刻对应颜色0, 0, 1
var colorKF = new THREE.KeyframeTrack('Box.material.color', [10, 20], [1, 0, 0, 0, 0, 1]);
// 创建名为Sphere对象的关键帧数据 从0~20时间段,尺寸scale缩放3倍
var scaleTrack = new THREE.KeyframeTrack('Sphere.scale', [0, 20], [1, 1, 1, 3, 3, 3]);
// duration决定了默认的播放时间,一般取所有帧动画的最大时间
// duration偏小,帧动画数据无法播放完,偏大,播放完帧动画会继续空播放
var duration = 20;
// 多个帧动画作为元素创建一个剪辑clip对象,命名"default",持续时间20
var clip = new THREE.AnimationClip("default", duration, [posTrack, colorKF, scaleTrack]);
3.播放关键帧(通过操作AnimationAction和混合器AnimationMixer两个API播放已有的帧动画数据,混合器THREE.AnimationMixer()的参数是案例代码中编写的两个网格模型的父对象group,实际开发中参数Group也可以是你加载外部模型返回的模型对象。)
**
* 播放编辑好的关键帧数据
*/
// group作为混合器的参数,可以播放group中所有子对象的帧动画
var mixer = new THREE.AnimationMixer(group);
// 剪辑clip作为参数,通过混合器clipAction方法返回一个操作对象AnimationAction
var AnimationAction = mixer.clipAction(clip);
//通过操作Action设置播放方式
AnimationAction.timeScale = 20;//默认1,可以调节播放速度
// AnimationAction.loop = THREE.LoopOnce; //不循环播放
AnimationAction.play();//开始播放
4.设置两次渲染时间间隔(获得时间间隔可以通过Threejs提供的一个时钟类Clock实现)
// 创建一个时钟对象Clock
var clock = new THREE.Clock();
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
mixer.update(clock.getDelta());
}
render();
- 解析外部模型的帧动画
如果你引用的外部模型文件里保存着动画信息(例如JSON文件),需要通过ObjectLoader解析JSON文件,首先在外部定义一个空的mixer混合器变量,然后在解析文件的回调函数里通过THREE.AnimationMixer把模型对象作为参数传入生成mixer,之后通过mixer.clipAction把模型对象的动画作为参数传入生成操作对象AnimationAction ,最后设置两次渲染时间间隔
// 通过ObjectLoader加载模型文件model.json
var loader = new THREE.ObjectLoader();
var mixer = null; //声明一个混合器变量
// 加载文件返回一个对象obj
loader.load("model.json", function(obj) {
obj.scale.set(15, 15, 15);//缩放加载的模型
scene.add(obj);
// obj作为混合器的参数,可以播放obj包含的帧动画数据
mixer = new THREE.AnimationMixer(obj);
// obj.animations[0]:获得剪辑clip对象
// // 剪辑clip作为参数,通过混合器clipAction方法返回一个操作对象AnimationAction
var AnimationAction = mixer.clipAction(obj.animations[0]);
AnimationAction.play();
});
/ 创建一个时钟对象Clock
var clock = new THREE.Clock();
// 渲染函数
function render() {
renderer.render(scene, camera); //执行渲染操作
requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
if(mixer!==null){
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
mixer.update(clock.getDelta());
}
}
render();
- 播放设置(暂停,快进,定位到某一时间,播放特定时间段,滚动条播放)
播放/暂停(.paused属性)
<button onclick="pause()" type="button" style="position: absolute;padding: 10px;">暂停/继续</button>
<script>
// 暂停继续播放函数
function pause() {
if (AnimationAction.paused) {
// 如果是播放状态,设置为暂停状态
AnimationAction.paused = false;
} else {
// 如果是暂停状态,设置为播放状态
AnimationAction.paused = true;
}
}
</script>
播放clip特定时间段
/**
* 播放编辑好的关键帧数据
*/
var mixer = new THREE.AnimationMixer(mesh); //创建混合器
var AnimationAction = mixer.clipAction(clip); //返回动画操作对象
// AnimationAction.timeScale = 5; //默认1,可以调节播放速度
AnimationAction.loop = THREE.LoopOnce; //不循环播放
AnimationAction.clampWhenFinished = true; //暂停在最后一帧播放的状态
// 设置播放区间10~18 关键帧数据总时间是20
AnimationAction.time = 10; //操作对象设置开始播放时间
clip.duration = 18;//剪辑对象设置播放结束时间
AnimationAction.play(); //开始播放
定位在某个时间点(开始结束时间设置为一样,相当于播放时间为0,直接跳转到时间点对应的状态)
**
* 播放编辑好的关键帧数据
*/
var mixer = new THREE.AnimationMixer(mesh); //创建混合器
var AnimationAction = mixer.clipAction(clip); //返回动画操作对象
// AnimationAction.timeScale = 5; //默认1,可以调节播放速度
AnimationAction.loop = THREE.LoopOnce; //不循环播放
AnimationAction.clampWhenFinished = true; //暂停在最后一帧播放的状态
// 开始结束时间设置为一样,相当于播放时间为0,直接跳转到时间点对应的状态
AnimationAction.time = 10; //操作对象设置开始播放时间
clip.duration = AnimationAction.time;//剪辑对象设置播放结束时间
AnimationAction.play(); //开始播放
快进(按钮递增时间点)
AnimationAction.time += 2; //操作对象设置开始播放时间
clip.duration = AnimationAction.time;//剪辑对象设置播放结束时间
AnimationAction.play(); //开始播放
滚动条拖动播放
<div id="app">
<div class="block" style="display:inline;width:500px">
<el-slider v-model="time" show-input :max=20 :step=0.01></el-slider>
</div>
</div>
<script>
...
...
var mixer = new THREE.AnimationMixer(mesh);
var AnimationAction = mixer.clipAction(clip);
AnimationAction.loop = THREE.LoopOnce;
AnimationAction.clampWhenFinished = true;
//实例化vue
vm = new Vue({
el: "#app",
data: {
time: 0,
},
watch: {
time:function (value) {
// 开始结束时间设置为一样,相当于播放时间为0,直接跳转到时间点对应的状态
AnimationAction.time = value; //操作对象设置开始播放时间
clip.duration = AnimationAction.time;//剪辑对象设置播放结束时间
AnimationAction.play(); //开始播放
}
},
})
</script>
十三 * 骨骼动画,变形动画
十四 * 音频
十五 * 加载外部fbx模型文件的过程
1.通过FBXLoader加载fbx模型文件之后,贴图无法显示的问题,解决:手动用THREE.TextureLoader()加载贴图,生成贴图对象,然后赋值给模型对象的材质对象的map属性,例如fbx.children[0].material.map = map4
2.如何获取模型对象,解决:加载完fbx模型文件后,log一下打印结果,childrens里保存的就是每个模型对象
3.下面是具体代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.js"></script>
<!-- <script src="./node_modules/three/examples/js/loaders/OBJLoader.js"></script>
<script src="./node_modules/three/examples/js/loaders/MTLLoader.js"></script> -->
<!-- 引入fbx模型加载库FBXLoader -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/loaders/FBXLoader.js"></script>
<!-- 辅助文件 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/libs/inflate.min.js"></script>
<script src="http://www.yanhuangxueyuan.com/threejs/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<script>
var FBX = "";
var scene = new THREE.Scene();
var map1 = new THREE.TextureLoader().load('./textures/big_parts_col.jpg');
var map2 = new THREE.TextureLoader().load('./textures/big_parts_nor.jpg');
var map3 = new THREE.TextureLoader().load('./textures/big_parts_rough.jpg');
var map4 = new THREE.TextureLoader().load('./textures/fire_alpha.jpg');
var map5 = new THREE.TextureLoader().load('./textures/fire_col.jpg');
var map6 = new THREE.TextureLoader().load('./textures/small_parts_col.jpg');
var map7 = new THREE.TextureLoader().load('./textures/small_parts_rough.jpg');
var loader = new THREE.FBXLoader();
loader.load( 'trabant_realtime_v3.fbx', function ( fbx ) {
console.log(fbx);
FBX=fbx;
fbx.children[0].material.map = map4
fbx.children[1].material.map = map2
fbx.children[2].material.map = map6
fbx.children[3].material.map = map7
scene.add( fbx );
} );
//点光源
var point = new THREE.PointLight(0xcccccc);
point.position.set(400, 1000, 400); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
var ambient = new THREE.AmbientLight(0xffffff);
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);
}
var controls = new THREE.OrbitControls(camera,renderer.domElement);//创建控件对象
controls.addEventListener('change', render);//监听鼠标、键盘事件
</script>
</body>
</html>