threejs构建web三维视图入门教程
本文是一篇简单的webGL+threejs构建web三维视图的入门教程,你可以了解到利用threejs创建简单的三维图形,并且控制图形运动。若有不足,欢迎指出。
本文使用的框架是three.js
github地址:https://github.com/mrdoob/three.js, 官网:http://threejs.org/, 文档:http://threejs.org/docs/, 本文中的示例已上传github,地址:https://github.com/RizzleCi/three.js-demo一、创建场景
我们所见的视图由两个部分共同创建,scene和camera。首先定义一个场景:
var scene = new THREE.Scene();
然后定义一个相机:
var camera = new THREE.PerspectiveCamera( 90, width/height, 0.1, 1000 );
等等,定义相机需要视窗的长宽。现在我要让我的绘图显示在页面的一个区域(<div>)标签中。我们来选中这个元素,获取它的长宽。
var container = document.getElementById('canvasdiv');
var width = canvasdiv.clientWidth;
var height = canvasdiv.clientHeight;
这样再加上前面的一行代码,我们就完成了对相机的定义。然后把相机位置设定在z轴上方便观察。
camera.position.set(0,0,10)
现在我们需要一个渲染器把定义好的场景渲染出来。
var renderer = new THREE.WebGLRenderer();
给这个渲染器合适的大小。
renderer.setSize( width, height );
然后将其加入到dom中。
canvasdiv.appendChild( renderer.domElement );
(运行以后发现这其实就是一个canvas元素。其实我们也可以在html中创建canvas元素再将renderer绑定到它上面。
var renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('mainCanvas') });
)
最后进行渲染。
renderer.render(scene,camera);
这样,就建立了一个简单的3d场景。
二、绘制图形
我将threejs中的物体理解为模型+材料。以一个长方体为例。
创建模型:
var geometry = new THREE.BoxGeometry( 1,2,1 );
定义材料:
var material = new THREE.MeshBasicMaterial( { color: 0x645d50 } );
有了这两者,我们就可以构建一个长方体方块了。
var cube = new THREE.Mesh( geometry, material );
我们将其添加到场景中显示。
scene.add( cube );
这样,一个三维的长方体就绘制完成了
关于其他形状的绘制,张雯莉的threejs入门指南中介绍的很详细,在此不多赘述。
这部分的完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
#canvasdiv{
width: 600px;
height: 600px;
} </style>
<script src="js/three.min.js"></script>
</head>
<body> <div class="main-content" id="canvasdiv"> </div> <script type="text/javascript" >
var container = document.getElementById('canvasdiv')
var scene = new THREE.Scene();
var width = canvasdiv.clientWidth;
var height = canvasdiv.clientHeight;
var camera = new THREE.PerspectiveCamera( 90, width/height, 0.1, 1000 );
camera.position.set(0,0,10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
canvasdiv.appendChild( renderer.domElement );
var geometry = new THREE.BoxGeometry( 2,1,1 );
var material = new THREE.MeshBasicMaterial( { color: 0x645d50 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
renderer.render(scene,camera);
</script>
</body>
</html>

看上去它只是一个长方形而已,但是它确实是一个立体图形,你可以改变一下camera的位置来观察一下。
camera.position.set( 5,3,10 );

好了,这样看起来是一个立体的长方体了吧。
三、创建3d对象
绘制对象
大多数时候,我们需要讲绘制的图形整合到一起进行控制。此时,我们便需要一个3d对象。
在上面绘制的那个长方体上面再放一个球。
var geometry = new THREE.SphereGeometry( 0.5,100,100 );
var material = new THREE.MeshBasicMaterial( { color: 0xb9c16c } );
var ball = new THREE.Mesh( geometry,material );
ball.position.set( 0,0,1 );
scene.add(ball);
另说一句,默认放置mesh的位置是( 0,0,0 ),和改变相机位置一样,我们可以用ball.position.set方法来改变图形或对象的位置。因此动画也利用这个方法来实现。
然后要把它们整合成一个对象。
首先我们创建一个对象。
var myobj = new THREE.Object3D();
然后把我们画的图形添加到对象里就ok啦。
myobj.add( cube );
myobj.add( ball );
这时候我们已经有了一个3d对象,它包含我们刚刚绘制的长方形和球。于是就没有必要像原来那样把图形一个一个地放置到场景里,只需要把刚刚创建的对象放置到场景里。
scene.add( myobj );
完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
#canvasdiv{
width: 600px;
height: 600px;
} </style>
<script src="js/three.min.js"></script> </head>
<body> <div class="main-content" id="canvasdiv"> </div> <script type="text/javascript" >
var container = document.getElementById('canvasdiv')
var scene = new THREE.Scene();
var width = canvasdiv.clientWidth;
var height = canvasdiv.clientHeight;
var camera = new THREE.PerspectiveCamera( 90, width/height, 0.1, 1000 );
camera.position.set( 0,0,10 )
var renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
canvasdiv.appendChild( renderer.domElement ); var geometry = new THREE.BoxGeometry( 2,1,1 );
var material = new THREE.MeshBasicMaterial( { color: 0x645d50 } );
var cube = new THREE.Mesh( geometry, material );
//scene.add( cube ); var geometry = new THREE.SphereGeometry( 0.5,100,100 );
var material = new THREE.MeshBasicMaterial( { color: 0xb9c16c } );
var ball = new THREE.Mesh( geometry,material );
ball.position.set( 0,0,1 );
//scene.add(ball); var myobj = new THREE.Object3D();
myobj.add( cube );
myobj.add( ball );
scene.add( myobj ); renderer.render(scene,camera);
</script>
</body>
</html>
显示效果:

外部导入.obj文件
threejs支持从外部导入.obj文件,听说这种文件是用3DsMax绘制的,用PS也可以编辑。我们需要引入OBJMTLLoader.js,MTLLoader.js文件;也有一个OBJLoader.js,但利用这个库只能导入模型而不能导入绘制obj时添加的材质,个人感觉不是非常实用,就不做介绍了。这时候,我们需要把文件们放到一个服务器上,否则会出现跨域问题。
为了让图像更明显,我们添加一些光线。
scene.add( new THREE.AmbientLight( 0xffffff ) );
这里,我们通过导入图片来设置这个对象的纹理。
var texture = new THREE.Texture();
var loader = new THREE.ImageLoader( );
loader.load( 'tank.jpg', function ( image ) {
texture.image = image;
texture.needsUpdate = true;
} );
开始导入我们的3D对象!
var loader = new THREE.OBJMTLLoader();
loader.load('tank.obj','tank.mtl',function(object){
tank = object; object.traverse(function(child){
if (child instanceof THREE.Mesh){
//将贴图赋于材质
child.material.map = texture;
child.material.transparent = true;
}
});
object.position.set(0,0,0);
scene.add( object );
camera.lookAt( object.position );
renderer.render( scene,camera );
});
模型导入进去了,但是看起来还是很奇怪,这就要我们加一些其他光线渲染一下。在这里我们添加平行光线。
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.5 );
directionalLight.position.set( 1, 1, 1 );
scene.add( directionalLight );

变得光泽多了。
从外部导入obj的完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
#canvasdiv{
width: 1200px;
height: 800px;
} </style>
<script src="js/three.min.js"></script>
<script src="js/MTLLoader.js"></script>
<script src="js/OBJMTLLoader.js"></script>
</head>
<body> <div class="main-content" id="canvasdiv"> </div> <script type="text/javascript" >
var container = document.getElementById('canvasdiv')
var scene = new THREE.Scene();
var width = canvasdiv.clientWidth;
var height = canvasdiv.clientHeight;
var camera = new THREE.PerspectiveCamera( 90, width/height, 0.1, 1000 );
camera.position.set( -10,10,10);
var renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
canvasdiv.appendChild( renderer.domElement ); var texture = new THREE.Texture();
var loader = new THREE.ImageLoader( );
loader.load( 'tank.jpg', function ( image ) { texture.image = image;
texture.needsUpdate = true; } );
var loader = new THREE.OBJMTLLoader();
loader.load('tank.obj','tank.mtl',function(object){
tank = object;
object.traverse(function(child){
if (child instanceof THREE.Mesh){
//将贴图赋于材质
child.material.map = texture;
//重点,没有该句会导致PNG无法正确显示透明效果
child.material.transparent = true;
}
});
object.position.set(0,0,0);
scene.add( object );
camera.lookAt( object.position );
renderer.render( scene,camera );
});
scene.add( new THREE.AmbientLight( 0xffffff ) );
var directionalLight = new THREE.DirectionalLight( 0xffffff, 1.5 );
directionalLight.position.set( 1, 1, 1 )
scene.add( directionalLight ); renderer.render(scene,camera);
</script>
</body>
</html>
四、动画
现在我们想办法让这些图形动起来。
在threejs中运用最多的动画是用requestAnimationFrame()方法。也可以利用传统的setInterval()做,但用这个会掉帧。
这里我们做一个render函数,来进行渲染和动画调用。这里以前面添加了myobj对象的代码为基础。
现在来不断地改变对象的角度方便对其进行观察。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
#canvasdiv{
width: 600px;
height: 600px;
} </style>
<script src="js/three.min.js"></script> </head>
<body> <div class="main-content" id="canvasdiv"> </div> <script type="text/javascript" >
var container,camera,scene,renderer,myobj; var init = function () {
container = document.getElementById('canvasdiv')
scene = new THREE.Scene();
var width = canvasdiv.clientWidth;
var height = canvasdiv.clientHeight;
camera = new THREE.PerspectiveCamera( 90, width/height, 0.1, 1000 );
camera.position.set( 0,0,10 )
renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
canvasdiv.appendChild( renderer.domElement ); var geometry = new THREE.BoxGeometry( 2,1,1 );
var material = new THREE.MeshBasicMaterial( { color: 0x645d50 } );
var cube = new THREE.Mesh( geometry, material );
//scene.add( cube ); var geometry = new THREE.SphereGeometry( 0.5,100,100 );
var material = new THREE.MeshBasicMaterial( { color: 0xb9c16c } );
var ball = new THREE.Mesh( geometry,material );
ball.position.set( 0,0,1 );
//scene.add(ball); myobj = new THREE.Object3D();
myobj.add( cube );
myobj.add( ball );
scene.add( myobj );
} var render = function () {
requestAnimationFrame( render );
myobj.rotation.x+=0.01;
myobj.rotation.y+=0.01;
renderer.render(scene,camera);
}
init()
render()
</script>
</body>
</html>
接着让我们对动画进行控制。
在我实现的项目中,是通过websocket连接后台传入参数来控制对象运动的,这里就介绍一下使用参数控制吧。
这里有一个问题,就是requestAnimationFrame回调的函数不能带有参数,否则会出现奇怪的bug。所以我选择用一个全局对象来进行控制。
var control={
s:0,
p:0,
q:0,
j:0,
}
这里s是运动的速度,p,q,j分别是myobj将要运动到的位置的x,y,z坐标。我们先写一个控制它在x轴上运动的函数:
var run = function () {
if ( myobj.position.x<control.p ) {
myobj.position.x += control.s;
requestAnimationFrame( run );
renderer.render( scene,camera )
};
if ( myobj.position.x>control.p ) {
myobj.position.x -= control.s;
requestAnimationFrame( run );
renderer.render( scene,camera )
};
}
再在render函数中添加对run的调用requestAnimationFrame( run )。这样就可以在命令行中改变对象control的值实现控制myobj的运动。但是在运动停止后我的浏览器为什么会变得很卡,而且运动速度回有变化。我还不知道原因。不知道有没有朋友和我有同样的问题。于是我把函数拆成了两个,这样浏览器性能好些。
var run = function () {
if ( myobj.position.x<control.p ) {
myobj.position.x += control.s;
requestAnimationFrame( run );
};
renderer.render( scene,camera )
}
var runx = function () {
if ( myobj.position.x>control.p ) {
myobj.position.x -= control.s;
requestAnimationFrame( runx );
};
renderer.render( scene,camera )
}
同样的,也可以写出在y,z轴上运动的函数。
在x轴上运动的完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
#canvasdiv{
width: 600px;
height: 600px;
} </style>
<script src="js/three.min.js"></script> </head>
<body> <div class="main-content" id="canvasdiv"> </div> <script type="text/javascript" >
var container,camera,scene,renderer,myobj; var init = function () {
container = document.getElementById('canvasdiv')
scene = new THREE.Scene();
var width = canvasdiv.clientWidth;
var height = canvasdiv.clientHeight;
camera = new THREE.PerspectiveCamera( 90, width/height, 0.1, 1000 );
camera.position.set( 0,0,10 )
renderer = new THREE.WebGLRenderer();
renderer.setSize( width, height );
canvasdiv.appendChild( renderer.domElement ); var geometry = new THREE.BoxGeometry( 2,1,1 );
var material = new THREE.MeshBasicMaterial( { color: 0x645d50 } );
var cube = new THREE.Mesh( geometry, material );
//scene.add( cube ); var geometry = new THREE.SphereGeometry( 0.5,100,100 );
var material = new THREE.MeshBasicMaterial( { color: 0xb9c16c } );
var ball = new THREE.Mesh( geometry,material );
ball.position.set( 0,0,1 );
//scene.add(ball); myobj = new THREE.Object3D();
myobj.add( cube );
myobj.add( ball );
scene.add( myobj );
} var control={
s:0,
p:0,
q:0,
j:0,
} var run = function () { if ( myobj.position.x<control.p ) {
myobj.position.x += control.s;
requestAnimationFrame( run );
};
renderer.render( scene,camera )
}
var runx = function () { if ( myobj.position.x>control.p ) {
myobj.position.x -= control.s;
requestAnimationFrame( runx );
};
renderer.render( scene,camera )
} var render = function () {
requestAnimationFrame( run );
requestAnimationFrame( runx );
renderer.render(scene,camera);
} init()
render()
</script>
</body>
</html>
这个入门教程就到这里了,感谢阅读。
threejs构建web三维视图入门教程的更多相关文章
- spring mvc构建WEB应用程序入门例子
在使用spring mvc 构建web应用程序之前,需要了解spring mvc 的请求过程是怎样的,然后记录下如何搭建一个超简单的spring mvc例子. 1) spring mvc的请求经历 请 ...
- JMeter Web测试快速入门教程
学习前的准备 学习本教程前,你的电脑上至少应该有Apache JMeter这款软件.如果你没有,点击此处下载. 当你点进去后,你会发现它是一个依赖Java的软件 因此如果你电脑上没有Java环境,你应 ...
- Web三维编程入门总结之一:WebGL与Threejs入门知识
/*在这里对这段时间学习的3D编程知识做个总结,以备再次出发.计划分成“webgl与three.js基础介绍”.“面向对象的基础3D场景框架编写”.“模型导入与简单3D游戏编写”三个部分,其他零散知识 ...
- Web三维编程入门总结之二:面向对象的基础Web3D框架
本篇主要通过分析Tony Parisi的sim.js库(原版代码托管于:https://github.com/tparisi/WebGLBook/tree/master/sim),总结基础Web3D框 ...
- Web三维编程入门总结之三:3D碰撞检测初探
自己动手写一个方法比分析他人的写的方法困难很多,由此而来的对程序的进一步理解也是分析别人的代码很难得到的. 一.先来几张效果图: 1.场景中有两个半径为1的球体,蓝色线段从球心出发指向球体的“正向” ...
- DotNetBrowser入门教程(更新完善中)
DotNetBrowser 希望实现的目标:桌面软件可以完美运行Html5,内置支持MVC与WebSocket的微型服务器. 基于.Net 4.0开发.开发环境:VS2017,运行环境支持Window ...
- Spring Boot入门教程1、使用Spring Boot构建第一个Web应用程序
一.前言 什么是Spring Boot?Spring Boot就是一个让你使用Spring构建应用时减少配置的一个框架.约定优于配置,一定程度上提高了开发效率.https://zhuanlan.zhi ...
- ASP.NET Core 入门教程 1、使用ASP.NET Core 构建第一个Web应用
一.前言 1.本文主要内容 Visual Studio Code 开发环境配置 使用 ASP.NET Core 构建Web应用 ASP.NET Core Web 应用启动类说明 ASP.NET Cor ...
- abp学习(四)——根据入门教程(aspnetMVC Web API进一步学习)
Introduction With AspNet MVC Web API EntityFramework and AngularJS 地址:https://aspnetboilerplate.com/ ...
随机推荐
- ajaxFileUpload文件上传
一.简介 ajaxFileUpload是一种异步的文件上传控件,通过ajax进行文件上传,并获取上传处理结果.在很多时候我们需要使用到文件上传的功能,但是不需要使用那些强大的上传插件.此时就可以使用a ...
- 手机远程调试工具spy-debugger
关于spy-debugger 1.一站式页面调试工具,远程调试任何手机浏览器页面,任何手机移动端webview(如:微信,HybirdApp等)HTTP/HTTPS.2.spy-debugger内 ...
- PHP添加Redis模块及连接
上几篇文章介绍了Redis的安装及使用,下面将介绍php如何添加Redis扩展! php手册并没有提供Redis的类和方法,也没有提供相关的扩展模块,但我们可以在Redis的官网下载PHP的扩展,里面 ...
- HTML实体对照表
HTML开发特殊字符是没办法原样输出的,必须用到实体,为了以后查看方便,收藏一下实体对照表是必要的,另外,使用<xmp></xmp>标签可以原样输出,当然,也包括特殊字符啦! ...
- Java基础の乱弹琴一:assert关键字
一.概述 assert:表示断言 二.语法 在Java中,assert关键字是从JAVA SE 1.4 引入的,为了避免和老版本的Java代码中使用了assert关键字导致错误,Java在执行的时候默 ...
- 用命令测试安装好的OpenStack环境
OpenStack三个节点icehouse-gre模式部署一文部署了一套OpenStack环境,接下来使用命令测试一遍. 首先要明确几个概念: 外网:可分配floating ip绑定到虚拟机,外部就可 ...
- Java性能调优笔记
Java性能调优笔记 调优步骤:衡量系统现状.设定调优目标.寻找性能瓶颈.性能调优.衡量是否到达目标(如果未到达目标,需重新寻找性能瓶颈).性能调优结束. 寻找性能瓶颈 性能瓶颈的表象:资源消耗过多. ...
- Eclipse 中的重构功能
Eclipse 中的重构功能使其成为了一个现代的 Java 集成开发环境 (IDE),而不再是一个普通的文本编辑器.使用重构,您可以轻松更改您的代码,而不必担心对别处造成破坏.有了重构,您可以只关注于 ...
- Google play billing(Google play 内支付) 上篇
写在前面: 最近Google貌似又被全面封杀了,幸好在此之前,把Google play billing弄完了,现在写篇 博客来做下记录.这篇博客一是自己做个记录,二是帮助其他有需要的人.因为现在基本登 ...
- css中position属性(absolute|relative|static|fixed)概述及应用
position属性的相关定义: static:无特殊定位,对象遵循正常文档流; relative:对象遵循正常文档流; absolute:对象脱离正常文档流 fixed:对象脱离正常文档流 我们先来 ...