webGL是基于OpenGL的Web3D图形规范,是一套JavaScript的API。简单来说,可以把它看成是3D版的canvas。恩,你会这样引入canvas对吧:

canvas = document.getElementById("xxx");
ctx = canvas.getContext("2d");

SO,3D版本的就酱:

canvas = document.getElementById("xxx");
gl = canvas.getContext("experimental-webgl");

是的,webGL直接使用canvas元素,只是引入一个不同的上下文“experimental-webgl”,方便吧。

这里的上下文实际上应该是.getContext("webgl"),但由于现在webgl标准尚未完善,所以多数浏览器采用一个“试验性”的上下文

让我们先啰嗦一些玩意儿

3D坐标系

这个玩意儿大家都认识吧不多啰嗦了

这里y轴跟canvas是逆向的,这是一个右手坐标系

网格、多边形和顶点

网格(Mesh)是绘制3D图形的一种方法,它是由一个或多个多边形组成的物体,每个顶点的坐标(x,y,z)定义了多边形在3D空间中的位置,这里的多边形通常是三角形和四边形。网格用来描述物体形状。恩,大概......也许......差不多......长这样:

材质、纹理和光源

贴个骷髅头什么的最嗨森了。但仅仅这样是然并卵的,为什么?因为现在毛都看不见。诶不带丢鸡蛋的,诶卧槽你再丢!

为什么说看不见呢,因为视觉是光作用于视网膜细胞所产生的大脑认知,所以我们需要,还需要能反射光的表面。这样网格才能看得见

于是有:

  • 纹理映射(texture map) :物体表面对光的反射,颜色及光泽度等,常由位图来决定。
  • 光源(light) :顾名思义就是闪瞎你的那个东西。常用有环境光、点光源、平行光等,物体表面对光的反射还有环境反射、镜面反射和漫反射。
  • 材质(material) :网格表面的特性的统称。

变换和矩阵

网格的形状是由顶点决定的,而我们做的是动画,难道动画每一帧要重新定义所有网格的所有顶点?显然是不可取的,所以我们需要变换(transform)。变换是不需要遍历每个顶点就可以移动网格的操作,需要由矩阵(matrix)来操作。

类似介种:

相机、透视、视口和投影

我们生活在三维世界中,但是用眼睛只能看到二维的图像。同样的,三维的网格要能够看见,需要渲染成二维图像。

好多好多的概念:

  • 场景(scene) :容纳一切的容器
  • 相机(camera) :就是你在webGL世界里面的眼睛呐。
  • 视口(viewport) :想想浏览器的视口的概念,对,就是3D场景渲染的二维图像,也就是你从浏览器的canvas元素上看到的。
  • 视野(field of view) :相机可见范围左右边界的夹角。
  • 视锥体(view frustum) :物体可以被渲染到视口的空间,换句话说,只有处于视锥体空间内部的物体,才可以被看见。
  • 近裁剪面(near clipping plane) :视锥体靠近相机的一面,其实就是视口。
  • 远裁剪面(far clipping plane) :视锥体最远离相机的平面。

太君别开枪!我知道你最讨厌一大片的概念了,来看图:

这样清楚了吧~~~ ?(终于啰嗦完了......)

数学真难

概念讲完了是不是该开搞了呢?诸位看官别急,且听小生慢慢道来。

大家明白,模拟三维空间,需要非常多的计算,网格的坐标、大小、角度,网格的平移、旋转,相机观察网格的二维映射等等等等。

前方高能(学霸请无视这一行)

《线性代数》乱入:

前面说了,网格由N个多边形构成,实际上就是由多边形的顶点集合构成。顶点是一个向量,而向量可以用一个三维坐标(x, y, z)来表示。矢量之间存在加法、减法、点乘、叉乘运算。(作者抱着《线性代数》一顿狂翻......)

到这里有没有发现一个问题?就是向量和坐标的表示方法是一样的。于是这里引入齐次坐标(w)来区分,w=0,则表示向量,否则表示点。于是我们的向量就长这样:(x, y, z, w)。值得一提的是,齐次坐标表示方法不唯一,(x, y, z, w)跟(x/w, y/w, z/w, 1)表示同一个点,后者为齐次坐标的正常化处理。eg: (15, 12, 9, 3)跟(5, 4, 3, 1)并没有什么区别,都表示三维点(5, 4, 3)。(作者抱着《线性代数》又是一顿狂翻......)

所谓齐次坐标就是将一个原本是n维的向量用一个n+1维向量来表示——百度百科

http://baike.baidu.com/link?url=qKIV6kEiCXE-MEdwSFvI3Ew6XkDwoOywt_6oYG8Nu6tdThO1EF9heuS8MDQpujJbXyDErMPsDYBiGNj3FqL9l_

向量坐标说完了,各位看官还记得向量运算的好朋友——矩阵么?什么?不记得?请跟作者一起抱着《线性代数》一顿狂翻......

具体矩阵计算就不细说了,大致有这几个:加法减法乘法求逆转置

Waring:矩阵的乘法 不满足 乘法交换律,所以还分 左乘右乘

我知道各位看官要丢鸡蛋了,讲这么半天线性代数到底有什么卵用啊?恩且慢动手。接下来我们要说重要的东西了。

仿射变换

仿射变换:大概就是对原坐标做一些羞羞的事情然后获取他们新坐标的值。

下面图略丑请凑合看

平移

平移矩阵长这样,tx, ty, tz为位移向量,比如(tx, ty, tz)=(3,2,0),则平移变换效果如下图:

旋转

旋转三个矩阵,分别对应x、y、z轴,这个坐标轴遵循右手法则,右手法则就是:

那么比如我们绕z轴旋转,使用上面的第三个矩阵,旋转90度,效果这样:

缩放

这个运算看上去简单多了对吧嘿嘿嘿

注:上述仿射变换均是用对应的仿射矩阵 左乘 齐次坐标得到结果

好了,讲了半天这个那个矩阵的,《线性代数》已经被学渣作者翻烂,不知道各位看官是什么感觉(学霸:so easy!)

那么问题来了,难道玩图形学的人们天天搞矩阵?不!这不科学!一定不是这样的!程序员是一类神奇的生物,凡是遇到觉得很烦躁很麻烦的东西,都会创造另外一些东西让他们不烦躁不麻烦。这个“另外一些东西”就是:

正经开搞

好了我们要开始创造天与地了,不要担心,我们不会去算矩阵的,难道肚子饿了还要先插秧吗?webGL已经有那么些封装很好的引擎了,这些引擎能够帮助开发者规避矩阵计算等复杂的操作,让你能够专注于天地的创造。这里我们使用Three.js。

Three.js 是一个js编写的第三方库,运行在浏览器中,提供场景、相机、光照、材质等各种对象——http://threejs.org/

首先我们创建一个渲染器并添加到页面上

antialias是一个抗锯齿参数,我们设置了渲染器的宽高,简单吧。

渲染器有了我们就可以渲染场景了,然后往里面丢各种东西,想想还有点小激动呢。建场景就一行

现在世界已经从一片混沌变成天地初开了,我们需要一双发现真善美的眼睛——相机

Three.js最主要的相机一个是正投影相机(OrthographicCamera),这个相机是“上帝视角”,为啥说是上帝视角,因为东西是啥样他看着就是啥样儿。恩,我这样说我知道你肯定没听懂。没事儿我们继续看。

另一个就是我们这里用到的了,透视投影相机(PerspectiveCamera) (并不能把穿了衣服的看成没穿衣服的)。透视投影有一个基本点,远处的物体比近处的物体小。这就是与正投影的区别。还记得前面讲透视时候的那个图吗?

看上面的几个参数,CONST.FIELD_OF_VIEW——视野角度,第二个是宽高比,然后远近裁剪面,想起来了吧~~~

最后把它放在(0, 0, 3)的地方,偶吼吼,盘古大婶睁眼了。

不过现在睁眼然并卵啊,上帝说:要有光!

这里我们创造一组平行光,因为照亮世界的是太阳,物理学角度来说通常把太阳光看成是平行光。

除此之外还有环境光、区域光、点光源和聚光灯。

万事俱备,我们要开始开天辟地的辟地了。

我们先创造一个几何球体(当然同理还有CubeGeometry等等),三个参数,第一个是球体半径,后两个分别是球体在两个方向上的几何精度(其实就是每条线上用多少个顶点描述),这里的横向和纵向都设置为64个顶点。

接下来是定义材质,为了效果更逼真,我们使用着色器来定义材质,需要三张贴图,分别是:

  • 漫反射贴图 :即颜色贴图
  • 法线贴图 :描述材质的凹凸程度
  • 高光贴图 :描述材质的反光效果

这里我们拿到网上有一套非常清晰的地球的图(从左往右依次是法线贴图、高光贴图、漫反射贴图)

只要有了漫反射贴图,我们就可以通过 PixPlant 软件来生成其法线贴图和高光贴图,效果嘛,还行。

我们拿两张来试试,分别是木星和金星的漫反射贴图

经过PixPlant的处理后得到下面几张。是不是很爽?

好我们开始把贴图做成纹理

通过读取图片做成纹理映射,然后把纹理映射给到着色器材质

最后用几何体跟材质生成网格,并倾斜一个小角度方便我们瞅着它

把网格添加到场景中

这样“辟地”就弄好了

是不是感觉跟平常看到的不太一样?

对啊卧槽云呢?咱们的星球那么漂亮,要有云哇!

相同的步骤,我们再做一个网格。只不过这里我们不再需要着色器材质了,因为云层不需要高光法线这些东西。我们使用兰伯特(Lambert)材质,这个材质的特点是无论观察者角度如何变化,它的表面亮度都一样。这个性质用来做我们的云层最棒了。然后我们还要把云层网格设为透明,让它“罩”在地球上,转动比地球快一丢丢,更接近真实。

好了,最后我们使用requestAnimationFrame()函数来让它转起来!

requestAnimationFrame函数是专为脚本动画创建的,使用它可以让浏览器来自动控制动画的最佳帧频,提升性能、节省电能。在这一点上它比setTimeout和setInterval函数更好。

最后大功告成

完整代码

/**  build by rhj 2015/09/27*/
function World(id){//各部件Objthis.container = document.getElementById(id);this.renderer  = null;this.scene     = null;this.camera    = null;this.light     = null;this.world     = null;this.cloud     = null;//常量this.constObj  = {ANGLE_INCLINED      : Math.PI / 6,ROTATION_WORLD_RATE : 0.001,ROTATION_CLOUD_RATE : 0.0012,FIELD_OF_VIEW       : 45,NEAR_CLIPPING_PLANE : 1,FAR_CLIPPING_PLANE  : 10,WORLD_SHININESS     : 15,//云层高约10km,地球半径6371km,云层球体半径R=(6371+10)/6371≈1.0016WORLD_RADIUS        : 1,CLOUD_RADIUS        : 1.0016,GLOBE_RESOLUTION    : 64}
}World.prototype.initRender = function(){var container = this.container;var renderer  = null;renderer = new THREE.WebGLRenderer({antialias: true});renderer.setSize(container.offsetWidth, container.offsetHeight);this.renderer = renderer;this.container.appendChild( this.renderer.domElement );
}World.prototype.initScene = function(){this.scene = new THREE.Scene();
}World.prototype.initCamera = function(){var container = this.container;var CONST     = this.constObj;var camera    = null;camera = new THREE.PerspectiveCamera(CONST.FIELD_OF_VIEW, container.offsetWidth/container.offsetHeight,CONST.NEAR_CLIPPING_PLANE, CONST.FAR_CLIPPING_PLANE);//相机坐标camera.position.set(0, 0, 3);this.camera = camera;this.scene.add(this.camera);
}World.prototype.initLight = function(){var light = null;light = new THREE.DirectionalLight(0xffffff, 1.5);//光源坐标light.position.set(0, 0, 1);this.light = light;this.scene.add(this.light);
}World.prototype.initWorld = function(){var shader   = null;var uniforms = null;var material = null;var geometry = null;var CONST = this.constObj;var surfaceMap  = THREE.ImageUtils.loadTexture("images/earth_surface.jpg");var normalMap   = THREE.ImageUtils.loadTexture("images/earth_normal.jpg");var specularMap = THREE.ImageUtils.loadTexture("images/earth_specular.jpg");shader   = THREE.ShaderUtils.lib["normal"];uniforms = THREE.UniformsUtils.clone(shader.uniforms);//法线贴图、漫反射贴图、高光贴图uniforms["tNormal"].texture   = normalMap;uniforms["tDiffuse"].texture  = surfaceMap;uniforms["tSpecular"].texture = specularMap;uniforms["enableDiffuse"].value  = true;uniforms["enableSpecular"].value = true;//物体表面光滑度uniforms["uShininess"].value = CONST.WORLD_SHININESS;//着色器material = new THREE.ShaderMaterial({fragmentShader : shader.fragmentShader,vertexShader   : shader.vertexShader,uniforms       : uniforms,lights         : true});//球体网格(半径、纬线顶点数、经线顶点数)geometry = new THREE.SphereGeometry(CONST.WORLD_RADIUS, CONST.GLOBE_RESOLUTION, CONST.GLOBE_RESOLUTION);geometry.computeTangents();world = new THREE.Mesh(geometry, material);world.rotation.x = CONST.ANGLE_INCLINED;world.rotation.y = CONST.ANGLE_INCLINED;this.world = world;this.scene.add(this.world);
}World.prototype.initCloud = function(){var cloudsMap      = null;var cloudsMaterial = null;var cloudsGeometry = null;var CONST = this.constObj;cloudsMap      = THREE.ImageUtils.loadTexture("images/earth_clouds.png");cloudsMaterial = new THREE.MeshLambertMaterial({color: 0xffffff, map: cloudsMap, transparent: true});//云层球体网格(半径、纬线顶点数、经线顶点数)cloudsGeometry = new THREE.SphereGeometry(CONST.CLOUD_RADIUS, CONST.GLOBE_RESOLUTION, CONST.GLOBE_RESOLUTION);cloud          = new THREE.Mesh(cloudsGeometry, cloudsMaterial);cloud.rotation.y = CONST.ANGLE_INCLINED;this.cloud = cloud;this.scene.add(this.cloud);
}World.prototype.build = function(){this.initRender();this.initScene();this.initCamera();this.initLight();this.initWorld();this.initCloud();
}World.prototype.rotate = function(self){var CONST = self.constObj;self.renderer.render(self.scene, self.camera);self.world.rotation.y += CONST.ROTATION_WORLD_RATE;self.cloud.rotation.y += CONST.ROTATION_CLOUD_RATE;requestAnimationFrame( function(){ self.rotate(self); } );
}

线上演示地址:http://rhj1122.github.io/webgl/

前端新玩具——webGL简介相关推荐

  1. Tim Berners-Lee重新分散的新Web SOLID简介

    by Arnav Bansal 通过Arnav Bansal Tim Berners-Lee重新分散的新Web SOLID简介 (An introduction to SOLID, Tim Berne ...

  2. 第一章 WebGL简介 Introduction

    第一章 WebGL简介 Introduction 概述 webGL是一组用于在web html上下文中绘制3D图像的web接口 html Canvas对象所有绘制图像的舞台,通过使用CanvasRen ...

  3. 今天给大家推荐一个深挖国内外前端新领域的前端社区

    印记中文(docschina.org)社区致力于打造良好的中文社区环境,我们有着官方授权的中文文档维护及管理权,包括但不限于 React.webpack 等.同时我们推出了 webpack 文档更新期 ...

  4. Unity3D for VR 学习(1): 又一个新玩具 暴风魔镜 4(Android)

    2016年伊始,有了VR虚拟现实硬件设备:  暴风魔镜4–好奇者的新玩具 . 2015年下半年的朋友圈中各种VR.AR的新闻层次不穷,搞的我也心痒痒的:好歹咱也是职业的Unity3D程序员,高大上的O ...

  5. 微型计算机是台式机,#有货自远方来# 黑五买的新“玩具” — Intel 英特尔 NUC5PPYH 微型电脑...

    #有货自远方来# 黑五买的新"玩具" - Intel 英特尔 NUC5PPYH 微型电脑 2015-12-31 17:07:04 22点赞 89收藏 63评论 混迹于倡导" ...

  6. 乐迪智能陪伴机器人_乐迪陪伴机器人 孩童在智能时代的新玩具

    0 乐迪陪伴机器人 孩童在智能时代的新玩具 2016-08-04 08:39 乐迪机器人定位为"学龄前儿童陪伴机器人",搭载了图灵机器人开发的Turing OS操作系统,具备语音识 ...

  7. 前端JavaScript(1) --Javascript简介,第一个JavaScript代码,数据类型,运算符,数据类型转换,流程控制,百度换肤,显示隐藏...

    一.Javascript简介 Web前端有三层: HTML:从语义的角度,描述页面结构 CSS:从审美的角度,描述样式(美化页面) JavaScript:从交互的角度,描述行为(提升用户体验) Jav ...

  8. zabbix前端php界面,zabbix简介及安装

    第一部分简介 1.1Zabbix简介 Zabbix是一个企业级的开源分布式监控解决方案,由一个国外的团队持续维护更新,软件可以自由下载使用,运作团队靠提供收费的技术支持赢利. 官方网站: Zabbix ...

  9. 如何高效学习前端新知识,拓展视野,我推荐

    技术日新月异,发展迅速,作为一个与时俱进的互联网人,需要不断地学习扩宽视野. 今天为大家推荐几个技术领域中出类拔萃的公众号,它们的每一篇推文都值得你点开! 1 前端开发爱好者 学习路线 数据结构算法  ...

最新文章

  1. oracle valueerror,Oracle VALUE_ERROR异常(挑战题编号000005)
  2. 启动 ServiceFabric Windows服务报1053
  3. Ubuntu E: Unable to locate package错误解决办法
  4. 3.10 触发字检测-深度学习第五课《序列模型》-Stanford吴恩达教授
  5. fzu 2139 久违的月赛之二
  6. CF#1288A Deadline (函数求最值问题)
  7. 设置css3动画的顺序,CSS3 “瓷砖”顺序飘落的动画
  8. 与Netflix合作 美电视运营商推出4K频道
  9. 通过getSystemServices获取手机管理大全
  10. Pycharm中运行Python代码的几种方式
  11. python自编信息加密函数_自定义Python加密算法
  12. ScrollView详解
  13. [轉]winrar的命令行
  14. docker 部署 gitlab最新版本( 当前 11.8.1通过验证)
  15. 跑跑卡丁车Bingo喜当托儿纪念,2022/04/30,23:38:56
  16. 《窈窕绅士》里的诗句
  17. 红罐王老吉品牌定位战略
  18. NAC(网络准入控制)实施案例(20100531)
  19. macos修改WIFI共享功能的默认网段
  20. MATLAB 多元线性回归(regress)

热门文章

  1. asa 防火墙拦截了https_防火墙(ASA)的基本配置与远程管理
  2. GreenDao使用CRUD及数据库结构升级
  3. Vista优化大师更新历史:
  4. 一次简单的计网实践——浅谈校园网认证原理、ipv6机制绕过认证限制、双路由器宿舍组网
  5. C语言如何判断中文符号(简单和原理包中文括编码大全和中文符号)
  6. 复杂网络概论----复杂网络分析(三)
  7. C#将数组转换为字符串,且将字符串分割存入数组中
  8. win7家庭版远程桌面补丁_无需惊慌!微软漏洞数月后再被“预警” 打补丁即可防御...
  9. VisualSVN 插件,专业高效地使用 Subversion 来处理问题
  10. 干掉iTerm,号称下一代 Terminal 终端神器,用完爱不释手