Three.js的轻量级封装框架Sim.js解析(1)
2016-03-13 13:17
363 查看
这段时间在看《WebGL入门指南》,其中使用的Three.js的轻量级封装框架,本来使用Three.js框架就有点困难,还要使用Three.js的框架,OMG~~~
发牢骚归发牢骚,不看是不会懂的。初看书本上的Sim.js写出的代码,第一感觉,这都写的是啥啊。的确,要看懂这些,要求对js的面向对象的思想有一定的了解。下面是本人现学现卖总结的有关js面向对象的知识,仅供参考:
http://blog.csdn.net/birdflyto206/article/category/6121645
下面是我阅读Sim.js源码所做的笔记,由于在初步涉猎webgl,js学得也不是很好,难免会有错误的地方,请各位看官不吝指教。
如果直接读Sim.js的源码,肯定云里雾里的,所以我们对照书上第三章的第一个例子,来看Sim.js框架到底是如何运行的。
ok,至此为止,我们分析了第一个例子的运行原理。总结如下:
1.首先抽象出整个应用程序类EarthApp,继承自Sim.App,主要完成Three.js中一些变量的初始化操作,像声明render、scene、camera等,还有一些事件的订阅和发布,本例中没有用到这些 。还有就是初始化当前场景中需要渲染的物体,根据面向对象编程的思想,把这些要渲染的物体都封装在一个对象中,本例中的对象就是Earth类,该类的初始化就是在EarthApp的init方法中完成的。
2.然后抽象出自己要渲染的对象类Earth,这个对象类是一个容器,其中可以包含很多要渲染的物体,当然本例中只包含了一个贴了纹理的地球。该类的init方法的主要是定义要画的物体,本例中画的地球的几何和纹理以及包装成要画的Mesh等操作都是在该方法中完成的。
3.然后是关键的一步,就是循环重绘。Sim.js框架是通过调用Sim.App的run方法开启的,首先调用自身的update方法,当前这步是为了让物体进行简单的动画,比如绕坐标轴进行旋转。真正的循环重绘操作是通过requestAnimationFrame完成的,不断的调用run方法,run方法中调用Three.js中的render(scene,camera)方法,这样整个程序就运行起来了。
4.面向对象思想是门艺术!!!
发牢骚归发牢骚,不看是不会懂的。初看书本上的Sim.js写出的代码,第一感觉,这都写的是啥啊。的确,要看懂这些,要求对js的面向对象的思想有一定的了解。下面是本人现学现卖总结的有关js面向对象的知识,仅供参考:
http://blog.csdn.net/birdflyto206/article/category/6121645
下面是我阅读Sim.js源码所做的笔记,由于在初步涉猎webgl,js学得也不是很好,难免会有错误的地方,请各位看官不吝指教。
如果直接读Sim.js的源码,肯定云里雾里的,所以我们对照书上第三章的第一个例子,来看Sim.js框架到底是如何运行的。
//-------------earth-basic.js--------------------- //该例子是画一个地球。首先是抽象出一个EarthApp类,该类继承Sim.App类 EarthApp = function() { Sim.App.call(this);//调用父类的构造函数 } // Subclass Sim.App EarthApp.prototype = new Sim.App();//继承Sim.App的函数原型 //---------------------------Sim.js----------------------------------- //现在我们看看Sim.App的定义 // Sim.App - application class (singleton) Sim.App = function() { //Sim.App也是继承Sim.Publisher类的,该类负责管理框架中的事件订阅/发布。该例子中没有用到事件,这个后面再讲。 Sim.Publisher.call(this); //初始化一个Three.js场景中的基本对象 this.renderer = null; this.scene = null; this.camera = null; //全局app中要渲染的物体的集合 this.objects = []; } //让Sim.App.prototype指向一个Sim.Publisher对象,也就达到继承Sim.Publisher原型中所有方法和属性的目。这时js中实现继承的一种方式。 Sim.App.prototype = new Sim.Publisher; //小结:声明一个EarthApp实例,实际主要完成的操作就是声明一些Three.js场景中render、scene、camera等变量。 //-------------earth-basic.js--------------- //自定义EarthApp的初始化方法 EarthApp.prototype.init = function(param) { //调用父类的init方法完成scene、render、camera的初始化 //注意:这里的this传递进去很重要,这是js中实现继承的关键。 Sim.App.prototype.init.call(this, param); // 创建一个Earth对象,由于我们是画一个地球,根据OOP的思想,将其抽象为一个Earth对象,该对象继承Sim.js框架中的Sim.Object对象 var earth = new Earth(); //调用Earth对象的init方法 earth.init(); //将earth对象的实例添加上到EarthApp中 this.addObject(earth); } //---------------------------Sim.js----------------------------------- //Sim.App的init方法 //因为自定义的EarthApp调用父类的init方法传递的是其代表其本身的this,所以,父类init方法中的所有this相关的操作都被映射为EarthApp的操作。说得简单点,现在Sim.App中的this代表的是EarthApp。这样EarthApp就可以不会吹灰之力继承父类init方法中的所有操作,而不必自己再实现一遍,这就是Sim.js框架的目的所在。 //现在我们看看,Sim.App的init方法中干了些什么。 Sim.App.prototype.init = function(param) { //传递的param是一个json对象 param = param || {}; var container = param.container; var canvas = param.canvas; // 初始化在Sim.App构造函数中定义的一些场景元素 var renderer = new THREE.WebGLRenderer( { antialias: true, canvas: canvas } ); renderer.setSize(container.offsetWidth, container.offsetHeight); container.appendChild( renderer.domElement ); // Create a new Three.js scene var scene = new THREE.Scene(); scene.add( new THREE.AmbientLight( 0x505050 ) ); //为scene动态添加一个属性data,指向EarthApp(子类对象),这个还不知道是干什么的,后面再说。 scene.data = this; // 初始化相机 camera = new THREE.PerspectiveCamera( 45, container.offsetWidth / container.offsetHeight, 1, 10000 ); camera.position.set( 0, 0, 3.3333 ); scene.add(camera); // 创建一个Object3D对象,Object3D对象是Sim.Object对象的一个属性,这个类会在后面讲到。该属性一般存储的是一个将要绘制的对象,一般是一个Mesh。例如本例中,Object3D对象就是一个球体和材质组合的Mesh对象。该属性是通过setObject3D函数完成的。 var root = new THREE.Object3D(); scene.add(root); // 创建一个工具类,用于完成在Three.js鼠标拾取对象。 var projector = new THREE.Projector(); // 保存一些变量到全局对象的属性中,为了方便在任何地方能够访问到。 this.container = container; this.renderer = renderer; this.scene = scene; this.camera = camera; this.projector = projector; this.root = root; // 设置事件相关的句柄。这里先跳过。 this.initMouse(); this.initKeyboard(); this.addDomHandlers(); } //小结:earth-basic.js中这段代码主要完成的任务就是初始化一些Three.js场景中的基本元素,如scene、camera、render等。 //下面看看自定义的Earth对象 //---------earth-basic.js------------------ // Custom Earth class Earth = function() { Sim.Object.call(this);//继承Sim.Object } Earth.prototype = new Sim.Object(); //这里Earth的init方法没有调用父类的init方法,为什么呢? //我们看下Sim.js的源码,发现Sim.Object的init方法为空 Earth.prototype.init = function() { //下面是Three.js中的操作 // Create our Earth with nice texture var earthmap = "../images/earth_surface_2048.jpg"; var geometry = new THREE.SphereGeometry(1, 32, 32); var texture = THREE.ImageUtils.loadTexture(earthmap); var material = new THREE.MeshBasicMaterial( { map: texture } ); var mesh = new THREE.Mesh( geometry, material ); // Let's work in the tilt mesh.rotation.x = Earth.TILT; // 将Mesh对象作为Object3D传递给Sim.js框架 // 这里的this指的是什么? // 对,就是Earth类,而Earth对象我们并没有定义setObject3D方法啊?对,这个方法是继承父类Sim.Object的,我们看看父类中的setObject3D方法,其实就是mesh对象赋值给Sim.Object类的Object3D属性。 this.setObject3D(mesh); } Earth.prototype.update = function() { // "I feel the Earth move..." this.object3D.rotation.y += Earth.ROTATION_Y;//这里的Object3D就是Mesh对象,因为前面已经 this.setObject3D(mesh); 结合Sim.js源码 } Earth.ROTATION_Y = 0.0025; Earth.TILT = 0.41; //--------Sim.js--------- //此案例中Object3D对象传递进来的就是一个包含了纹理的地球Mesh对象 Sim.Object.prototype.setObject3D = function(object3D) { object3D.data = this; this.object3D = object3D; } //然后在主页面中是这么调用框架的 $(document).ready( function() { var container = document.getElementById("container"); var app = new EarthApp();//自定义的EarthApp对象,表示整个应用程序 app.init({ container: container }); app.run(); } ); //看看app.run()方法 Sim.App.prototype.run = function() { this.update();//首先调用刷新界面的方法 this.renderer.render( this.scene, this.camera );//Three.js中的render方法 var that = this;//保存Sim.App的引用。 requestAnimationFrame(function() { that.run(); }); } Sim.App.prototype.update = function() { var i, len; len = this.objects.length; //循环当前场景中的所有的物体,让其全部重绘。重绘的方法是子类自己实现的。 //该类中Earth对象的update方法就是不断的更改其绕y轴旋转的角度,以达到旋转动画的目的。 for (i = 0; i < len; i++) { this.objects[i].update();//每个自定义的Object对象必须有update方法,可以在该方法中完成旋转动画等。 } }
ok,至此为止,我们分析了第一个例子的运行原理。总结如下:
1.首先抽象出整个应用程序类EarthApp,继承自Sim.App,主要完成Three.js中一些变量的初始化操作,像声明render、scene、camera等,还有一些事件的订阅和发布,本例中没有用到这些 。还有就是初始化当前场景中需要渲染的物体,根据面向对象编程的思想,把这些要渲染的物体都封装在一个对象中,本例中的对象就是Earth类,该类的初始化就是在EarthApp的init方法中完成的。
2.然后抽象出自己要渲染的对象类Earth,这个对象类是一个容器,其中可以包含很多要渲染的物体,当然本例中只包含了一个贴了纹理的地球。该类的init方法的主要是定义要画的物体,本例中画的地球的几何和纹理以及包装成要画的Mesh等操作都是在该方法中完成的。
3.然后是关键的一步,就是循环重绘。Sim.js框架是通过调用Sim.App的run方法开启的,首先调用自身的update方法,当前这步是为了让物体进行简单的动画,比如绕坐标轴进行旋转。真正的循环重绘操作是通过requestAnimationFrame完成的,不断的调用run方法,run方法中调用Three.js中的render(scene,camera)方法,这样整个程序就运行起来了。
4.面向对象思想是门艺术!!!
相关文章推荐
- JQuery1——基础($对象,选择器,对象转换)
- Android学习笔记(二九):嵌入浏览器
- Android java 与 javascript互访(相互调用)的方法例子
- JavaScript演示排序算法
- javascript实现10进制转为N进制数
- 最后一次说说闭包
- Ajax
- 2019年开发人员应该学习的8个JavaScript框架
- HTML中的script标签研究
- 对一个分号引发的错误研究
- 异步流程控制:7 行代码学会 co 模块
- ES6 走马观花(ECMAScript2015 新特性)
- JavaScript拆分字符串时产生空字符的原因
- Canvas 在高清屏下绘制图片变模糊的解决方法
- Redux系列02:一个炒鸡简单的react+redux例子
- JavaScript 各种遍历方式详解
- call/apply/bind 的理解与实例分享