three.js初探,立体几何入手(一)
前言:首先先推荐一篇博客,关于webgl原理,讲的非常之通俗易懂了 图解WebGL&Three.js工作原理 webGL可以理解为openGL ES2.0 (webGL2.0 - openGL ES3.0)的javascript绑定。所以实现的语言是javascript和opengl(最常用的跨平台图形库)着色语言,webgl是 HTML5中提出的新技术,是一种3D绘图标准。 three.js是以webgl为基础的库,封装了一些3D渲染需求中重要的工具方法与渲染循环。WebGL门槛相对较高,Three.js对WebGL提供的接 口进行了非常好的封装,简化了很多细节,大大降低了学习成本 我们可能还听说过一个D3.js(Data-Driven Documents),是一个数据可视化的库,技术基础是SVG。兼容性是IE9+,官网(http://d3js.org), 从官网的example中可以看出,它跟3d视图还是不同的。 |
我们只需要从官网上下载一个three.js,然后用script标签引入即可。
首先注意的一点是,我们在页面上并不需要一个canvas标签,只需要一个盛放canvas的容器就行,canvas是three.js动态生成的。
<!DOCTYPE html>
<html>
<head>
<title>01.01 - WebGLRenderer - Skeleton</title>
<script src="../libs/three.js"></script>
<style> #canvas3d{
width:800px;
height:450px;
margin:100px auto;
}
</style>
</head>
<body>
<div id="canvas3d"></div>
</body>
</html>
threejs里最重要的几个元素,如下:
<script>
var renderer; //渲染器
var scene; //场景
var camera; //相机
var light; //光源
var cube; //物体
</script>
1,生成3d渲染器,设置渲染器的宽高和背景色,(通常我们可以直接获取页面上画布的宽高,便于嵌入改动)
renderer = new THREE.WebGLRenderer({antialias:true}); //生成渲染器对象(antialias属性:抗锯齿效果为设置有效)
renderer.setClearColor(0x333333, 1.0);
//renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setSize('800', '450');
2,设置一个场景,也就是一个三维空间,用 [Scene] 类声明一个叫 [scene] 的对象。
scene = new THREE.Scene();
3,设置一个摄像机camera,
OpenGL(WebGL)中、三维空间中的物体投影到二维空间的方式中,存在透视投影和正投影两种相机。 透视投影就是、从视点开始越近的物体越大、远处的物体绘制的较小的一种方式、和日常生活中我们看物体的方式是一致的。 正投影就是不管物体和视点距离,都按照统一的大小进行绘制、在建筑和设计等领域需要从各个角度来绘制物体,因此这种投影被广泛应用。在 Three.js 也能够指定透视投影和正投影两种方式的相机。
正交投影与透视投影的区别如上图所示,左图是正交投影,物体发出的光平行地投射到屏幕上,远近的方块都是一样大的;右图是透视投影,近大远小,符合我们平时看东西的感觉。
camera坐标系
Three中使用采用常见的右手坐标系定位。
// 四个参数分别代表了摄像机的视角、宽高比、近和远两个视截面。
//设置透视投影的相机,默认情况下相机的上方向为Y轴,右方向为X轴,沿着Z轴朝里(视野角:fov 纵横比:aspect 相机离视体积最近的距离:near 相机离视体积最远的距离:far)
camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.1, 1000);
// position and point the camera to the center of the scene
camera.position.x = 20;
camera.position.y = 18;
camera.position.z = 35;
camera.lookAt(scene.position); //设置视野的中心坐标
4,设置光源light
OpenGL(WebGL)的三维空间中,存在点光源和聚光灯两种类型。 而且,作为点光源的一种特例还存在平行光源(无线远光源)。另外,作为光源的参数还可以进行 [环境光] 等设置。 作为对应, Three.js中可以设置 [点光源(Point Light)] [聚光灯(Spot Light)] [平行光源(Direction Light)],和 [环境光(Ambient Light)]。 和OpenGL一样、在一个场景中可以设置多个光源。 基本上,都是环境光和其他几种光源进行组合。 如果不设置环境光,那么光线照射不到的面会变得过于黑暗.
//设置light
light = new THREE.DirectionalLight(0xff0000, 1.0, 0); //设置平行光
light.position.set( 200, 200, 200 ); //设置光源向量
scene.add(light); // 追加光源到场景
5,设置物体 object
在three.js中,我们使用Mesh模型,Mesh的构造函数是这样的:Mesh( geometry, material ) geometry是它的形状,material是它的材质。 三维模型通常用三角形的网格来描述
对于图中的兔子,随着三角形数量的增加,它的表面越来越平滑/准确
我们这里是一个立方体 cube
var cubeGeometry = new THREE.BoxGeometry(20, 10, 15,2,3,1); //设置长宽高 以及对应长宽高的分段,在使用线模式({wireframe:true})进行渲染的时候可以看到效果
var cubeMaterial = new THREE.MeshNormalMaterial({wireframe : true}); //材质
cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
var border = new THREE.EdgesHelper( cube,0xffff00 ); //添加边框
scene.add(cube);
scene.add(border);
6,最后一步,进行渲染
//将渲染器的元素添加到页面中
document.getElementById('canvas3d').appendChild(renderer.domElement);
renderer.render(scene, camera);
完整的代码已经上传到github上: github(three-one) 如果你觉得我写的对你有所帮助的话,请给我个star吧,谢谢
最后的效果图如下:
在上面的学习基础上,我们继续深入的探究一下,如何给3d视图添加动画,纹理等;
1,首先我们在上面的基础上,添加多个立体几何图形
//立方体
var cubeGeometry = new THREE.BoxGeometry(15,15,15,1,1,1);
var cubeMaterial = new THREE.MeshNormalMaterial({wireframe : true}); //材质 cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
var border = new THREE.EdgesHelper( cube,0xffff00 ); //添加边框
scene.add(cube);
scene.add(border); //圆柱体
var cylinderGeometry = new THREE.CylinderGeometry(8, 8,10,30,30);
var cylinderMaterial = new THREE.MeshNormalMaterial();
var cylinder = new THREE.Mesh(cylinderGeometry,cylinderMaterial);
cylinder.position.x = -10;
cylinder.position.y = -5;
cylinder.position.z = 25;
cylinder.castShadow = true;
scene.add(cylinder); //球体
var sphereGeometry = new THREE.SphereGeometry(7, 25, 25);
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial); // position the sphere
sphere.position.x = 0;
sphere.position.y = 0;
sphere.position.z = 0;
sphere.castShadow = true; // add the sphere to the scene
scene.add(sphere); //圆环
var torusGeometry = new THREE.TorusGeometry(10,3,20,20);
var torusMaterial = new THREE.MeshBasicMaterial();
var tours = new THREE.Mesh(torusGeometry,torusMaterial);
tours.position.x = 10;
tours.position.y = -10;
tours.position.z = -40;
tours.castShadow = true; scene.add(tours);我们通过position属性
调整立体几何在scene中的位置(x,y,z)
创建几何体时有一点强调的是,对于参数的设置,例如创建圆环的时候,
THREE.TorusGeometry(10,3,20,20)
我们第三四个参数分割比的值越大,立体几何中拼凑的平面图形就越多,立体几何就越圆滑,就是上一篇博客中兔子的那个原理。
2,添加动画
我们要针对每个几何体添加不同的动画,所以就需要为每个几何体添加一个name属性来指定,比如:
cube.name = 'cube'; cylinder.name = 'cylinder';
然后在render函数中,用getObjectByName获取到对应的几何体,用setInterval的思想原理,通过requestAnimationFrame函数使得几何体动起来
scene.getObjectByName('cube').rotation.x += control.rotationSpeed;
scene.getObjectByName('cube').scale.set(control.scale, control.scale, control.scale); scene.getObjectByName('cylinder').rotation.z += control.rotationSpeed2; scene.getObjectByName('tours').rotation.z += 0.05;
requestAnimationFrame(render);
3,stats性能插件
stats.js用于对JavaScript进行性能检测。
我们创建一个createStats的函数,然后在init初始化中调用它
function createStats() {
var stats = new Stats();
stats.setMode(0); stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '5px'; return stats;
}
需要特别注意的一点是,我们需要在render函数中不断的更新stats显示
stats.update();
dat.gui.js用于创建菜单栏,可以用来控制场景中的各个参数来调试场景。
function addControls(controlObject){
var gui = new dat.GUI();
gui.add(controlObject,'rotationSpeed',-0.1,0.1);
gui.add(controlObject, 'scale', 0.01, 2); gui.add(controlObject, 'rotationSpeed2', -0.1, 0.1);
}
创建addControls函数,然后在init初始化函数中设置默认值,并调用这个函数
control = new function (){
this.rotationSpeed = 0.005;
this.scale = 1; this.rotationSpeed2 = 0.05;
}
addControls(control);
4,添加纹理
这个首先注意的就是图片应该是异步获取的,所以你可以放在本地的apache中,也可以自己用nodejs非常方便的搭建一个服务器,不然的话,他就会报错,跨域了。
var texture = new THREE.ImageUtils.loadTexture("http://10.1.26.29:84/Brick-2399.jpg");
torusMaterial.map = texture;
最后的效果图如下:
完整的代码:github(threejs-two) 如果你觉得我写的对你有帮助的话,请给我个star吧,谢谢,我会继续更新下去的
5,最后,从完整的代码中,我们可以看出,关于材质,我们也是调用了不同的函数,这里总结一下材质
材质种类:
MeshBasicMaterial:为几何体赋予一种简单的颜色,或者显示几何体的线框
MeshDepthMaterial:根据网格到相机的距离,该材质决定如何给网格染色
MeshNormalMaterial:根据物体表面的法向量计算颜色
MeshFaceMaterial:这是一种容器,可以在该容器中为物体的各个表面上设置不同的颜色
MeshLambertMaterial:考虑光照的影响,可以创建颜色暗淡,不光亮的物体
MeshPhongMaterial:考虑光照的影响,可以创建光亮的物体
ShaderMaterial:使用自定义的着色器程序,直接控制顶点的放置方式,以及像素的着色方式。
LineBasicMaterial:可以用于THREE.Line几何体,从而创建着色的直线
LineDashedMaterial:类似与基础材质,但可以创建虚线效果
(1)MeshBasicMaterial:不考虑光照的影响。
属性:
color
wireframe
wireframeLinewidth
wireframeLinecap:线段端点如何显示。可选值有:butt(平)、round、square。默认是round。WebGLRenderer对象不支持该属性。
wireframeLinejoin:线段连接点如何显示。可选值有:round、bevel(斜角)、miter(尖角)。默认是round。WebGLRenderer对象不支持属性。
shading:着色模式。可选值:THREE.SmoothShading、THREE.FlatShading。
vertexColors:为每个顶点定义不同的颜色。在CanvasRenderer对象中不起作用。
fog:指示当前是否会受全局雾化效果设置的影响。
两种设置属性的方式:
//1.构造函数
var meshMaterial = new THREE.MeshBasicMaterial({color:0xffccff});
//2属性
meshMaterial.visible = false;
(2)MeshDepthMaterial
使用这种材质的物体,其外观不是由光照或某个材质属性决定的;而是由物体到相机的距离决定的。可以将这种材质与其他材质相结合,从而很容易创建逐渐消失的效果。
只有两个控制线框的属性:
wireframe
wireframeLinewidth
可以通过设置相机的near和far的值,来控制创建中使用这种材质的物体的消失速度。如果near和fat之间的差值越大,那么物体远离相机时,只会稍微消失一点;反之,物体消失的效果非常明显。
var cubeMaterial = new THREE.MeshDepthMaterial();
var colorMaterial = new THREE.MeshBasicMaterial({color:0x00ff00,transparent:true,blending:THREE.MultiplyBlending}); var cube = new THREE.SceneUtils.createMultiMaterialObject(cubeGeometry,[colorMaterial,cubeMaterial]); cube.children[1].scale.set(0.99,0.99,0.99);//避免渲染遮挡而造成的闪烁
(3)MeshNormalMaterial
法向量的作用: 决定光的发射方向、在计算光照、阴影时提供信息、为物体表面上色。法向量所指的方向决定每个面从MeshNormalMaterial材质获取的颜色。
属性:
wireframe
wireframeLinewidth
shading
for(var f = 0 , f1 = sphere.geometry.faces.length; f < f1 ; f++){
var face = spere.geometry.faces[f];
var arrow = new THREE.ArrowHelper(face.normal,face.centroid,2,0x3333ff);
spere.add(arrow);
}
在球体的每个面上添加了一个长度为2,颜色为0x3333ff的箭头
(4)MeshFaceMaterial
可以为几何体的每一个面指定不同的材质。
假设有一个正方体,可以为每个面指定不同的颜色。
var matArray = [];
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00}));
matArray.push(new THREE.MeshBasicMaterial({color:0x00ff00})); var faceMaterial = new THREE.MeshFaceMaterial(matArray); var cubeGeometry = new THREE.CubeGeometry(3,3,3);
var cube = new THREE.Mesh(cubeGeometry,faceMaterial);
(5)MeshLambertMaterial
对光源有反应。
基本属性:
color、opacity、shading、blending、depthTest、depthWrite、wireframe、wireframeLineWith、wirefLinecap、wireframeLinejoin、vertexColors、fog。
独特属性:
ambient:和AmbientLight光源一起使用。该颜色会与AmbientLight光源的颜色相乘。默认是白色。
emissive:该材质发射的属性。不像是光源,只是一种纯粹的、不受其他光照影响的颜色。默认是黑色。
(6)MeshPhongMaterial
基本属性:
color、opacity、shading、blending、depthTest、depthWrite、wireframe、wireframeLineWith、wirefLinecap、wireframeLinejoin、vertexColors、fog。
独特属性:
ambient
emissive
specular:指定该材质的光亮程度及其高光部分的颜色。如果将他设置成跟color属性相同的颜色,将会得到一种更加类似金属的材质。如果设置为灰色,材质将变得更像塑料。
shininess:指定高光部分的亮度。默认是30.
(7)ShaderMaterial
属性:
wireframe
wireframeLinewidth
shading
vertexColor
fog:指示当前是否会受全局雾化效果设置的影响。
独特属性:
fragmentShader:定义每个传入的像素的颜色。
vertexShader:允许你修改每一个传入的顶点的位置
uniforms:该属性可以向你的着色器发送消息。将同样的信息发送到每一个顶点和片段。
defines:该属性可以转换为vertexShader和fragmentShader里的#define代码。该属性可以用来设置着色器程序里的一些全局变量。
attributes:该属性可以修改每个顶点和片段。常用来传递位置数据和法向量相关的数据。如果要用这个属性,辣么你要为几何体中的所有顶点提供信息。
lights:定义光照数据是否传递给着色器。默认是false。
独特属性:
fragmentShader:定义每个传入的像素的颜色。
vertexShader:允许你修改每一个传入的顶点的位置
uniforms:该属性可以向你的着色器发送消息。将同样的信息发送到每一个顶点和片段。
defines:该属性可以转换为vertexShader和fragmentShader里的#define代码。该属性可以用来设置着色器程序里的一些全局变量。
attributes:该属性可以修改每个顶点和片段。常用来传递位置数据和法向量相关的数据。如果要用这个属性,辣么你要为几何体中的所有顶点提供信息。
lights:定义光照数据是否传递给着色器。默认是false。
(8)LineBasicMaterial
基本属性:
color
lineWidth
LineCap:butt、round、square。默认是round。WebGLRenderer不支持该属性。
LineJoin:round、bevel(斜切)、miter(尖角)。默认是round。WebGLRenderer不支持该属性。
vertexColors:该属性值设置为 THREE.VertexColors值时,就可以为每个顶点指定一种颜色。
fog:指定当前物体是否受全局雾化效果的影响。
(9)LineDashedMaterial
和LineBasicMaterial有着一样的属性,但是有几个额外的属性,可以用来定义短划线长度和短划线中间空格长度的属性。
独特属性:
scale:缩放dashSize和gapSize。如果scale<1,则dashSize和gapSize就会增大。
dashSize:短线划的长度
gapSize:间隔的长度
three.js初探,立体几何入手(一)的更多相关文章
- Node.js初探之GET方式传输
Node.js初探之GET方式传输 例子:form用GET方法向后台传东西 html文件: <form action="http://localhost:8080/aaa" ...
- vue.js初探
前言 入手2016最火前端框架之一vue.js.大概从网上找了些资料看了下vue.js,从网上的资料来看只能惊叹其发展速度太快,让我意外的是其作者是华人的前提下作品这么受欢迎. 网上的博客和教程各种组 ...
- Node.js 初探
概念 Node.js 是构建在Chrome javascript runtime之上的平台,能够很容易的构建快速的,可伸缩性的网络应用程序.Node.js使用事件驱动,非阻塞I/O 模式,这使它能够更 ...
- 后端视角下的前端框架之Vue.js初探
背景 作为常年搞后端的自己来说,除了多年前学习的一点关于HTML的皮毛,对现在的前端技术栈可谓是一窍不通.但是因为最近在做的内部业务全链路监控系统,负责前端的同事做到一半去搞别的项目了,为了把项目落地 ...
- Node.js系列之node.js初探
官方介绍:Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable n ...
- [转]backbone.js 初探
本文转自:http://weakfi.iteye.com/blog/1391990 什么是backbone backbone不是脊椎骨,而是帮助开发重量级的javascript应用的框架. 主要提供了 ...
- angular.js初探
2015年7月27日 22:26:35 星期一 用在我论坛里的小栗子: 先列出来一级回帖, 点击帖子前边的"查看回复"按钮无刷新的去请求该帖子的所有回复 首先要引用js文件, 我这 ...
- Parallel.js初探续集
@author mrbean 例子均来源于github parallel.js 昨天写的第一篇今天一看居然有50+的阅读量了,感觉很激动啊,但是也有点害怕毕竟这只是自己笔记性质的一点东西,所以赶紧拿起 ...
- Parallel.js初探
今天闲着看了一下Parallel.js.这个库暂时貌似还没有什么中文的介绍(可能暂时用的人都不多吧).所以就只能上github找它得源码和介绍看看了.貌似它的代码也不多,以后可以深入研究一下. 先简单 ...
随机推荐
- pc端字体大小自适应几种方法
$(window).resize(function ()// 绑定到窗口的这个事件中 { var whdef = 100/1920;// 表示1920的设计图,使用100PX的默认值 var wH ...
- Servlet学习1
1.首先在Tomcat的webapp目录下新建文件夹myWebapp,作为自己的web应用. 2.myWebapp下新建WEB-INF(必须这个名)目录,WEB-INF下新建classes目录放置se ...
- Python结合SAP GUI Script操作sap的简易教程
众所周知,如果要用Python做一些桌面WIN32应用的自动化工作,就需要用到著名的pywin32尤其是其中的win32com.client模块,pywin32的安装不能直接通过pip install ...
- (转载)MyBatis传入多个参数的问题
原文地址:https://www.cnblogs.com/mingyue1818/p/3714162.html 一.单个参数: public List<XXBean> getXXBeanL ...
- C# 按不同的字节编码,通过字节数去截取字符串
/// <summary> /// 按不同的字节编码,通过字节数去截取字符串 /// 数据库UTF-8 1个数字.字母.英文符号算1个长度 1个中文.中文符号算3个长度 /// </ ...
- 一起ORA-00028案例的处理过程
前言 最近客户在测试新系统A时,遭遇ORA28,回话被终止的问题. 先了解一下大致环境,系统A由系统B通过rman还原恢复,应用程序已经在系统B跑批通过,现在系统A上遇到下面问题. 应用程序报错如下 ...
- laravel----------Client error: `POST http://47.98.116.219/oauth/token` resulted in a `401 Unauthorized` response: {"error":"invalid_client","message":"Client authentication failed"}
1.设备没有授权,原因是 这个client_id的值就是数据库wk_oauth_clients 的主键ID,查看下表是否有这条数据
- 接口自动化测试持续集成--Soapui接口功能测试断言
断言也就是判断实际结果与预期结果是否相等,如果相等测试通过,否则测试失败,自动化测试不管是UI,Services还有unit都需要做断言. 一.添加断言步骤的组件 二.设置断言 设置常用断言的三种方式 ...
- mysql获取连接connection失败
好久不写jdbc了,今天写了个小东西,数据库连接失败,错误信息如下: java.sql.SQLException: The server time zone value '???ú±ê×??±??' ...
- Beyond Compare相同文件为何显示差异
原文地址: http://www.beyondcompare.cc/wenti/wenjian-chayi.html Beyond Compare是一款经典老牌且优秀的专业级文本比较工具,它可以很方便 ...