CC6开发应用教材基础篇

yanrongzhu 贡献于2010-12-26

作者 微软用户  创建于2009-03-05 03:06:00   修改者captain  修改于2010-05-21 02:22:00字数130257

文档摘要:虚拟现实,英文名为Virtual Reality,简称VR技术。这一名词是由美国VPL公司创建人拉尼尔(Jaron Lanier)在80年代初提出的,也称灵境技术或人工环境。作为一项尖端科技,虚拟现实集成了计算机图形技术、计算机仿真技术、人工智能、传感技术、显示技术、网络并行处理等技术的最新发展成果,是一种由计算机生成的高技术模拟系统,它最早源于美国军方的作战模拟系统,九十年代初逐渐为各界所关注并且在商业领域得到了进一步的发展。这种技术的特点在于计算机产生一种人为虚拟的环境,这种虚拟的环境是通过计算机图形构成的三维数字模型,并编制到计算机中去生成一个以视觉感受为主,也包括听觉、触觉的综合可感知的人工环境,从而使得在视觉上产生一种沉浸于这个环境的感觉,可以直接观察、操作、触摸、检测周围环境及事物的内在变化,并能与之发生“交互”作用,使人和计算机很好地“融为一体”,给人一种“身临其境”的感觉。 
关键词:

 第一章 虚拟现实概论 6 第一节 什么是虚拟现实 6 第二节 网络与虚拟现实技术的发展 7 第三节 Web3D闪亮登场 8 第二章 Lyinux基础知识 9 第一节 2D与3D 9 第二节 3D世界是如何描述的 11 一、 空间位置 11 二、 视觉效果 12 三、 运动状态 13 第三节 有关Lyinux 13 一、 Lyinux的应用: 14 二、 Lyinux的特点 14 三、 Lyinux与互联网 15 第四节 Lyinux 基本概念 15 一、 CC6浏览器中的计量单位 15 二、 LYINUX的数据类型与域 16 三、 域类型 17 四、 3d建模工具导出资源 18 五、 小结 19 第三章 创建造型 20 第一节 简单造型 20 一、 Box 20 二、 Cube 20 三、 Sphere 21 四、 Cylinder 21 五、 Cone 22 第二节 复杂造型 22 一、 文本造型 22 二、 轮廓挤出节点 25 第三节 通用造型 25 一、 PointSet点集 26 二、 IndexedLineSet线集 27 三、 IndexedFaceSet面集 29 第四章 材质外观节点 31 第一节 材质类节点 31 一、 材质节点 31 二、 色彩节点 32 第二节 纹理类节点 33 一、 固有色纹理 33 二、 视频纹理MovieTexture 36 三、 网页纹理HtmlTexture 37 四、 凹凸纹理 39 五、 纹理文件格式 39 第三节 纹理变换 41 一、 纹理变换节点 41 二、 纹理坐标类节点 44 第五章 环境设计 46 第一节 创建背景 46 第二节 摄像机 48 一、 默认摄像机 48 二、 透视摄像机 48 三、 平截体摄像机 49 四、 平行摄像机 50 五、 导航节点NavigationInfo 51 第三节 灯光节点 54 一、 点光源 54 二、 平行光源 58 三、 锥光源 61 第四节 声音节点 65 一、 声音 65 二、 音频剪辑 66 第五节 雾化节点 67 第六节 环境光雾节点 69 第六章 组节点 69 第一节 Separator 69 第二节 Group 70 第三节 Transform 71 第四节 TransformSeparator 72 第五节 Billboard 73 第六节 MultipleCopy 75 第七节 Geo系列节点 78 一、 GeoCoordinate 78 二、 GeoSeparator 78 三、 GeoOrigin 78 四、 GeoLocation 79 第八节 细节层次控制 80 一、 LOD 81 二、 LevelOfDetail 84 第九节 小结 85 第七章 动画节点 85 第一节 事件和路由的基本概念 85 第二节 时间传感器 86 一、 TimeSensor 86 二、 DrawSensor 87 第三节 坐标系变换类 88 一、 PositionInterpolator 88 二、 OrientationInterpolator 89 第四节 参数变换类 91 一、 SCALARINTERPOLATOR 91 二、 COLORINTERPOLATOR 94 第五节 坐标插补器 96 第六节 法向量插补器 98 第八章 骨骼节点 100 第一节 骨骼动画介绍 100 第二节 Bone 100 第三节 BoneInstance 101 第九章 传感器节点 102 第一节 TouchSensor 102 第二节 PlaneSensor 105 第三节 CylinderSersor 106 第四节 SphereSensor 110 第五节 ProximitySensor 111 第六节 VisibilitySensor 112 第七节 高亮节点 112 第八节 输入控制节点 113 一、 响应键盘鼠标按键消息 113 二、 响应鼠标在屏幕中移动的轨迹消息 119 第九节 变换操作节点 121 一、 Dragger系列节点 121 二、 Manip操作器系列 122 三、 Controller控制器系列 128 第十章 脚本 133 第一节 Script 133 第二节 Javascript 134 一、 变量的声明和使用 134 二、 常用运算符和类 134 三、 程序控制流 140 四、 函数 142 第三节 脚本的运用 142 第四节 扩展函数——自定义光标 145 第五节 常用全局函数介绍 148 一、 print与alert函数 149 二、 fullScreen函数 149 三、 thisNode函数 149 四、 setTimeout函数 152 五、 获得当前用户信息函数 153 第六节 SFNode类的使用 153 第七节 VrmlMatrix类的使用 160 第八节 JavaScript的数据类型 161 第十一章 GUI二维界面 168 第一节 3D场景中的2D元素 168 一、 Text2 168 二、 Image 168 第二节 图形用户界面GUI 168 第十二章 虚拟现实结构体系 183 第一节 内联节点 183 第二节 原型 185 一、 原型定义 185 二、 原型调用 186 第三节 原型与内联节点的区别 186 第四节 原型构成体系 186 第十三章 客户端与服务器端的通信 187 第一节 WWWAnchor 187 第二节 Form节点 188 第三节 Update节点 196 第四节 NetSyncer节点 196 术语表 198 参考文献 198 概论篇 第一章 虚拟现实概论 第一节 什么是虚拟现实 虚拟现实,英文名为Virtual Reality,简称VR技术。这一名词是由美国VPL公司创建人拉尼尔(Jaron Lanier)在80年代初提出的,也称灵境技术或人工环境。作为一项尖端科技,虚拟现实集成了计算机图形技术、计算机仿真技术、人工智能、传感技术、显示技术、网络并行处理等技术的最新发展成果,是一种由计算机生成的高技术模拟系统,它最早源于美国军方的作战模拟系统,九十年代初逐渐为各界所关注并且在商业领域得到了进一步的发展。这种技术的特点在于计算机产生一种人为虚拟的环境,这种虚拟的环境是通过计算机图形构成的三维数字模型,并编制到计算机中去生成一个以视觉感受为主,也包括听觉、触觉的综合可感知的人工环境,从而使得在视觉上产生一种沉浸于这个环境的感觉,可以直接观察、操作、触摸、检测周围环境及事物的内在变化,并能与之发生“交互”作用,使人和计算机很好地“融为一体”,给人一种“身临其境”的感觉。  虚拟现实的特点 虚拟现实有三大特点:浸沉感、交互性和构想性。由于三者的英文名称均以“I”打头,又被称为3“I”特性。浸沉感指的是人浸沉在虚拟环境中,具有和在真实环境中一样的感觉;交互性指在虚拟环境中体验者不是被动地感受,而是可以通过自己的动作改变感受的内容;构想性指虚拟的环境是人构想出来的,因而可以用以实现一定目标的用途。 虚拟现实的种类 虚拟现实系统按其功能高低大体可分为四类:一是桌面虚拟现实系统,也称窗口中的VR。它可以通过桌上型机实现,所以成本较低,功能也最简单,主要用于CAD(计算机辅助设计)、CAM(计算机辅助制造)、建筑设计、桌面游戏等领域。二是沉浸虚拟现实系统,如各种用途的体验器,使人有身临其境的感觉,各种培训、演示以及高级游戏等用途均可用 这种系统。三是分布式虚拟现实系统,它在因特网环境下,充分利用分布于各地的资源,协同开发各种虚拟现实的利用。它通常是浸沉虚拟现实系统的发展,也就是把分布于不同地方的沉浸虚拟现实系统,通过因特网连接起来,共同实现某种用途。美国大型军用交互仿真系统NPSNet以及因特网上多人游戏MUD便是这类系统。四是增强现实又称混合现实系统。它是把真实环境和虚拟环境结合起来的一种系统,既可减少构成复杂真实环境的开销(因为部分真实环境由虚拟环境取代),又可对实际物体进行操作(因为部分系统是真实环境),真正达到了亦真亦幻的境界,是今后发展的方向。 虚拟现实的特点与重要意义 虚拟现实是发展到一定水平上的计算机技术与思维科学相结合的产物,它的出现为人类认识世界开辟了一条新途径。虚拟现实的最大特点是:用户可以用自然方式与虚拟环境进行交互操作,改变了过去人类除了亲身经历,就只能间接了解环境的模式,从而有效的扩展了自己的认知手段和领域。另外,虚拟现实不仅仅是一个演示媒体,而且还是一个设计工具,它以视觉形式产生一个适人化的多维信息空间,为我们创建和体验虚拟世界提供了有利的支持。 由于虚拟现实技术的实时三维空间表现能力、人机交互式的操作环境以及给人带来的身临其境的感受,它在军事和航天领域的模拟和训练中起到了举足轻重的作用。近年来,随着计算机硬件软件技术的发展以及人们越来越认识到它的重要作用,虚拟技术在各行各业都得到了不同程度的发展,并且越来越显示出广阔的应用前景。虚拟战场、虚拟城市、甚至“数字地球”;无一不是虚拟现实技术的应用。虚拟现实技术将使众多传统行业和产业发生革命性的改变。 虚拟现实系统的组成 一般的虚拟现实系统主要由专业图形处理计算机、应用软件系统、输入设备和演示设备等组成.虚拟现实技术的特征之一就是人机之间的交互性(interaction)。 虚拟现实技术的特点在于,计算机产生一种人为虚拟的环境,这种虚拟的环境是通过计算机图形构成的三维数字模型,编制到计算机中去产生逼真的"虚拟环境",从而使得用户在视觉上产生一种沉浸于虚拟环境的感觉,这就是虚拟现实技术的浸没感(Immersion)或临场参与感。 虚拟现实与通常CAD系统所产生的模型以及传统的三维动画是不一样的,它不是一个静态的世界,而是一个开放、互动的环境,虚拟现实环境可以通过控制与监视装置影响或被使用者影响,这是VR的第二个特征,即交互性(Interaction)。 用户可以使用一个鼠标、游戏杆或其它跟踪器,随意"行走"在方案规划中的居住小区或购物中心,任意进入其中的建筑,甚至可以"乘座"电梯,上到二楼去看一看新店铺的门面设计,感受一下购物中心大厅的装饰和其透过明媚阳光的天窗。 虚拟现实以视觉形式反映了设计者的思想,比如当在盖一座现代化的大厦之前,你首先要做的事是对这座大厦的结构、外形做细致的构思,为了使之定量化,你还需设计许多图纸,当然这些图纸只能内行人读懂,虚拟现实可以把这种构思变成看得见的虚拟物体和环境,使以往只能借助传统沙盘的设计模式提升到数字化的即看即所得的完美境界,大大提高了设计和规划的质量与效率。这是VR所具有的第三类特征,即想象性(Imagination)。 正是由于虚拟现实技术的上述特性,它在许多不同领域的应用,可以大大提高项目规划设计的质量,降低成本与风险,加快项目实施进度,加强各相关部门对于项目的认知、了解和管理,从而为用户带来巨大的经济效益。例如波音公司完全使用虚拟现实技术设计波音777新型客机获得成功;加拿大政府使用虚拟现实技术进行多伦多市(Toronto)的城市规划与管理,并把它作为申办2008年奥运会的重要宣传资料。 在某种程度上,虚拟现实系统其实就是通过计算机系统仿真的数字化沙盘,但比传统沙盘和模型功能更多、性能更强、应用更广,是建筑设计和规划表现工具从传统工艺向数字技术发展的又一次革命! 第二节 网络与虚拟现实技术的发展 最早的计算机网络雏形名为ARPANET,诞生于美国,在美国国防部高级研究计划署DARPA资助建立,先后有四所大学作为主节点加入,(UCLA,Stanford Research Institute,UC Santa Barbara 和 University of Utah)。 1972年,Bob Kahn组织建立了第一个展示ARPANET功能的公开演示网,同年,Email的出现改变了传统的书信交往模式,成为现在人与人交流沟通的主要方式之一。 随着计算机的普及和飞速发展,接入互联网变得更加方便快捷,越来越多的国家和机构的主机连入互联网。使用网络范围的扩大,使得人们可以通过传输文件的方式共享资源,不同的网络急需一种方式来支持互相传输数据,TCP/IP协议应运而生。TCP/IP技术是解决网络之间通信的核心技术,随着它的公开,互联网得到了极大程度的发展。随着互联网的广泛应用,与之相关的新兴技术及应用架构层出不穷,Tim Berners-Lee所提出的WEB架构就是其中最为耀眼的应用架构之一,而HTML作为它的发布语言,实现了信息之间的连接,利用URI统一资源定位技术精确定位,通过HTTP协议实现信息的共享。HTML语言是一种标记语言,它在很大程度基于SGML(Standard Generalized Mark-up Language)进行了简化和扩展,这使它的可靠性和可接受性与生俱来。同时,它还引入了超级链接的理念,使得WEB上的资源可以互相连接。 虚拟现实技术是通过计算机软件和硬件设备的支持,实现模拟真实或想象的环境成三维立体环境,可以通过特殊的输入输出设备,使人在视觉,听觉,嗅觉甚至触觉上有身临其境的参与感。早在上世纪50年代就有人开始希望模拟出虚拟感受,但是直到计算机的飞速发展和普及,虚拟现实技术才真正得到了广阔的发展空间。这项技术现在已经被广泛应用于国防、医学、建筑、工业设计等领域,可以通过模拟真实场景培养战斗人员,可以结合心理分析诊断早期的精神分裂患者,可以通过参照图纸的描述再现珍贵的文物古迹。虚拟现实分为浸入式和非浸入式。浸入式主要借助了一些特殊的输入输出设备,如头盔式显示器HMD(Head-Mounted Display),手套等让使用者在感官上有身临其境之感。而非浸入式则是借助简单的工具,如通过鼠标操作,音响效果等。 VRML(虚拟现实标记语言)的诞生,使以HTML为主的2D网络世界向3D虚拟世界更进一步迈进。VRML是一种标记性描述语言,它通过文本的方式来描述,通过浏览器或其他客户端对其进行解释,最终勾画出三维立体空间,由于它是文本的方式描述,使得它在Internet中进行传输时大大减小了数据的传输量,从而为3D虚拟现实技术在Internet中的充分应用铺平了道路。 第三节 Web3D闪亮登场 Web3D可以简单的看成是Web技术和3D技术相结合的产物,是互联网上实现3D图形技术的总称。从技术的亲缘关系来看,Web3D技术源于虚拟现实技术中的VRML分支,1997年,VRML(VRML Consortium)协会正式更名为Web3D(Web 3D Consortium)协会,并制定了VRML97新的国际标准。至此,Web3D的专用缩写被人们所认识(这也是常常把Web3D与虚拟现实联系在一起的原因)。 Web3D的核心技术及其特征 目前,走向实用化阶段的Web3D的核心技术有基于VRML、Java、XML、动画脚本以及流式传输的技术,为网络教学资源和有效的学习环境设计和开发、组织不同形式的网络教学活动,提供了更为灵活的选择空间。由于采用了不同的技术内核,不同的实现技术也就有不同的原理、技术特征和应用特点(见表1)。 表1:Web3D的核心技术及特征对比 Web3D 的核心技术 实现原理 技术特征 应用特点 基于VRML技术 服务器端提供的是VRML文件和支持资源,浏览器通过插件将描述性的文本解析为对应的类属,并在显示器上呈现出来。 通过编程、三维建模工具和VRML可视化软件实现;在虚拟三维场景展示时,文件数据量很大。 高版本浏览器预装插件;文件传输慢,下载时间长;呈现的图像质量不高;与其他多技术集成能力及兼容性弱。适合于三维对象和场景的展示。 基于XML技术 将用户自定义的三维数据集成到XML文档中,通过浏览器对其进行解析后实时展现给用户。 通过三维建模工具和可视化软件实现;在三维对象和三维场景展示时,文件数据量小。 需要安装插件;文件传输快,可被快速下载;呈现的图象质量较好;与其他多技术集成能力强;兼容性好。适合于三维对象和场景的展示。 基于Java技术 通过浏览器执行程序,直接将三维模型渲染后实时展现三维实体。 通过编程和三维建模工具来实现;在三维对象和三维场景展示时,文件数据量小。 不需要安装插件;文件传输快,可被快速下载;呈现的图象质量非常高;兼容性好。适合于三维对象和场景的展示。 基于动画脚本语言 在网络动画中加入脚本描述,脚本通过控制各幅图像来实现三维对象。 通过脚本语言编程来实现;在三维对象和三维场景展示时,文件数据量较小 需要插件;文件传输快,可被快速下载;呈现的图象质量随压缩率可调;兼容性好。适合于三维对象和场景的展示。 基于流式传输的技术 直接将交互的虚拟场景嵌入到视频中去。 通过实景照片和场景集成(缝合)软件来实现;在场景模拟时,文件数据量较小。 需要下载插件;用户可快速浏览文件;三维场景的质量高;兼容性好。实现360度全景虚拟环境。 第二章 Lyinux基础知识 Lyinux语言是一种描述语言(Markup Language)语言,通过文本的方式对3D场景进行描述,它是在VRML语言基础上的扩展与改进。它继承了VRML描述语言的基本节点,如Shape,Transform等,同时又针对CC6浏览器的实际应用扩展了如System,MoveController这样的节点。以这种文本的方式,是为了最好的与当前服务器配合,服务器可以通过PHP,JSP,ASP等脚本语言与Lyinux语言配合使用,通过动态解析生成新的文本返回给客户端,只要服务器可以输出文本,并且符合CC6所支持的标准,浏览器就可以动态的创建出任意场景。 第一节 2D与3D 随着计算机技术的进步,我们跨入了一个三维时代,各种扣人心弦的三维游戏、能数字化地显示天气变化的气象服务、震撼人心的3D数字化特殊效果,无不使我们体验到三维世界的全新感觉。可视化、计算机动画、虚拟现实是当今图形学领域的三大热门话题,它们的技术核心都是三维图形。下面我们就将当前的2D技术和3D技术做个对比。 2D、3D中的“D”指“维度”,2D即双维度,3D即三维度。那么,何谓“维度”?我们找一张纸,在纸上画一个正方形。现在我们可以看到,这个正方形具有“长”和“宽”这两个属性。如果用x来表示长,y来表示宽的话,我们可以构成一个x/y坐标系,这样一来正方形就完全处于这个坐标系中。正方形上的任何一点都有一个唯一的坐标值,这个坐标值的内容包括两个数据:该点所在的x值和y值。 同样,对于3D物体来说,我们也可以建立一个“长”、“宽”、“高”坐标系,暂且以x/y/z来表示坐标轴。那么,对于任何一个3D物体,我们都可以用一个包含x、y、z三个数值的集合来唯一地表示该物体上的任何一点。 在这里,我们应该注意到,3D和2D的区别在于3D世界多了一个表示“高度”的坐标轴。如果去掉这个坐标轴,那么3D就变成了2D,也就是说如果这个坐标轴的值是0的话,3D坐标系就可以用来表示2D图形。但是2D坐标系仅仅有两根坐标轴,即只有两个维度,所以无论如何也不可能用来表示3D物体。即:2D是平面,3D是空间。空间包含平面。 不管是网页,还是游戏,我们都可以称之为界面。从2D发展到3D,界面经历了一些蜕变。这种蜕变有人认为制作和使用界面都更复杂,更困难了。其实不然,我们就分析一下这种蜕变,看看在这个过程中界面会不会变得更复杂。 一个界面由三个方面构成:表现(Presentation)、交互(Interaction)和逻辑(Logic)。那么我们从这三个方面来分析: 表现上,对于计算机的显示器来说,就是一个2D平面显示,不管世界是2D还是3D的,在显示器上都被映射到屏幕平面。不同的是当计算机需要显示2D图形时,通常的做法(DirectX的做法)是在显存中开辟两块空间,用来储存基于x/y坐标系的数据。当需要显像的时候,计算机直接把坐标系中的数据贴上屏幕。当计算机需要显示3D场景时,DirectX的做法是在内存中开辟3D坐标系空间(对于计算机来说是三元数组)。一,首先要建立一个世界坐标系,这个坐标系就如同我们的宇宙,是容纳内存中其他3D物件的容器。然后,计算机往这个容器内添加物体(3D模型)。注意,此时还仅仅是计算机内存世界的建立,我们屏幕上还看不到任何东西。二,当内存世界建立完毕以后,计算机会建立一个摄像机,这个摄像机具备三个坐标:镜头方向、右方向和上方向。这个摄像机摄到的东西就是我们在屏幕上看到的东西,这三个坐标决定了我们看到的到底是什么。三,将场景关联交互,如当摄像机在内存世界中游走时,我们在屏幕上看到的东西也在不断的变化。 交互上,2D技术主要使用热区或热点来识别交互。设计师需要把屏幕中的某个点或区域选中设置为热点或热区,然后在这个热点或热区上设定交互,当热点或热区下的图像移动或变换时,该热区必须不断地调整其形状尺寸以适合图像。而在3D技术中,世界是用物体(Object)来组成的,所以交互的单元就是物体。物体无论怎样变换,它都是容易识别的。所以就这点来讲,3D的复杂度比2D要减小一些。 逻辑上,2D和3D的交互行为都是符合必然推理规则,即逻辑原则。所以在这一方面,从2D到3D没有改变。 另外,从制作的复杂度上来看,对于同一个界面,2D制作的复杂度随着界面的复杂度升高而迅速升高,3D制作的复杂度随界面复杂度升高而缓慢升高。由此我们可以得出这样一个曲线对比图: 界面复杂度 3D 2D 制作复杂度 随着3D技术的发展,GPU运算能力不断增强,特别是PPU物理运算的问世,使3D的特点(或者说它的优势)越来越明显,在于: 1. 真实感十足,展示效果更加接近真实世界; 2. 动感十足,交互动画效果更加接近真实世界,甚至某些绚丽的效果超越了真实世界。 第二节 3D世界是如何描述的 本节开始深入探索虚拟3D世界,首先通过例子让我们看看Lyinux是如何描述3D世界的。 一、 空间位置 为了定量地描述物体的位置及位置的变化,需要建立适当的参照系。在参照系中,为确定空间一点的位置,按规定方法选取的有次序的一组数据,这就叫做“坐标”。在某一问题中规定坐标的方法,就是该问题所用的坐标系(coordinate system)。 坐标可以分为平面坐标和空间坐标,平面坐标,也称二维坐标,用来描述平面上某点的位置,对应于一个二维平面坐标系;空间坐标,也称为三维坐标,用来描述空间中某点的位置,对应于一个三维空间坐标系。 坐标还分为绝对坐标和相对坐标,分别对应于绝对坐标系和相对坐标系。绝对坐标系是一个固定的坐标系,也称为世界坐标系,以世界的中心作为原点,在空间世界中的坐标称为绝对坐标;相对坐标系是相对于某个点的坐标系,以这个点作为坐标系的原点,在这个坐标系中的坐标称为相对坐标。 坐标系的种类很多,有笛卡儿直角坐标系、极坐标系、地理坐标系等。在CC6系统中统一使用笛卡儿直角坐标系。在三维坐标系中,Z轴的正轴方向是根据右手定则确定的。右手定则也决定三维空间中任一坐标轴的正旋转方向。 要标注X、Y和Z轴的正轴方向,就将右手背对着屏幕放置,拇指即指向X轴的正方向。伸出食指和中指,食指指向Y轴的正方向,中指所指示的方向即是Z轴的正方向。 二、 视觉效果 在计算机领域,视觉效果一般就是指显示在屏幕上的色彩,屏幕每个显像因子显示一个色彩,集合起来就是我们看到的效果。视觉效果是由形和色构成的,形就是形状,即我们创建的造型,色就是颜色,我们通过材质设定来影响视觉效果的颜色。 1. 造型 造型,指的是三维物体的几何形体。物体有体积,在三维空间中要占用一定的空间。 那么我们以"Hello,World!"作为我们的第一个虚拟境界,在场景中建立一个box。 在开始创作之前,应作好下面的准备。 1) 文本编辑器 随便你喜欢的文本编辑器,如NOTEPAD记事本,OFFICEWORD,VRMLPAD等等。 2) CC6浏览器或其他因特网浏览的CC6插件。 在文本编辑器中,输入的第一行文字是: #Lyinux V1.1 gb2312 这是CC6文件的标志,声明此文本文件是一个CC6文件,这一句不能省略,请注意这句一定要放在文本的最开头,前面不能留空行或空格。其中“#”表示这是一个注释。而gb2312表示此文件采用的是gb2312编码方案。 然后定义一个几何体Box: Box {} 就这样,我们已经成功地制作了第一个虚拟场景,把它保存为Hello World.cc6。 用CC6浏览器打开这个文件,你会看到一个灰色的立方体,尽管不太好看,但你还是可以在场景中点击右键,选择自由视角模式从不同方位观察它,初步体验“三维交互”的感觉。 2. 材质 材质,通俗的讲就是组成物体的材料和物体的质地。在3d虚拟世界里,材质表现为物体如何反射光线。如固有色、反射光线的颜色、自发光、透明度等。 比如在文本编辑器中我们输入以下代码: Shape { appearance Appearance { material Material { diffuseColor 1 0 0 } } geometry Box {} } 保存为material.cc6,用浏览器打开看看灰色的Box是否已经变成红色的了? Shape是外形节点 它有两个域appearance(外观)域和geometry(造型)域 appearance域的域值是 Appearance { material Material { diffuseColor 1 0 0 } } geometry域的域值是Box {}。 可以看出这时的Box节点是做为域值出现的,也就是说在Lyinux中节点也可以做域值。 在Appearance节点中material域的域值是Material(材质)节点。 Material节点正是本节的重点:在本例子中Material节点中包含了diffuseColor域,域值为1 0 0,这是一个RGB颜色值,代表红色,于是我们看到一个红色的盒子。这就是材质节点的作用,当然除了diffuseColor域,在Material节点中还包括很多其他能描述物体材质的域。后面章节中有详细介绍。 三、 运动状态 前面两项描述了物体的空间位置和视觉效果,总体来看这个物体还是静止不动的。我们的世界是运动的,所以必须要让世界动起来,这就需要描述物体的运动状态。 动画,英文Animation源自于拉丁文字根的anima,意思为灵魂,动词animare是赋予生命,引申为使某物活起来的意思,所以animation可以解释为经由创作者的安排,使原本不具生命的东西像获得生命一般地活动。 在虚拟世界里,所有的物体造型都是没有生命的,但我们要给与它们运动。那么就需要驱动物体运动,而且要给出运动的轨迹。我们把触发物体运动的节点称为传感器(Sensor),给出运动轨迹的节点称为插补器(Interpolator),把传感器、插补器、物体之间的关联称为路由(ROUTE)。 第三节 有关Lyinux Lyinux语言是一种标记语言(Markup Language),通过文本的方式对3D场景进行描述,它是在VRML语言基础上的扩展与改进。(VRML是Virtual Reality Modeling Language的简称,翻译成中文就是虚拟现实建模语言,是一种在Internet上营造虚拟环境的技术。)Lyinux用类似HTML标记文本语言来描述三维场景,就象我们的编程语言,比如,上面的例子如果我们要规定正方体的边长为3厘米,可以这样写:Box{size 3.0 3.0 3.0}。 本书中已经多次提到节点一词,现在我们要了解节点到底是什么。Lyinux语言用层次化的场景图来描述三维对象和世界。在场景图中的实体称为节点。了解web语言的人都应该知道HTML,XML等都是标记语言,在Lyinux中节点就相当于HTML、XML中的标签,就像标签有自己的属性一样,每个节点也有每个节点的属性,在Lyinux中我们叫做域,把属性的值称为域值。比如Box{size 3.0 3.0 3.0},Box就是一个立方体节点,花括号里size是描述长宽高的属性即域,size后跟的数值是属性值即域值。本书中将采用节点、域、域值用来区分3维标记语言和传统标记语言。 一、 Lyinux的应用: 1. 建筑 建筑本身就涉及三维环境的设计,在传统的工作方式下,建筑设计人员所面临的一个最大的问题是如何向客户讲清楚所要设计的建筑物的形状、空间布局、采光效果和声响效果等问题,并且在建筑物造好后,客户往往感到不满意。虚拟现实技术可解决这个问题 ,可预先"看到"待建的建筑物,并在其中漫游。使用Lyinux,建筑设计人员和客户可以位于不同的地理位置,甚至在两个不同的城市。 2. 艺术和历史 讲授艺术和历史的教师常常会发现学生对其所讲的内容不感兴趣,之所以这样,主要是因为老师所用的表示方法过于单调,如果配以3D图形、动画,由学生自由使用相应的网络信息查询软件来浏览,那么,学生一定会产生浓厚的兴趣。如虚拟艺术博物馆、古城堡和古战场的再现、著名城市和教堂等建筑的漫游。 3. 广告 Internet用户急剧增长,网上交互式的图形将为广告业开辟新天地,可能的广告类应用有:3D购物商场、旅馆和景点等休闲设施的3D展示、3D主页(介绍人、企业或研究所)。 4. 工程 基于Internet网,异地工程人员可以进行协同设计,可能的应用有:多用户实时3D机械设计图的观察和讨论、可视3D产品设计管理(PDM)数据库、虚拟3D快速成型。 5. 科学研究 在传统的科学研究中,研究人员主要依靠一些出版物(论文或书)交流信息。随着WWW 网上3D交互式图形的发展,科学出版物本身也发生了革命性的变化,基于网络的电子出版物越来越流行,研究人员除了常规的图像和文字外,他们还可以交互式3D图形的方式共享一些实验结果,这类应用领域包括:分子造型、地学、计算流体学、医学图像处理。 6. 其它 其它应用领域有信息服务、娱乐和教育等。 二、 Lyinux的特点 1) 可编辑性 使用各种文本编辑器都可以编辑Lyinux文件,还可以开发应用程序来创建、编辑和保存Lyinux文件,也可将其它常用的三维文件格式转换为Lyinux支持的格式。 2) 可重用性 提供了使用、组合并允许重用动态三维对象的能力。 3) 可扩展性 提供了增加新的对象类型的能力。 4) 跨平台性 在不同的计算机平台上都能达到可扩展和交互的性能。 5) 可伸缩性 允许任意大小的动态三维世界。 三、 Lyinux与互联网 人与计算机的交互方式已经历了命令行,图形用户界面,多媒体等阶段,计算机的输入输出通道越来越多,人机交互的手段也越来越丰富。多通道技术的发展促使了虚拟现实技术的诞生,网络虚拟现实技术是一项正在蓬勃发展的前沿技术,代表了计算机发展的一个方向。 随着Internet的飞速发展及3D技术的日益成熟,人们已经不满足Web页上二维空间的交互特性,而希望将WWW变成一个立体空间。今后主页上将不再仅仅有图片文字,而是有类似于《古墓丽影》、《帝国时代II》这类游戏的三维场景,主页的链接也不再是高亮度显示的图片和文字,而是在三维空间打开一扇门或者触摸一个物体,就进入了另一个主页。甚至你在网上还可以有一个虚拟的自己,也就是你的替身在网络世界中冒险;上网者互相之间都能相互看到,你可以和逛街一样浏览主页,同时和路上碰到的人打招呼。 Lyinux天生就是依赖于互联网的。Lyinux本身是一种用于分布式网络的虚拟现实技术,是对VRML技术的扩展。 第四节 Lyinux 基本概念 一、 CC6浏览器中的计量单位 CC6采用笛卡尔右手坐标系,在三维空间中,X轴的正方向朝右,Y轴的正方向朝上,Z轴的正方向朝向用户(浏览者)。这与3D建模软件3DSMax是不同的,Max中X轴的正方向朝右,Y轴的正方向背向用户,Z轴的正方向朝上。 CC6坐标中的长度单位称为一个CC6单位,和尺寸单位不具有可比性,实际应用时由开发者统一协调,一般使用时理解为米即可。 CC6的角度使用弧度单位,角度单位应转换为弧度单位再使用。 CC6中的时间分为绝对时间和相对时间。绝对时间是从格林威治标准时1970年1月1日零时开始到当前时间的秒数,比如到格林威治标准时2008年8月8日下午20时的绝对时间值是: 3600×((2008年8月8日-1970年1月1日)×24+20)=3600×(13879×24+20)=1199217600秒 北京时间比格林威治时间(世界时)早8小时,即北京时间=世界时+8小时。 相对时间指从时空的某一时刻开始作为计时的起点,用数值0表示,到时空的另一时刻作为计时的终点,用数值1表示。从[0 1]的实际经过时间可以是1秒,也可以是几分钟,也可以是若干小时,等等。 CC6空间的颜色采用红、绿、蓝(RGB)三基色组合而成,三种颜色对应三个浮点数,取值范围在0.0到1.0之间。 下表给出了由三基色组合而成的部分颜色。RGB三基色组合颜色示例 红 绿 蓝 组合颜色 0.0 0.0 0.0 黑色 0.0 0.0 1.0 蓝色 0.0 1.0 0.0 绿色 1.0 0.0 0.0 红色 1.0 1.0 1.0 白色 1.0 1.0 0.0 黄色 0.0 1.0 1.0 蓝绿色 1.0 0.0 1.0 紫红色 0.75 0.75 0.75 浅灰色 0.5 0.5 0.5 中灰色 0.25 0.25 0.25 深灰色 0.0 0.0 0.5 暗蓝色 0.0 0.5 0.0 暗绿色 0.5 0.0 0.0 暗红色 二、 LYINUX的数据类型与域 在前面的学习中我们知道,一个遵循Lyinux语法的文件实际是由一个个节点组成,每个节点都是属于SFNode类型,SF为前缀的类型一般表示单一数值,MF为前缀的类型表示多值,类似于数组,如MFNode,就是由多个SFNode构成。节点中有不同的域来描述,而域值有不同的数据类型,以下是Lyinux中所支持的数据类型列表: SFBool 布尔类型,TRUE或FALSE。 SFFloat 32位浮点数值 SFInt32 32位整数,该整数可以使用十进制或十六进制表示,使用十六进制时应在数字前加0x,如:0xFF00。 SFString 编码为UTF-8的字符串,与ASCII兼容, 允许使用Unicode字符集。定义时应使用双引号(")包围字符串。 SFVec2f 2D向量,经常用于2D坐标,如texture坐标,2D向量用一对浮点数表示。 SFVec3f 3D向量,经常用于3D坐标,3D向量用3个浮点数表示。 SFTime 该值等于从1970年1月1日0:00到此刻的秒数。用double类型表示 SFRotation 由4个浮点数所组成:前3个限定旋转轴的x、y、z坐标,最后1个限定旋转角度。 SFNode 一个节点的容器。 SFColor 由3个分别表示红、绿、兰的0~1间的浮点数所组成的向量。 SFImage 定义二维像素图像。它由三部分组成:最前面两组整数,分别表示二维图像的宽度和高度,单位是像素(pixel);接着的一个整数描述像素的性质:1表示灰度,2表示灰度透明,3表示RGB彩色,4表示RGB彩色透明;最后是若干组十六进制或十进制的整数,分别描述每个像素的颜色、强度和透明度。 MFFloat 为SFFloat的数组 MFInt32 为SFInt32 的数组 MFVec2f 为SFVec2f 的数组 MFVec3f 为SFvec3f 的数组 MFColor 为SFColor 的数组 MFRotation 为SFRotation 的数组 MFString 为SFString 的数组 MFNode 为SFNode 的数组 注意: 还有一种域值类型为SFEnum,这表示该域是一个包含枚举类型值的单值域。 注意通过使用这个域的类来定义值的助记名。 它和SFString的区别如下: SFEnum以助记类型名写到文件中,在各种节点类中使用此域时名字是不同的。 SFString 是一个包含ASCII字符串(字符序列)的域。 SFString 以在双引号中(如果字符串不包含任何空格,则是可选的)ASCII字符序列写到文件中,任何字符(包括换行符)可以出现在引号中。通常,在字符串中包含双引号时,则在它前面写反写杠。 例如,有效的字符串如下: Testing "One, Two, Three" "He said, \"Wise Words are uttered in CPS616!\"" 三、 域类型 域的类型与域值的数据类型不同,它用来决定这个域在变化是是否会发出事件,是否可以接收外部值等。一共有4种域类型:eventIn, eventOut, field和exposedField。 1. eventIn 可以被这个节点接收的事件。通常,eventIn事件对节点的某个域通信,节点的域不能从外部被访问,通过eventIn通信的方法你可以改变它们 一些节点还存在一些eventIn事件,它们不能和这个节点的其他域通信,但可以为他提供附加功能。例如Transform节点存在一个eventIn 事件addChildren,当这个事件被接到时,这个被传进来的子节点就会添加到这个接受的Transform的children列表中。 1. eventOut 可以被这个节点发出的事件。这个类型的事件将在那个允许发出事件的域值发生改变时被发出。 2. field 节点的私有成员,存放着节点的数据。它可以在文件中设置特定的值,一般来说,field是所在节点私有的,它的值只有在它所在的节点接收到了传来的eventIn事件。需要明白的一点是field自己不能被外面的节点来改变。 3. exposedField 节点的公有成员,存放着节点的数据,exposedField具有eventIn、eventOut和field的全部特性,即可以 接收数据、发送数据,也是控制该节点状态的重要参数。 CC6浏览器为了与VRML兼容,保留了像eventIn,eventOut这样的类型,但在这个基础上作了一定的扩充,以exposedField为主要模式,eventIn与eventOut都将视为是exposedField。 四、 3d建模工具导出资源 我们可以用以下几种方法削减文件的大小和提高执行速度。 ⒈ 注意建模时的减肥 ⑴要仔细管理好建立的对象。在开始建立场景模型之前,先做一个关于面数(多边形)的“估算”,然后再为不同模型粗略地分配面的数量。在用3DS MAX建立VRML模型时,PolygonCounter(多边形统计)将会帮助你,使创建的模型不会超过所预计的面数。 ⑵尽量利用简单造型节点(Box、Cone、Cylinder和Sphere)来“拼装”复杂的造型,这点非常重要。有人曾做过一个小测试,制作楼梯:用三个Box互相堆砌来制作,生成的文件大小为881字节;用三个Box经过Boolean来制作,生成的文件大小为2007字节;用Loft的方法来制作,并且将Skin参数里的造型和路径的steps值均减少为0,生成的文件大小为1126字节。我查看了它们的源文件,发现用Boolean和Loft方法生成的文件是用“面”来描述物体(面是由一系列的三维坐标点连线而成),因此文件里充满了点坐标,文件就庞大;而用Box方法生成的文件只用了三个Box语句就可描述完成,因此文件就很小。 ⑶减少分段数 减少面的数量的最简单的方法就是在所建立的基本几何体中减少分段数。在3DS MAX中,基本几何体中分段数的默认设置将生成过多的面,这是VRML领域不允许的。因此在建立基本几何体后,立刻转到Modify面板,然后减少分段数。 ⑷删除和隐藏面 你可以做的另一件简单的事情,就是从场景中的对象里删除看不见的面。事实上你不必使用基本对象创建建筑下面的地面效果。VRML2.0为Background辅助对象提供Ground color选项,帮助你设置底于水平线的视图的颜色。另一种方法就是隐藏不要的面,而不是删除他们。因为VRML并不输出隐藏的面,这些面将不是最后所下载的文件的一部分。但是3DS MAX还计算隐藏的面,因此在建模过程中你得不到完全的精确的面的数量。隐藏还是删除面完全取决于你,如果你的模型只在VRML浏览器上使用,删除他们更为方便。 ⑸使用Optimize修改器或PolygonCruncher插件 毫无疑问,你已经很熟悉Optimize编辑修改器,也没必要指出为VRML环境建立含有较少面数模型的优点。一般来说,网格越复杂,通过使用Optimize修改后减少的面就越多。PolygonCruncher是一款减面插件,支持3DSMax各种版本和其他建模工具,可以在不影响3d模型外观的前提下,尽量减少模型的多变形数量。在高优化比的情况下不损失细节,还可以保留原模型的纹理信息、节点色、保持多变性对称等! ⑹使用关联复制(Instances) Instance是3DS MAX对象的关联拷贝,当你改变任何一个关联复制品的时候,所有其它的复制品都会改变。在为WEB建立小型文件时,关联复制品是非常有用的,当使用关联复制的时候,组成关联复制的对象的面的设置只在VRML码中定义一次。这样你可以使用多次同样的几何图形,但不增加文件的下载时间。 ⑺使用简单模型加纹理贴图 使用Box等原始结构节点来构建场景,然后,通过在这些简单模型上使用不同的纹理贴图以及改变尺寸和方向,你就能使场景看起来与它实际的形状有很大区别。尽管纹理贴图增加了下载时间和屏幕重画时间,但这和给物体建造细节的代价要小得多。 当你加载纹理贴图时,要记住WEB服务器最有可能是区分大小写的,除非大小写很准确,否则找不到贴图文件。此外,还要注意贴图文件要放在VRML导出时所定义的贴图文件夹里。 ⒉ 注意导出对话框的设置 3DS MAX的VRML导出对话框有许多能影响文件大小的参数设置。Normals参数可以使导出的物体更圆滑,但同时文件大小也会激增;如果不需要观看由输出器生成的VRML代码,就不必选中Indentation参数,可以减少文件大小的20%左右;如果在场景中有插值动画,减少Sample Rate参数的数值可使文件大小有显著的差异。 五、 小结 在Lyinux中,通过造型节点比如Box节点等创建造型,通过造型节点中的域设定物体的大小、颜色、位置等外观并且可以通过特殊的造型节点声音节点在场景中创建立体声音,利用传感器节点和插补器节点控制动画的方式,路径等运动方式。利用Script节点实现人机交互。并通过ROUTE(路由)使场景中的各个节点联系起来。这样,Lyinux就可以描述栩栩如生的虚拟现实世界。具体节点的应用将在后面的章节中详细阐述。 造型篇 第三章 创建造型 第一节 简单造型 一、 Box Box节点用来创建以坐标原点为中心的正方体或长方体造型,并可作为Shape节点geometry域的值。其语法格式如下: 节点名称 域名称 域值 #域及域值类型 Box{ size 2.0 2.0 2.0 # exposedField SFVec3f } 域值说明: size域的域值设定了三维立方体的长宽高。该域值为三维数组,第一个数值对应X轴方向的边长,第二个数值对应Y轴方向的边长,第三个数值对应Z轴方向的边长,这三个数值必须大于零。size的默认值为2.0 2.0 2.0。 二、 Cube Cube节点用来创建以坐标原点为中心的立方体造型,并可作为Shape节点geometry域的值。其功能与Box一致。其语法格式如下: 节点名称 域名称 域值 #域及域值类型 Cube{ width 2.0 # exposedField SFFloat height 2.0 # exposedField SFFloat depth 2.0 # exposedField SFFloat } 域值说明: width域的域值设定立方体的X轴方向的边长。该域值为浮点数,数值必须大于零,默认值为2.0。 height域的域值设定立方体的Y轴方向的边长。该域值为浮点数,数值必须大于零,默认值为2.0。 depth域的域值设定立方体的Z轴方向的边长。该域值为浮点数,数值必须大于零,默认值为2.0。 三、 Sphere Sphere节点用来创建以坐标原点为中心的三维球体造型,并可作为Shape节点geometry域的值。其语法格式如下: 节点名称 域名称 域值 #域及域值类型 Sphere{ radius 1.0 # exposedField SFFloat } 域值说明: radius域的域值设定了球体的半径尺寸。该值必须大于零,默认值为1.0。 四、 Cylinder Cylinder节点用来创建以坐标原点为中心、以Y轴为对称轴的圆柱体造型,并可作为Shape节点geometry域的值。其语法格式如下: 节点名称 域名称 域值 #域及域值类型 Cylinder{ radius 1.0 # exposedField SFFloat height 2.0 # exposedField SFFloat bottom TRUE # exposedField SFBool top TRUE # exposedField SFBool side TRUE # exposedField SFBool } 域值说明: 1) radius域的域值设定圆柱体底面半径尺寸。该域值必须大于零,默认值为1.0。 2) height域的域值设定圆柱体的高度。该域值必须大于零,默认值为2.0。圆柱体底面中心位于Y轴-1.0处,顶面中心位于Y轴1.0处。 3) side域的域值设定是否创建圆柱体的侧面。如果域值为TRUE则创建锥面,如果域值为FALSE则不创建侧面,即不显示圆柱体的侧面。默认值为TRUE。 4) top域的域值设定是否创建圆柱体的顶面。如果域值为TRUE则创建顶面,如果域值为FALSE则不创建顶面,即不显示圆柱体的顶面。默认值为TRUE。 5) bottom域的域值设定是否创建圆柱体的底面。如果域值为TRUE则创建底面,如果域值为FALSE则不创建底面,即不显示圆柱体的底面。默认值为TRUE。 五、 Cone Cone节点用来创建以坐标原点为中心、以Y轴为对称轴的圆锥体造型,并可作为Shape节点geometry域的值。其语法格式如下: 节点名称 域名称 域值 #域及域值类型 Cone{ bottomRadius 1.0 # exposedField SFFloat bottom TRUE # exposedField SFBool height 2.0 # exposedField SFFloat side TRUE # exposedField SFBool } 域值说明: 1) bottomRadius域的域值设定圆锥体底面半径尺寸。该域值必须大于零,默认值为1.0。 2) height域的域值设定圆锥体的高度。该域值必须大于零,默认值为2.0。圆锥体底面中心位于Y轴-1.0处,顶端位于Y轴1.0处。 3) side域的域值设定是否创建圆锥体的锥面。如果域值为TRUE则创建锥面,如果域值为FALSE则不创建锥面,即不显示圆锥体的锥面。默认值为TRUE。 4) bottom域的域值设定是否创建圆锥体的底面。如果域值为TRUE则创建底面,如果域值为FALSE则不创建底面,即不显示圆锥体的底面。默认值为TRUE。 第二节 复杂造型 简单造型节点可以被用来创建多种单一造型,但是它们不适用于创建复杂形体,比如一些光滑或流动的曲面。CC6提供了一些非常灵活的节点使你能够通过使用点、线和面来构造出所需的几何形体。 下面我们将介绍文本造型和轮廓挤出造型节点。更为复杂的几何造型节点Extrusion挤出造型节点,ElevationGrid海拔造型节点、Nurbs曲线曲面我们将在进阶篇中做更为详细的介绍。 一、 文本造型 1. Text Text节点主要用于在场景中显示文字(只能显示英文文字,显示中文请使用Text2和Text3节点),使用该节点显示出来的文字会随着镜头的旋转而旋转。 其用法如下: 节点名称 域名称或事件 域值 #域值或事件类型 Text { string [ ] # exposedField MFString length 0.0 # exposedField MFFloat maxExtent 0.0 # exposedField MFFloat fontStyle NULL # exposedField SFNode } 域值说明: string:文本内容,单行文本使用双引号括起来;多行文本使用空格或逗号分开。 length:设置每一行文本的长度。 maxExtent:设定文本最大有效长度。 fontStyle:设定文本样式,域值为FontStyle文本样式节点。 FontStyle 文本样式节点语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 FontStyle    {         family "SERIF"        # exposedField SFString         size 1.0                 # exposedField SFFloat         spacing    1.0               # exposedField SFFloat         style "PLAIN"         # exposedField SFString         horizontal TRUE            # exposedField SFBool         justify    "BEGIN"       # exposedField SFString         leftToRight    TRUE         # exposedField SFBool         topToBottom    TRUE     # exposedField SFBool         language "ENGLISH"    # exposedField SFString } 域值说明: family:字体,共三种字体可选"SERIF","SANS","TYPEWRITER" size:字体大小 spacing :行间距 style:字体风格,共4种“PLAIN”通常体,"BOLD"粗体,"ITALIC"斜体,"BOLDITALIC"粗斜体 horizontal:文字的排列方式,TRUE为水平排列,FALSE为垂直排列 justify:相对于X轴和Y轴的对齐方式,共4种,"BEGIN"左对齐,"MIDDLE"居中对齐,"END"右对齐,"FIRST" leftToRight:文字在X轴上的方向,TRUE为从左向右排,FALSE为从右向左排 topToBottom:文字在Y轴上的方向,TRUE为从上向下排,FALSE为从下向上排 language:文字的语言类型,默认为英语 1. Text2 Text2节点主要用于在场景中显示文字,支持中英文,使用该节点显示出来的文字不会产生缩放和旋转变换,它的坐标系的原点在首行文字的左下角。 其用法如下: 节点名称 域名称或事件 域值 #域值或事件类型 Text2 { string [ ] # exposedField MFString spacing 25 # exposedField SFFLoat justification LEFT # exposedField SFString } 域值说明: string:需要显示的文字内容,该String中的每一个SFString为一行。 spacing:文字的行间距,使用的单位为像素。 justification:文字的对齐方式,LEFT左对齐,RIGHT右对齐。 2. Text3 Text3节点主要用于在场景中显示文字,支持中英文,显示出来的文字为面片状,可以通过Transform进行平移、缩放、旋转等变换,它的坐标系的原点在首行文字的左下角。 其用法如下: 节点名称 域名称或事件 域值 #域值或事件类型 Text3 { string [ ] # exposedField MFString spacing 25 # exposedField SFFLoat justification LEFT # exposedField SFString } 域值说明: string:需要显示的文字内容,该String中的每一个SFString为一行。 spacing:文字的行间距,使用的单位为cc6文件单位。 justification:文字的对齐方式,LEFT左对齐,RIGHT右对齐。 3. Font字体节点 Font字体节点用于指定Text2和Text3文本造型的字体。 Font {      name "黑体" #SFString      size 10 #SFFloat } 域值说明: name #SFString 指定文本字体 size #SFFloat指定文字大小 二、 轮廓挤出节点 LinearProfile线性轮廓线。轮廓线是文字造型的轮廓构成的线。线性轮廓线简单连接各个控制点来控制曲面造型——通过填满轮廓线来控制。其语法格式如下: LinearProfile{ index MFInt32 控制点. linkage START_FIRST与前置轮廓线节点的合成方式. } linkage域有三个选项: START_FIRST(缺省),使用本轮廓线节点替换前置轮廓线. START_NEW 将当前轮廓线补充在前置轮廓线. ADD_TO_CURRENT 将当前轮廓线的索引补充在前置. 一个造型在挤出成三维的时候,挤出的深度作为X,挤出时基于挤出方向的偏移作为Y,我们可以构造一个二维坐标系。利用这个二维坐标,我们可以控制一个平面如何被挤出成三维造型,一般用于控制Text3节点. 第三节 通用造型 通用造型节点包括PointSet点集,IndexedLineSet线集,IndexedFaceSet面集节点利用PointSet点集节点可以画出星星和一些分散的点造型。利用IndexedLineSet线集节点可以画出直线、曲线和网格等造型。利用IndexedFaceSet面集节点可以创建一个由许多面组成的造型,如光滑的鼠标表面,起伏的高山,流线型的跑车,或是其他的造型。实际上,任何几何造型都是可以由通用造型构造成的。 一、 PointSet点集 CC6 中点的造型是用X,Y,Z三维坐标定位,大小为1个像素的空间点。点集就是不同位置空间点集合。 PointSet 节点用于在三维立体空间中,创建一系列位置不同的空间点的造型。它常常被用来模拟天上闪烁的繁星和远处点点的灯光。空间点的造型不受光源影响,不能粘贴纹理,不进行碰撞检测。点集节点可以被用作Shape节点的geometry域的值。 PointSet点集节点的层次结构表 1 2 3 父节点 域 域值或子节点 域值 域值类型 PointSet点集节点 coord坐标域 NULL空值 Coordinate坐标节点 point[]坐标列表 多个三维量 color颜色域 NULL空值 Color 颜色节点 color[]颜色列表 多个三维量 PointSet 点集节点语法格式如下: 节点名称 域名称 域值 #域、域值或事件类型 PointSet{ coord NULL #exposedField SFNode color NULL #exposedField SFNode } 域值说明: 1.coord 域的域值设定离散点的三维坐标位置。该域值有两种选择:NULL或者Coordinate 坐标节点。该域值默认值为NULL,表示不创建任何点造型。如果创建离散点造型,该域值必须选择Coordinate 坐标节点,该节点包括了用来进行点定位的坐标。 Coordinate坐标节点语法格式如下; 节点名称 域名称 域值 #域、域值或事件类型 Coordinate{ point [ ] #exposedField MFVec3f } point域的域值提供了一张三维坐标列表,用来设定一个或一组空间点的 X, Y, Z 坐标。每个点的坐标都包含三个浮点数,分别表示在 X,Y, Z,方向上与坐标原点的距离。各个点坐标之间用“,”号分开。该域值的默认值为空,即point[],表示不创建任何点造型。 2.color域的域值通常选择Color颜色节点,用来设定每个空间点的颜色。该域值的默认值为NULL,表示不对空间点着色。 二、 IndexedLineSet线集 CC6中直线造型是由两个端点连接而成,创建一条直线必须设定线的点和终点。CC6中折线造型是由多个点连接而成,除了起点,终点外还有中间转折点。因此创建直线、折线造型需要做两个项目工作:一是设定连接点的坐标,二是设定连接点的顺序。为了方便设定连接顺序,每个连接点的坐标都有一个默认的索引号,只要指定索引号的连接次序,就可以完成直线或折线造型的创建工作。线集就是不同线段的集合。 IndexedLineSet线集节点用与在三维空间中创建由线段组合而成的各种开放或封闭的立体几何造型。线集节点创建的造型不受光源的影响,不能粘贴纹理,不进行碰撞检测。线集节点可以被用作Shape节点的geometry域的值。 IndexedLineSet线集节点创建的造型的层次结构表 父节点 域 域值或子节点 域值 域值类型 IndexedLineSet线集节点 coord坐标域 NULL空值 Coordinate坐标节点 point[]点坐标列表 多个三维向量 coordIndex坐标索引域 []坐标索引列表 多个32位整数 color颜色域 NULL空值 color颜色节点 color[]颜色列表 多个三维向量 colorIndex颜色索引域 []颜色索引列表 多个32位整数 colorPerVertex着色方式域 TRUE或FALSE IndexedLineSet线集节点语法格式如下: 节点名称 域名称 域值 #域,域值或事件类型 IndexedLineSet{ coord NULL # exposedField SFNode coordIndex [] # exposedField MFlnt32 color NULL # exposedField SFNode colorIndex [] # exposedField MFInt32 colorperVerex TURE # exposedField SFBool set_coordIndex #eventIn MFInt32 set_colorIndex #eventIn MFInt32 } 域值说明:(1) coord域的域值设定线段连接点的三维坐标位置。与pointset 点集节点完全一样,该域值有两种选择;NULL或者Coordinate坐标节点。该域值默认值为NULL,表示为空的列表,不创建任何线的造型。如果创建线的几何造型,该域值必须选择Coordinate坐标节点,该节点包括了用来构建线段的全部连接点的定位坐标。Coordinate坐标节点语法格式与点集节点中出现的Coordinate坐标节点完全相同,故不再重复,值得强调的是;point域的域值提供了一张连接点的三维坐标列表,同时为每一个连接点按照出现的顺序建立了默认的索引号。也就是说,point列表中第一组坐标的索引号为0,第二组坐标的索引号为1,第三组坐标的索引号为2,以此类堆。 (2)coordIndex 域的域值设定一条或多条线段连接路径的索引列表,其中的索引号与point域值相对应。每一个索引号对应一个连接点的坐标位置,索引号之间逗号分隔,线的创建方式是按照索引号依次连接对应的点。索引号为-1表示当前连接的线段已经结束,下一条线段的连接即将开始,列表中最后一条线段结束时可以不标索引号-1。该域值的默认值为空,表示不创建任何线造型。 (3)color,colorIndex,colorPerVertex域的域值均用于为创建的线段着色。 (4)set_coordIndex入事件用以设置新的坐标索引列表;set_colorIndex入事件用于设置颜色列表。 举例: 使用IndefxedLineset 节点,将中五个顶点连接成四棱锥体的白色轮廓线造型。 #Lyinux V1.1 gb2312 shape{ appearance Appearance{ material Material{ emissiveColor 1 1 1 } } geometry IndexedLineset{ coord Coordinate{ point[ 0 3 0  #索引号为0 3 0 0             #索引号为1 0 -3 0            #索引号为2 -3 0 0           #索引号为3          0 0 3 #索引号为4 ] } coordIndex[ 0 3 4 -1 3 2 4 -1 2 1 4 -1 1 0 4 ] } } 三、 IndexedFaceSet面集 IndexedFaceSet 面集节点用于在三维空间中创建各种由平面组合而成的不规则的立体几何造型。不仅可以创建平面几何造型,也可以创建实体几何造型。同时它可以被用作Shape节点的geometry域的值。 IndexedFaceSet 面集节点语法格式如下: 节点名称 域名称 域值 #域,域值或事件类型 IndexedFaceSet{ coord NULL # exposedField SFNode coordIndex [] # exposedField MFlnt32 texCoord NULL # exposedField SFNode texCoordIndex [ ] # exposedField MFInt32 color NULL # exposedField SFNode colorIndex [ ] # exposedField MFInt32 colorPerVertex TURE # exposedField SFBool normal NULL # exposedField SFNode normalIndex [ ] # exposedField MFInt32 normalPerVertex TURE # exposedField SFBool ccw TURE # exposedField SFBool convex TURE # exposedField SFBool solid TURE # exposedField SFBool creaseAngle 0.0 # exposedField SFFloat set_coordIndex #eventIn MFInt32 set_texCoordIndex #eventIn MFInt32 set_colorIndex #eventIn MFInt32 set_normalIndex #eventIn MFInt32 } 域值说明: 1. coord域的域值设定平面边界线连接点的三维坐标位置。与PointSet点集节点完全一样,该域值有两种选择:NULL空值或Coordinate坐标节点。该域值默认值为NULL,不创建任何面造型。 2. coordIndex 域的域值设定一条或多条平面边界线连接路径的索引列表,其中的索引号与point域值相对应。每一个索引号对应一个连接点的坐标位置,索引号之间逗号分隔,平面边界线的创建方式是按照索引号依次连接对应的点。索引号为-1表示当前连接的边界线段已经结束,下一条边界线段的连接即将开始,列表中最后一条边界线段结束时可以不标索引号-1。该域值的默认值为空,表示不创建任何平面造型。 3. texCoord、texCoordIndex域的值用于为所创建的面造型映射纹理。 4. color、colorIndex、colorPerVertex域的域值用于为创建的面造型着色。 5. normal域用于设定个平面的法向量,来控制平面的光线明暗效果。此域包含一个Normal节点,或选择NULL空值。通常使用的是浏览器自动产生的默认法向量,需用特殊明暗效果时才使用Normal节点。 6. normalIndex域值为一个法向量索引列表,指向Normal节点,用于设定所用的法向量。 7. normalPerVertex域值用于设定法向量是作用于每个平面的顶点,还是作用于每个平面。域值为TRUE时表示法向量作用于每个平面的顶点,预置为FALSE时表示法向量作用于每个平面。 8. ccw域用于设定平面的边界线索引的方向,其完整写法是:counterclock-wise(逆时针方向),域值为TRUE时,按逆时针方向索引,所画平面的正面面向屏幕;域值为FALSE时,按顺时针方向索引,所画平面的反面面向屏幕。缺省值为TRUE。 9. convex域用于设定所有表面是否为凸面。缺省值为TRUE。 几何体按照凹凸属性可以分为两类物体:Convex(凸面体)和Concave(凹面体)。凸面体是指在这个物体内部的任意两点之间的连接线段都不会穿出这个物体,否则称之为凹面体。凸面体包括球体、圆柱体、立方体等物体,而茶壶、地形、房屋等物体则属于凹面体。一般来说,凸面体的物体在进行模拟计算时的速度要远远快于凹面体的模拟计算速度,所以要尽可能地使用凸面体进行模拟计算。CC6浏览器就是将凹面通过细分为许多凸面来计算的。 10. solid域用于设定面造型是否为实体。域值为TRUE时,表示所建造型为实体,不需要构建其背面,浏览器将跳过对背面的绘制,从而节省运算时间;域值为FALSE时,表示所建造型不是实体,需要构建造型的背面。缺省值为TRUE。 11. creaseAngle域用于设定面造型的光滑角度,其域值为一个弧度表示的转折角,可以使邻近的两个平面的边界看上去有平滑过度。缺省值为0,表示不进行光滑处理。 12. set_coordIndex、set_texCoordIndex、set_colorIndex、set_normalIndex是面集节点的四个入事件,用于域值的动态设置。前面我们说过简单的几何造型也都是由面来构成的。在CC6浏览器中,组成圆锥体、圆柱体和球体曲面的面数是由你的计算机配置和浏览器决定的。通常,一个圆柱体的的侧面由18个或者更多的面组成,一个球体由60个或更多的面组成。浏览器可以改变造型的面数,当观察着接近造型是,浏览器就增加造型的面数;当观察着远离造型是,浏览器就减少造型的面数。这种对于面数的改变保证了造型在任何时候看上去都是光滑的,而且提高了浏览速度。而如果是用IndexedFaceSet节点创建的由面组成的圆柱、圆锥或球体,那么不管观察者离造型有多远,组成这些造型的面数都始终不变。 第四章 材质外观节点 Appearance 节点指定造型的外观属性,并可用作Shape节点appearance域的值。 Appearance域的值定义一个节点,该节点定义造型的外观,包括它的颜色和表面纹理。Appearance节点语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 Appearance{ material NULL #exposedField SFNode texture NULL #exposedField SFNode textureTransform NULL #exposedField SFNode } Appearance节点的三个域分别表示材质、纹理和纹理变换。这三个属性都是用节点来定义的,这些节点在下面节中讲述。 第一节 材质类节点 一、 材质节点 Material材质节点设定造型外观的颜色,透明度,发光度,反光度等基本材质特征,并可作为Appearance节点material域的值。重点介绍Material材质节点语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 Material{ diffuseColor 0.8 0.8 0.8 #exposedField SFColor ambientIntensify 0.2 #exposedField SFFloat specularColor 0.0 0.0 0.0 #exposedField SFColor emissiveColor 0.0 0.0 0.0 #exposedField SFColor shininess 0.2 #exposedField SFFloat transparency 0.0 #exposedField SFFloat } 域值说明: 1. diffuseColor域的域值设定物体的漫反射颜色。漫反射颜色指的是:当光照射在物体表面时,物体表面向各个方向反射的基本色彩。缺省值为(0.8 0.8 0.8)浅灰色。 2. ambientIntensify设定有多少环境光线被物体表面反射。环境光各向同性,颜色以(ambientIntensify)X(diffuseColor)计算。缺省值为0.2,表示对环境光产生较低的反射效果。 3. specularColor设定物体镜面反射光的颜色。入射角等于出射角是镜面反射的基本原理。缺省值为(0.0 0.0 0.0)黑色,表示无反射。 4. emissiveColor设定发光物体产生光的颜色。缺省值为(0.0 0.0 0.0)黑色,表示不发光。 5. shininess设定物体表面的亮度。取值范围从漫反射表面的0到高度抛光表面的1。缺省值为0.2。 6. transparency设定物体的透明度。取值范围从完全不透明的0到完全透明的1。缺省值为0,表示不透明。 Material节点缺省的NULL值表示一种发光的白色材质。 二、 色彩节点 1. Color节点 Color节点用于指定跟随在其后的节点的默认颜色。 Color {     color 1 1 1 #SFColor } color域的域值三个数值分别表示 r、g、b,即红、绿、蓝。 举例 Color{color 0 0 1} Sphere{} 1. BaseColor节点 BaseColor控制后续造型节点的颜色,在CC6文件编辑中应用广泛。 rgb 为BaseColor中的域,即:BaseColor{rgb 0 0 0} rgb的三个数值为 r、g、b 分别是红、绿、蓝 BaseColor{rgb 1 0 0 } Sphere {radius 1 } 2. PackedColor节点 PackedColor用于设置慢射和透明的材质值,该节点提供了方便的途径用32位RGBA向量设置漫射颜色和透明值。 格式: PackedColor { orderedRGBA 0xccccccff } 这是一个四元数,0x后面的每两个字母分别用于表示r、g、b、a四个属性。 第二节 纹理类节点 现实世界中充满了大量的视觉细节。例如,一棵树从远处看像一个绿色的水滴状斑点。当走近时,它分成了主干和枝叶茂盛的树冠。再近一点,树枝和一丛丛的树叶也可以看见了,接下来是一片片的叶子,叶子上的纹理,如此等等。在计算机图形中,这种视觉细节就叫纹理。为一棵树的树枝、树叶或树叶的脉络生成大量的细节造型是不实际的。因此,我们可以将现实世界中的景物图片画到,或者映射到虚拟造型上——这就叫做纹理映射技术。纹理映射可以为建模节省大量的时间,不必再为大量的视觉细节生成模型。 一、 固有色纹理 1. ImageTexture ImageTexture 图象纹理节点用于设置图象纹理的参数并将该纹理粘贴映射到造型表面。图象纹理是最简单最常用的一种纹理方式,它可以完成多种纹理效果。使用的图像文件格式有JPEG、GIF和PNG文件。 ImageTexture 图像纹理节点语法格式如下: 节点名称 域名称或事件 域值 #域及域值类型 ImageTexture{ url [ ] #exposedfield MFSting repeats TRUE #field SFBool repeat TRUE #field SFBool asynchronism TRUE #exposedfield SFBool } 域值说明: url域值指定一个由高优先级别的图象纹理文件url地址的排序表,浏览器从第一个url地址存储的图象文件试起,如果打不开或找不到文件,浏览器将尝试打开第二个url地址的图像,依此类推,直到找到一个可以打开的图像文件,将文件读入并作为图像纹理粘到造型表面。如果找不到任何一个可以打开的图像文件,或者url域值为空,则不进行纹理映射。 如果不使用textureTransform纹理变换域对纹理图进行缩放处理,浏览器会自动调整纹理图的大小使其恰好填满造型表面。只有人为对纹理图进行缩小处理,使纹理图小于造型表面时,才需要设置repeates域和repeatT域的域值,选择是否重复粘贴纹理图。 每一个纹理都有一个坐标系,有两个坐标轴:S和T,左下角为坐标系的原点(S=0,T=0),右上角为(S=1,T=1)。当纹理贴在Box上时,Box的每一个面都能看到贴图,如果没有进行特别的处理,贴图的四个端点将位于Box表面的端点上,因而贴图可能拉长或压扁。为了使纹理的效果比较好,最好将图片的点阵定为128*128或256*256。纹理贴在不同的物体上效果不同。 repeatS,repeatT用来表示是否允许纹理贴图在物体的表面上重复粘贴。 repeatS域的域值设定图像纹理是否沿S方向重复粘贴。若该域值为TRUE,图像纹理会沿S水平方向重复粘贴,直至横向填满造型表面,若域值为FALSE,图像纹理在S水平方向只粘贴一次。该域值的默认值为TRUE。 repeatT域的域值设定图像纹理是否沿T方向重复粘贴。若该域值为TRUE,图像纹理会沿T垂直方向重复粘贴,直至纵向填满造型表面,若域值为FALSE,图像纹理在T垂直方向只粘贴一次。该域值的默认值为TRUE。 2. PixelTexture PixelTexture像素纹理节点没有url域,而是利用image域将纹理直接存放在文件中,这样浏览器不必调用外部的图像文件,可以节约网络下载的时间。PixelTexture像素纹理节点以显示像素数组的形式定义一个二维像素纹理,并且设定将该纹理映射至造型表面时所需的参数。因为这种方式需要给定各点的颜色值,使用起来不方便,所以一般只用来创建简单的纹理,对于复杂的纹理图不适用。 PixelTexture像素纹理节点的语法格式如下: 节点名称 域名称或事件 域值 #域及域值类型 PixelTexture{ image 0 0 0 #exposedfield SFImage repeatS TRUE #field SFBool repeatT TRUE #field SFBool } 域值说明: image域的域值用于设定对造型进行纹理映射的像素纹理的大小、类型和像素值。该域的前三个值必须为整数,其中第一个数值表示像素纹理的横向像素个数(纹理宽度),第二个数值表示像素纹理的纵向像素个数(纹理高度),第三个数值表示像素纹理类型,可在0,1,2,3,4中选择一个。该域值的默认值为(0 0 0),表示无像素纹理。 像素纹理类型共分四种:单元,双元,三元和四元像素纹理。分别对应于像素纹理类型值1,2,3,4。单元是灰度像素纹理,使用一个字节的十六进制数据表示灰度,0xFF表示最亮,0x00表示最暗。双元是灰度加透明度像素纹理,使用两个字节的十六进制数据,第一个字节表示灰度,与单元像素纹理相同;第二个字节表示透明度,0xFF表示完全透明,0x00表示完全不透明。三元是RGB彩色像素纹理,使用三个字节的十六进制数据,每个字节分别表示颜色的R、G、B成分,如0xFF0000为红色,0x00FF00为绿色,0x0000FF为蓝色。四元是RGB彩色加透明度像素纹理,使用四个字节的十六进制数据,前三个字节表示颜色成分,第四个字节表示透明度,如0x0000FF80为半透明蓝色,0xFFFF0080为半透明黄色。 像素纹理图的颜色从左下角第一个像素开始,一直到右上角最后一个像素填满结束。例如: image 2 2 3 0xFF0000 0x00FF00 0x0000FF 0xFFFF00 表示2个像素宽,2个像素高的三元彩色像素纹理,左上角为红色,右上角为绿色,左下角为蓝色,右下角为黄色。 repeatS,repeatT用来表示是否允许像素纹理在物体的表面上重复粘贴。 repeatS域的域值设定像素纹理是否沿S方向重复粘贴。若该域值为TRUE,像素纹理会沿S水平方向重复粘贴,直至横向填满造型表面,若域值为FALSE,像素纹理在S水平方向只粘贴一次,剩余造型表面用纹理图的最后一行像素填充。该域值的默认值为TRUE。 repeatT域的域值设定像素纹理是否沿T方向重复粘贴。若该域值为TRUE,像素纹理会沿T垂直方向重复粘贴,直至纵向填满造型表面,若域值为FALSE,像素纹理在T垂直方向只粘贴一次,剩余造型表面用纹理图的最后一行像素填充。该域值的默认值为TRUE。 如果在使用像素纹理的同时又使用了Material节点设置材质,则Material中的漫反射颜色和透明度属性有可能影响像素纹理的渲染效果。 3. TextureUnit TextureUnit的意思是贴图单元声明,用来作为多层贴图的分隔。 其语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 TextureUnit{ unit n #n为单元编码,取值为0,1,2,…… mappingMethod IMAGE_MAPPING #贴图方式 图像贴图 } TextureUnit节点后面一般使用Texture2,Texture2Transform,TextureCoordinateEnvironment 等贴图及控制节点,共同组成一个贴图单元,再由多个单元组成多层贴图纹理。 4. Texture2 Texture2节点用于设定贴图单元的图像文件存储路径,并跟在TextureUnit后面共同组成一个贴图单元。该节点的语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 Texture2{ filename “ ” #exposedField SFString } 域值说明: filename域值指定一个图象地址,浏览器将文件读入并作为图像纹理粘到造型表面。如果打不开或找不到文件,或者filename域值为空,则不进行纹理映射。 5. Texture3 该节点的语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 Texture3{ } 二、 视频纹理MovieTexture MovieTexture节点用来将视频想贴图一样出现在物体表面,它具有以下属性: loop SFBool(default TRUE) 是否循环播放 speed SFFloat(default 1.0f) 播放速度,用浮点数 startTime SFTime(default 0.0f) 开始时间 stopTime SFTime(default 0.0f) 停止时间 url MFString 资源路径 repeatS SFBool TRUE repeatT SFBool TRUE duration_changed SFTime (被使用,定义与VR保持一致。返回当前播放的时间(秒),在播放的时候不停变化). isActive SFBool (is playing) 是否可用 stretch SFBool (default is FALSE). please use texture transform but this,that is hardware calculate. width SFFloat(default 0 height SFFloat(default 0 minPosition SFTime(最小重置时间,当前时间与startTime的差值大于这个时间,将会依照startTime设置当前播放点。) blendColor SFColor(default 0 0 0) model MODULATE(*this is default) | DECAL | BLEND | REPLACE duration SFTime(播放源的总时间,单位是秒). pause SFBool(True暂停播放,False继续播放,当前必须已播放,否则无法更改本值,自动变回去). volume SFFloat(声音大小,有效范围0到1.0. 1.0使用当前声音设定,0为完全听不到.缺省为1). balance SFFloat(左右平衡,有效范围-1 到 1.0 缺省为0). state SFInt32(当前的真实状态,0为未指定url.1为正在加载.2为加载失败,3为加载成功,4为正在播放,5为停止,等待缓冲或未播放或播放完毕,6为暂停). 三、 网页纹理HtmlTexture HtmlTexture继承自Texture2一致(拥有Texture2的全部属性),并扩充了如下属性. * url #SFString 指示URL (default "") * visible #SFBool 指示是否显示窗口.(default FALSE) * position #SFVec2f 指示显示窗口的左上角.(范围0 - 1.0) (default 0 0) * size #SFVec2f 指示显示窗口的尺寸.(范围0 - 1.0) (default 0.2 0.2) * readyState #SFEnum 指示当前文档的加载状态(UNINITIALIZED,LOADING,LOADED,INTERACTIVE,COMPLETE) (Event) * texture #SFBool 指示是否产生贴图.(default TRUE) * refresh #SFBool 每次设置无条件更新贴图.(default FALSE) * autohide #SFBool 当鼠标离开窗口时,是否自动隐藏.(default FALSE) * inject #SFString 要注入的代码.本HTML代码将在readyState更改为COMPLETE的时候注入.注入的代码可以完成任意工作. 例如下面这个例子: #Lyinux V1.1 gb2312 Material{ diffuseColor 1 1 1 } TextureUnit{unit 0} Texture2Transform{ translation 0 0 scaleFactor 1 1 # rotation 0.2 } #TextureCoordinateEnvironment{} HtmlTexture{ url "http://www.henhao.com/" visible FALSE position 0 0 size 1 1 readyState INTERACTIVE texture TRUE refresh FALSE autohide FALSE } Box{size 4 3 3} 这段代码的效果将网页henhao.com映成一副贴图贴在了紧跟其后的Box上,如下图所示: 如果HtmlTexture的visible为TRUE.那么HtmlTexture窗口将被显示出来.这个显示的窗口如同IE一样可以被使用.那么如何从IE环境下调用Lyinux脚本呢.我们需要在Lyinux脚本中有一个Script节点,名称为cc6->callersink.这个节点中的函数是可以被IE调用的.调用方法为window.external.XXXX(). XXXX为Script节点中的函数. 最后,有几个特殊的名字被保留: ViewerWidth ,ViewerHeight,InternalVersion. 反过来,我们也可以从Lyinux脚本中调用HTML脚本.当获取到一个HtmlTexture对象引用时,可以调用HtmlTexture方法call.用法为xxxx.call(funcNameInHTML,param1,param2...) 目前,param仅支持String,Int32,Float,Bool四个类型. 四、 凹凸纹理 BumpMap凹凸纹理节点,用于改变造型表面法线,产生表面凹凸的效果。可以使用的图像文件格式有JPEG、GIF、PNG文件。 BumpMap语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 BumpMap { filename " " #exposedField MFString } 域值说明: filename域的值指定一个凹凸纹理文件的url地址,例如filename "../maps/image.jpg",表示所用图像是位于本文件所在目录的上级目录(".."表示相对于当前文件所在目录的上级目录,无论本地还是远程)的maps目录中的image.jpg,所用图像文件的路径可以是绝对地址或相对地址。如果两者放在同一个文件目录或其子目录下,图像文件的地址可以简化为相对地址,如filename "image.jpg"。注意:如果不使用BumpMapTransform对纹理进行缩放或移动,浏览器会自动调整图像的大小比例使其填满造型的每一个表面。 五、 纹理文件格式 CC6支持四种最常见的图片文件格式来存储纹理:BMP,JPEG,GIF和PNG。 1. BMP图片文件格式 Bitmap 是最简单的格式,基本就是图像点阵的内存拷贝。没有任何压缩,也无法表示格外的数据。现在很少用BMP来做图像数据交换了。BMP格式保存的图像质量不变,文件也比较大,因为要保存每个像素的信息。 2. JPEG图片文件格式 JPEG代表“Joint Photographic Experts’ Group”是发明这种文件格式委员会的名字。JPEG图片文件格式用一种高效的存储压缩算法,设计用来存储高质量的图片。这种格式目前是最常用最流行的图片文件格式。 在PC机上,JPEG文件一般用.jpg作为文件扩展名。在UNIX系统中,JPEG文件经常使用,jpeg或.jfif作为文件扩展名。在Macintosh上,JPEG格式则用“JPEG”文件类型来表示。 3. GIF图片文件格式 GIF代表“Graphical Interchange Format”。GIF格式是CompuServe为映像分配开发的标准格式,现在在Web上随处可见,并且所有的Web浏览器都支持这种格式。GIF格式使用了普通的压缩方案来存储相对来说较低质量的图片,一般用于动态格式的图片存储。 在PC或UNIX系统中,GIF 文件一般以.gif作为文件扩展名。在Macintosh上,GIF格式以“GIFI”类型来表示。 4. PNG图片文件格式 PNG代表“Portable Network Graphics”。PNG是20世纪90年代中期开始开发的图像文件存储格式,其目的是企图替代GIF和TIFF文件格式,同时增加一些GIF文件格式所不具备的特性。名称来源于非官方的“PNG's Not GIF”,是一种位图文件(bitmap file)存储格式,读成“ping”。PNG用来存储灰度图像时,灰度图像的深度可多到16位,存储彩色图像时,彩色图像的深度可多到48位,并且还可存储多到16位的α通道数据。PNG使用从LZ77派生的无损数据压缩算法。 PNG文件格式保留GIF文件格式的下列特性: 1、使用彩色查找表或者叫做调色板可支持256种颜色的彩色图像。 2、流式读/写性能(streamability):图像文件格式允许连续读出和写入图像数据,这个特性很适合于在通信过程中生成和显示图像。 3、逐次逼近显示(Progressive Display):这种特性可使在通信链路上传输图像文件的同时就在终端上显示图像,把整个轮廓显示出来之后逐步显示图像的细节,也就是先用低分辨率显示图像,然后逐步提高它的分辨率。 4、透明性(transparency):这个性能可使图像中某些部分不显示出来,用来创建一些有特色的图像。 5、辅助信息(Ancillary Information):这个特性可用来在图像文件中存储一些文本注释信息。 6、独立于计算机软硬件环境。 7、使用无损压缩。 PNG文件格式中要增加下列GIF文件格式所没有的特性: 1、每个像素为48位的真彩色图像。 2、每个像素为16位的灰度图像。 3、可为灰度图和真彩色图添加α通道。 4、添加图像的γ信息。 5、使用循环冗余码(Cyclic Redundancy Code,CRC)检测损害的文件。 6、加快图像显示的逐次逼近显示方式。 7、标准的读/写工具包。 8、可在一个文件中存储多幅图像。 GIF和PNG都是索引色彩,也就是不直接描述象素的颜色,只是说这个点是几号颜色。另外有个索引表(调色板)给出颜色号对应的RGB颜色。有简单的压缩算法,但这种压缩仅对于连续色彩的象素(例如大块色块的图形)才有效,适用于颜色有限的图像(如商业图形/地图/漫画),对真彩色图像(如照片)不太合适。 第三节 纹理变换 一、 纹理变换节点 1. TextureTransform TextureTransform纹理坐标变换节点用于相对已有原始纹理坐标系创建一个新的纹理坐标系。该节点的功能与Transform坐标变换节点相似,可以创建一个新的纹理坐标系,通过对纹理坐标系的平移,旋转和缩放等操作,改变造型表面的纹理的位置、角度和缩放比例。该节点通常作为Appearance外观节点中textureTransform域的域值。 TextureTransform纹理坐标变换节点语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 TextureTransform { center 0 0 # exposedField SFVec2f scale 1 1 # exposedField SFVec2f rotation 0 # exposedField SFFloat translation 0 0 # exposedField SFVec2f } 域值说明: translation域的域值用于设定变换后新的纹理坐标系的原点与原始纹理坐标系在S、T方向上的距离。域值可正可负,只是方向相反而已。缺省值为(0 0),表示新的纹理坐标系与原始纹理坐标系重合,没有位移。 rotation域的域值用于设定新的纹理坐标系相对原始纹理坐标系进行旋转的角度。由于纹理映射仅在平面上进行,所以纹理坐标系的旋转可以理解为以Z轴为旋转产生的角度,以弧度为单位。缺省值为0,表示新的纹理坐标系不产生旋转。 scale域的域值用于设定新的纹理坐标系在S、T方向上的缩放系数。缺省值为(1 1),表示无缩放。 center域的域值用于设定scale,rotation,translation变化的中心点,该点是一个二维坐标点。缺省值为(0 0),表示以原始纹理坐标系的原点为中心点。 注意: 1. 所有的操作都是针对纹理坐标系进行的,而不是作用于纹理图像本身。例如,scale 2 2 并不是将纹理图像放大一倍,而是将纹理坐标系放大了一倍,其效果是将映射的纹理图像在S、T两个方向上均缩小为原来的一半。 2. 纹理坐标系的原点(0,0)在图像的左上角处,(1,1)点在图像的右下角处。 TextureTransform应用举例: Transform { children [ Shape { appearance Appearance { material Material { } texture ImageTexture {url "images/map.jpg"} textureTransform TextureTransform { translation 0.0 0.5 0.0     rotation 0 0 1 0 scale 1.0 1.0 1.0 center 0 0 0 } } geometry Box { size 4 4 4 } } ] } 1. Texture2Transform Texture2Transform 纹理贴图变换节点定义纹理贴图的二维坐标变换,该节点的功能与TextureTransform纹理坐标变换节点相似,通过对纹理坐标系的平移、旋转、缩放操作,改变贴图在造型表面上的位置、角度和缩放比例。 Texture2Transform 节点语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 Texture2Transform { center 0 0 # exposedField SFVec2f scaleFactor 1 1 # exposedField SFVec2f rotation 0 # exposedField SFFloat translation 0 0 # exposedField SFVec2f } 域值说明: scaleFactor: 指定纹理图像以center域中定义的物体中心为原点的缩放。两个轴向的缩放程度可以不同。 rotation: 指定纹理图像以center域中定义的物体中心为原点的旋转。 center: 指定纹理图像变换(平移、缩放及旋转)的中心。 translation: 指定纹理图像平移。 Texture2Transform 节点定义了对纹理坐标的变换。这个节点使用在TextureUnit之后,它影响Texture2纹理映射到物体表面的方式。这个节点中的操作的顺序是缩放、旋转、平移 。 2. Texture3Transform Texture3Transform 纹理贴图变换节点定义纹理贴图的三维坐标变换,该节点的功能与TextureTransform纹理坐标变换节点相似,通过对纹理坐标系的平移、旋转、缩放操作,改变贴图在造型表面上的位置、角度和缩放比例。 Texture3Transform节点语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 Texture3Transform { translation 0 0 0 # exposedField SFVec3f rotation 0 0 1 0 # exposedField SFRotation scaleFactor 1 1 1 # exposedField SFVec3f scaleOrientation 0 0 1 0 # exposedField SFRotation center 0 0 0 # exposedField SFVec3f } 域值说明: scaleFactor: 指定纹理图像以center域中定义的物体中心为原点的缩放。两个轴向的缩放程度可以不同。 rotation: 指定纹理图像以center域中定义的物体中心为原点的旋转。 center: 指定纹理图像变换(平移、缩放及旋转)的中心。 translation: 指定纹理图像平移。 scaleOrientation:设定纹理图像缩放时的旋转值。 3. BumpMapTransform BumpMapTransform 凹凸纹理变换节点定义凹凸纹理的二维坐标变换,该节点的功能与TextureTransform纹理坐标变换节点相似,通过对纹理坐标系的平移、旋转、缩放操作,改变造型表面凹凸纹理的位置、角度和缩放比例。 BumpMapTransform 节点语法格式如下: 节点名称 域名称或事件 域值 #域值或事件类型 BumpMapTransform { center 0 0 # exposedField SFVec2f scaleFactor 1 1 # exposedField SFVec2f rotation 0 # exposedField SFFloat translation 0 0 # exposedField SFVec2f } 域值说明: scaleFactor: 指定纹理图像以center域中定义的物体中心为原点的缩放。两个轴向的缩放程度可以不同。 rotation: 指定纹理图像以center域中定义的物体中心为原点的旋转。 center: 指定纹理图像变换(平移、缩放及旋转)的中心。 translation: 指定纹理图像平移。 BumpMapTransform 节点定义了对纹理坐标的变换。这个节点使用在BumpMap之后,它影响凹凸纹理映射到物体表面的方式。这个节点中的操作的顺序是缩放、旋转、平移。 二、 纹理坐标类节点 就像3D建模软件中用到的UVWmap, CC6还为我们提供了一些常用的纹理坐标类节点: 1. TextureCoordinate纹理坐标节点 TextureCoordinate纹理坐标节点定义了一组二维坐标,用于完成纹理和几何表面顶点间的映射。它通常用在IndexedFaceSet和ElevationGrid节点的texCoord域中。纹理图参数值沿纹理图像从0到1变化。先确定水平坐标s,然后确定垂直坐标t。 其语法格式如下: TextureCoordinate {   point [] # exposed field MFVec2f }   域值说明: point 以二维(s,t)形式给出的一组纹理坐标点,它们一般与IndexedFaceSet或ElevationGrid中的顶点构成对应关系。 在point域定义的TextureCoordinate值可以在-infinity和+infinity之间变化。如果纹理在某一方向上重复(s或t),那么纹理坐标c映射到沿指定方向有n个像素的纹理图上; location=(c - floor(c))*n 如果纹理没有重复,c被剪裁到0--1的范围内: location=max(0,min(1,c))*n 1. TextureCoordinateEnvironment TextureCoordinateEnvironment环境贴图节点,即声明本贴图单元为环境贴图,首先将该贴图贴在 “天球”(尺寸无限大的圆球)上,然后再将天球反射到物体上,以达到环境映射的效果。 该节点语法格式如下: TextureCoordinateEnvironment{} 这个节点没有域,只是起到环境贴图声明的作用,与TextureUnit,Texture2,TextureTransform等节点共同使用产生环境纹理效果。 2. TextureCoordinatePlane 它贴图的方式是以平面的计算进行物体包裹,也是一个以平面的贴图方式进行轴心的定位,它会自动的生成坐标轴心的位置,还可以设定贴图平铺的尺寸大小等。 这是一个例子的常用写法: Texture2{filename "wood08.jpg"} TextureCoordinatePlane{} Sphere{} 3. TextureCoordinateCube 它贴图的方式是以立方体的计算进行物体包裹。 这是一个例子的常用写法: Texture2{filename "wood08.jpg"} TextureCoordinateCube{} Cone{} 4. TextureCoordinateSphere 它贴图的方式是以球体的贴图方式进行的包裹,它会自动的生成坐标轴心的位置,还可以设定贴图平铺的尺寸大小等。 这是一个例子的常用写法: Texture2{filename "wood08.jpg"} TextureCoordinateSphere{} Cone{} 5. TextureCoordinateCylinder 它贴图的方式是以平面的方式进行包裹物体的,这是一个以圆柱体的贴图方式进行的包裹的例子,它会自动的生成坐标轴心的位置,还可以设定贴图平铺的尺寸大小等。 这是一个例子的常用写法: Texture2{filename "wood08.jpg"} TextureCoordinateCylinder{} Cube{} Cylinder{radius .5 height 3} 第五章 环境设计 第一节 创建背景 Background节点用来定义天空,地面和前景图到所在世界的视平线上。所有在背景上的元素像重视距离我们很遥远的样子,你不可能靠近背景上的图片。 其基本语法如下: Background{ skyColor [0 0 0] # exposed field MFColor skyAngle [ ] # exposed field MFFloat groundColor [ ] # exposed field MFColor groundAngle [ ] # exposed field MFFloat backUrl " " # exposed field MFString bottomUrl " " # exposed field MFString leftUrl " " # exposed field MFString rightUrl " " # exposed field MFString frontUrl " " # exposed field MFString topUrl " " # exposed field MFString } 天空的颜色有两个属性域决定,它们分别是skyColor和skyAngle,如果你想定义单一的天空色,只需要定义skyColor而不需定义skyAngle。SkyColor中写在第一位的颜色是天空最上方的颜色。SkyAngle只有在有梯度效果的情况下才需要,并且SkyAngle中值的数量总是比skyColor中值的数量少1。最后一个SkyColor的值被用来填充描述这个天空的球体剩余的部分。 与天空类似,地面也是由两个属性域决定,它们分别是groundColor和groundAngle。groundColor中的第一个时地面球体最下方的颜色。 backUrl, bottomUrl, leftUrl, rightUrl, frontUrlbtopUrl分别用来指定空间立方体上各个面的图片位置。通过这些属性域,可以将背景图像变得更符合场景的需求。 以下列出了一个Background的具体案例: #Lyinux V1.1 gb2312 Background { skyColor [ 0 0 1 0 0 0.6 1 0 0.0 ] skyAngle [1.2 1.57] groundColor [ 0.5 0.5 0 0.5 0.5 0 ] groundAngle [1.57] } Shape { appearance Appearance { material Material {}} geometry Box { size 20 0.01 20} } Transform { translation 0 2 -5 children Shape { appearance Appearance { material Material {}} geometry Sphere {} } } 第二节 摄像机 一、 默认摄像机 浏览一个场景,需要有摄像机的存在,在没有摄像机的情况下,CC6浏览器会为场景安排一个默认的透视摄像机,将场景中的所有物体覆盖其中。这个摄像机的位置不是固定的,但方向和视角角度是固定的。 在编写cc6文件时,可以添加订制的摄像机节点,来控制摄像机的初始位置。在脚本运行期间,可以通过相应值的变化改变摄像机的位置,角度等属性,从而改变浏览时的效果。共有两种类型的摄像机在应用中常被使用,一种是名为PerspectiveCamera的透视摄像机,另一个是名为OrthographicCamera的平行透视摄像机。下文将对这两种摄像机做进一步介绍。 二、 透视摄像机 PerspectiveCamera透视摄像机用来定义从某一个视点的透视投影。缺省地,照相机位于(0,0,1)并且沿着z轴的负向看,位置和方向域可以用于改变这些值。 heightAngle 域定义了全部观察内容的垂直角。 其默认格式如下: PerspectiveCamera { viewportMapping ADJUST_CAMERA position 0 0 1 orientation 0 0 1 0 nearDistance 1 farDistance 10 aspectRatio 1 focalDistance 5 heightAngle 0.78539819 } 其中,position定义了摄像机的位置 orientation定义了摄像机的朝向 nearDistance定义了在摄像机的视线之内,从摄像机位置到最近片段的距离。默认值为1.0,必须为正值。 farDistance定义了在摄像机的视线之内,从摄像机位置到最远片段的距离。默认值为10,必须大于nearDistance中定义的值。 aspectRatio 为摄像机定义了纵横比。 focalDistance 定义了摄像机到场景中心的距离。 heightAngle 定义了视点的垂直角度,默认值是45度 三、 平截体摄像机 FrustumCamera也就是所谓的平截体摄像机,在第三人称视角的网游中大量使用,可以用PerspectiveCamaera来模拟.为方便计,我们引入这一节点.其语法格式如下: FrustumCamera{ viewportMapping 同其它两类Camera.( CROP_VIEWPORT_FILL_FRAME | CROP_VIEWPORT_LINE_FRAME | CROP_VIEWPORT_NO_FRAME | ADJUST_CAMERA* | LEAVE_ALONE) position Vec3f 同其它两类Camera. orientation SFRotation 同其它两类Camera. aspectRatio SFFloat 同其它两类Camera. nearDistance SFFloat 同其它两类Camera. farDistance SFFloat 同其它两类Camera. focalDistance SFFloat 同其它两类Camera. left SFFloat 平截体左剪切面距离 right SFFloat 平截体右剪切面距离 top SFFloat 平截体上剪切面距离 bottom SFFloat 平截体下剪切面距离 } 四、 平行摄像机 OrthographicCamera 平行透视摄像机用来设定某一个物体总是出现在视线的前方,且随着是视线的变化而跟着变化。本节点常用于实现悬浮层或HUD效果。 其默认格式如下: OrthographicCamera { viewportMapping ADJUST_CAMERA position 0 0 1 orientation 0 0 1 0 nearDistance 1 farDistance 10 aspectRatio 1 focalDistance 5 height 2 } 其中,position定义了摄像机的位置 orientation定义了摄像机的朝向 nearDistance定义了在摄像机的视线之内,从摄像机位置到最近片段的距离。默认值为1.0,必须为正值。 farDistance定义了在摄像机的视线之内,从摄像机位置到最远片段的距离。默认值为10,必须大于nearDistance中定义的值。 aspectRatio 为摄像机定义了纵横比。 focalDistance 定义了摄像机到场景中心的距离。 height定义了高度 以下是一个用OrthographicCamera实现HUD效果的案例: #Lyinux V1.1 gb2312 Separator { PerspectiveCamera { position 0 0 5 } Separator { Translation {translation 0 0 -2} Cube { } } Separator { OrthographicCamera { position -0.7 -0.7 3 } BaseColor { rgb 1 1 0 } Sphere { radius 0.2 } } } 五、 导航节点NavigationInfo NavigationInfo导航节点创建一个观察者的替身,这个替身是不可见的。利用替身的视角,按照不同的视点导航方式,在虚拟现实的空间里漫游,浏览场景和造型。该节点对替身的外表尺寸,浏览方式,浏览速度,头灯光源等参数进行设置。 NavigationInfo导航节点语法格式如下: 节点名称 域名称或事件 域值 #域,域值或事件类型 NavigationInfo{ type ["WALK""ANY] #exposedField MFString headLight TRUE #exposedField SFBool speed 1.0 #exposedField SFFloat visibilityLimit 0.0 #exposedField SFFloat avatarSize [0.25 1.6 0.75] #exposedField MFFloat set_bind #eventIn SFBool isBound #eventOut SFBool steady FALSE #exposedField SFBool pickType PICK_ALL PICK_ALL | PICK_FRONT | PICK_BACK | PICK_FRONT | PICK_BACK ability ALL (NONE | FRREVIEW | SEEK | HOME | LIGHT | FULLSCREEN | TURN_LEFT | TURN_RIGHT | TURN_UP | TURN_DOWN | TURN_CLOCKWIZE | TURN_ANTICLOCKWIZE | MOVE_FORWARD | MOVE_BACKWARD | MOVE_LEFT | MOVE_RIGHT | MOVE_UP | MOVE_DOWN | CONTENT MENU | ALL) autoFocusTimer 1000 #自动对焦时间,用于控制焦点缓冲. WindowSize SFVec2f 窗口尺寸,可以利用这个值来计算窗口横纵比,这可以确保采用双摄像机投射的图像永远与窗口同步,不受窗口横纵比影响。不保证利用系统摄像机修改以后的正确性。请使用本值,在系统初始化时,本值会发出事件。 TouchCacheTime SFFloat (0.15) touch cache system的刷新时间,缺省是0.15秒。0则关闭touch的cache子系统。这影响所有的sensor,并不仅仅是touchSensor。 cache为智能3级cache,时间长并不会导致Sensor无法使用,只是在有效时间内,优先命中cache物体,这样,视觉上,在一个物体前相对动态的加入一个物体,则最长cache时间内,会检测到新加入的物体。 TouchCacheObject SFBool(TRUE) 是否启动对象级touch cache.缺省是启用。touch cache分为三级,首先检查是否命中缓冲三角形,然后检查是否命中缓冲对象(缓冲对象在其有效期内不受PICK_STYLE的改变而改变)。本值设定是否检查缓冲对象,当需要动态改变对象的PICK_STYLE时,最好将其设为FALSE。当对象的三角形很大(低模)时,本值对效率影响不大,当对象的三角形很小(高模)时,打开对象级cache将会获得明显的效率提升。 } 域值说明: (1)headLight域的域值用于设定是否使用场景中默认的头灯光源。该域值的默认值为TRUE,即使用默认的头灯光源;该域值若为FALSE,则关闭头灯光源。头灯源相当于一个由DirectionalLight节点创建的强度值为1.0的白色平行光源。该平行光源与观察替身同步移动、旋转,始终沿观察者替身的视线射向前方。 (2)type域的域值用于设定观察者替身的视点导航方式。共有五种方式可供选择(见表5-1):WALK(行走方式),FLY(飞行方式),EXAMINE(观察方式),ANY(任意方式)和NONE(不使用任何方式)。该域值的默认值为“WALK”和“ANY”,即浏览器以行走方式作为初始浏览状态,用户可以在浏览器的控制面板上选择切换成任何一种浏览方式。 type域值 说明 “WALK“(行走方式) 观察者的替身贴着地面移动,相当于受到重力的影响不能离开地面。浏览器控制面板上和飞行方式相关的按钮失效,变成灰色。 ”FLY“(飞行方式) 观察者的替身不能可以在整个空间里自由移动,不受地形限制 ”EXAMINE“(观察方式) 观察者的替身不能在空间里自由的移动,只允许改变观察视角,可以移动或旋转造型 ”ANY“(任意方式) 表示支持浏览器提供的任何一种浏览方式 NONE”(不使用任何方式) 表示不提供替身浏览方式,此时浏览器将关闭控制面板上提供的各种浏览方式,观察者只能以固定的视点进行观测 (3)speed域的域值用于设定观察者替身的遨游速度,单位是;CC6单位/秒。该域值的默认值为1.0 CC6单位/秒。 (4)visibilityLimit域的域值用于设定观察者替身的最大观察距离。如果观察者在最大观察距离内没有观察到任何对象,浏览器只显示背景图。在创建大的三维空间场景时,远处不必显示的造型和场景可以通过合理设置该域值而忽略掉,以便减少浏览器的运算量。该域值的默认值为0.0,表示可以观察到无穷远处。该域值的设置必须大于等于0.0。 (5)avatarSize域的域值用于设定观察者的外表参数,这些参数决定了进行碰撞检测以及穿越障碍物时观察者的可移动范围。替身的外表是一个不可见的圆柱体,该域值共用三个参数描述替身的外表尺寸,该域值的默认值为(0.25 1.6 0.75)。 avatarSize域的参数 说明 第一个参数 替身外表的高度尺寸,设置替身进行碰撞和穿越时1/2的厚度和宽度 第二个参数 替身外表的高度尺寸,设置替身视点距地面的高度 第三个参数 替身抬腿的高度,设置替身能够跨越障碍物的最高高度 (6)set_bind入事件与isBound出事件用于绑定系统导航节点。只要向指定的NavigationInfo节点的set_bind入事件发送TRUE值,该节点就将被设置为当前系统的导航节点 (7)isBound 原来的NavigationInfo节点的isBound出事件将向外发送一个FALSE值,表示不在作为当前的系统导航节点。isBound 出事件在浏览器使用该指定的导航节点时,输出事件值为TRUE。 (8)steady 设定替身造型是否可以前后左右运动。为TRUE时禁止前后左右运动,默认值为FALSE,表示替身可以自由移动。 (9)pickType指定鼠标点选时的规则。PICK_FRONT只选择相交面为正(逆时针)的物体,PICK_BACK只选择相交面为负(顺时针)的物体。 PICK_ALL(缺省)选择时忽略正面/反面信息。 (10)camCollision设定是否产生碰撞检测,默认值为TRUE,表示开启碰撞检测。 (11)ability 本场景允许的用户操作,可以使用'|'来允许多个。缺省全部允许。 (12)autoFocusTimer 1000#自动对焦时间,用于控制焦点缓冲. (13)windowSize SFVec2f 窗口尺寸,可以利用这个值来计算窗口横纵比,这可以确保采用双摄像机投射的图像永远与窗口同步,不受窗口横纵比影响。不保证利用系统摄像机修改以后的正确性。请使用本值,在系统初始化时,本值会发出事件。 (14) touchCacheTime SFFloat (0.15)touch cache system的刷新时间,缺省是0.15秒。0则关闭touch的cache子系统。这影响所有的sensor,并不仅仅是touchSensor。 cache为智能3级cache,时间长并不会导致Sensor无法使用,只是在有效时间内,优先命中cache物体,这样,视觉上,在一个物体前相对动态的加入一个物体,则最长cache时间内,会检测到新加入的物体。 (15) touchCacheObject SFBool(TRUE) 是否启动对象级touch cache.缺省是启用。touch cache分为三级,首先检查是否命中缓冲三角形,然后检查是否命中缓冲对象(缓冲对象在其有效期内不受PICK_STYLE的改变而改变)。本值设定是否检查缓冲对象,当需要动态改变对象的PICK_STYLE时,最好将其设为FALSE。当对象的三角形很大(低模)时,本值对效率影响不大,当对象的三角形很小(高模)时,打开对象级cache将会获得明显的效率提升。 第三节 灯光节点 一、 点光源 PointLight节点可以在VRML空间中创建一个点光源,光源光线将从空间中一个给定的点出发,向着空间中所有的方向发散,它可以照射一定距离内的形体,不论形体是否与PointLight同在一个局部坐标系,在PointLight节点中可以规定这个空间点光源的光照强度,光的坐标以及光线的颜色(光源颜色与物体不同材质的组合可产生特殊的显示效果)。点光源在各个方向上亮度相等,即点光源是各向同性的。 其基本语法如下: PointLight{ on SFFBool exposedField TRUE intensity SFFloat exposedField 1 color SFColor exposedField 1 1 1 location SFVec3f exposedField 0 0 0 } 域值说明: On: 用来设置在VRML空间中是否打开由这个节点所创建的光源。一个打开的光源将在VRML空间中产生相应的光照效果;反之,一个被关闭 的光源不能在VRML空间中产生任何的光照效果。缺省域值为TRUE,即这个光源是处于打开的状态。On域的域值将通过输出接口on_changed传递出去。 Intensity: 用来指定点光源的光照亮度,缺省域值为1,最大值为100,最小值为0。Intensity域的域值可以通过输入接口set_intensity进行重新设置,新的Intensity域的域值将通过输入接口intensity_changed传递出去。 Color: 用来指定点光源的颜色,缺省域值为 1 1 1,即光源光线是和太阳光一样的白光。Color域的域值可以通过输入接口set_Color进行重新设置,新的Color域的域值将通过输出接口Color_changed传递出去。 Location: 用来指定点光源的空间位置的三维坐标值,缺省域值为 0 0 0,即这个PointLight节点所创建的空间点光源将位于当前空间坐标系的原点位置上。Location域的域值可以通过输入接口set_Location进行重新设置,新的Location域的域值将通过输出接口 Location_changed传递出去。 下面是关于PointLight的例子,为了更好的验证点光源的光照效果,我们可以在点光源的周围建立一个球阵,其光照效果如图: 举例如下: #01 PointLight { on TRUE color 0 0 1 location 0 5 0 intensity 1 } #02 PointLight { on TRUE color 0 1 0 location 2.5 7.5 0 intensity 1 } DEF sphere9 Transform { children [ DEF sphere Transform { children [ Shape { appearance Appearance { material Material { diffuseColor 1 1 1 } } geometry Sphere {radius 1} } ] } Transform {translation 5 0 0 children USE sphere } Transform {translation -5 0 0 children USE sphere } Transform {translation 0 0 5 children USE sphere } Transform {translation 0 0 -5 children USE sphere } Transform {translation 5 0 5 children USE sphere } Transform {translation -5 0 5 children USE sphere } Transform {translation 5 0 -5 children USE sphere } Transform {translation -5 0 -5 children USE sphere } ]} Transform {translation 0 5 0 children USE sphere9 } Transform {translation 0 10 0 children USE sphere9 } Transform { translation 0 -1 0 children [ Shape { appearance Appearance { material Material { diffuseColor 1 1 1 } } geometry Box {size 20 0.1 20} } ] } 二、 平行光源 DirectionalLight节点可以在VRML空间中创建一个平行光源,光源光线将按照一个给定的空间方向在VRML空间中传播,DirectionalLight节点定义了一个具有指定方向的等强度的光源,就像一个探照灯。在DirectionalLight节点中可以规定这个空间聚光光源的光照强度,光照颜色和光照范围等参数。 其基本语法如下: DirectionalLight{ on SFFBool exposedField TRUE intensity SFFloat exposedField 1 color SFColor exposedField 1 1 1 ambientIntensity SFVect3f exposedField 0 direction SFVect3f exposedField 0 0 0 } 域值说明: on:用来设置在VRML空间中是否打开由这个节点所创建的光源。一个打开的光源将在VRML空间中产生相应的光照效果;反之,一个被关闭 的光源不能在VRML空间中产生任何的光照效果。缺省域值为TRUE,即这个光源是处于打开的状态。on域的域值将通过输出接口on_changed传递出去。 intensity: 用来指定点光源的光照亮度,缺省域值为1,最大值为100,最小值为0。intensity域的域值可以通过输入接口set_intensity进行重新设置,新的intensity域的域值将通过输入接口intensity_changed传递出去。 color: 用来指定点光源的颜色,缺省域值为 1 1 1,即光源光线是和太阳光一样的白光。Color域的域值可以通过输入接口set_color进行重新设置,新的color域的域值将通过输出接口color_changed传递出去。 ambientIntensity: 用来指定平行光源的环境照明强度系数,缺省域值为 0,即光源对周围的环境没有任何影响;当该域值取为 1 时表明光源产生较强的环境光照效果。ambientIntensity域的域值可以通过输入接口set_ambientIntensity进行重新设置,新的ambientIntensity域的域值将通过输出接口ambientIntensity_changed传递出去。 direction: 用来指定这个平行光源发射光线的空间方向,其给出的是一个空间点的坐标值,通过这个点和坐标原点可以确定一个空间向量,并且这个向量的方向规定为坐标原点指向给定的空间点,光源光线的方向将和这个给定的空间向量的方向相一致。缺省域值为 0 0 -1,即平行光源的光线将是沿着当前空间坐标系z轴的方向传播。direction域的域值可以通过输入接口set_direction进行重新设置,新的direction域的域值将通过输出接口direction_changed传递出去。 下面是关于SpotLight的例子,为了更好的验证平行光源的光照效果,我们可以在点光源的周围建立一个球阵,下面的例子中有一盏从上往下照射的蓝光和一盏从左往右的红光,其光照效果如图: 举例如下: #blue DirectionalLight { on TRUE color 0 0 1 ambientIntensity 0 intensity 1 direction 0 -1 0 } #red DirectionalLight { on TRUE color 1 0 0 intensity 1 direction 1 0 0 } DEF sphere9 Transform { children [ DEF sphere Transform { children [ Shape { appearance Appearance { material Material { diffuseColor 1 1 1 } } geometry Sphere {radius 1} } ] } Transform {translation 5 0 0 children USE sphere } Transform {translation -5 0 0 children USE sphere } Transform {translation 0 0 5 children USE sphere } Transform {translation 0 0 -5 children USE sphere } Transform {translation 5 0 5 children USE sphere } Transform {translation -5 0 5 children USE sphere } Transform {translation 5 0 -5 children USE sphere } Transform {translation -5 0 -5 children USE sphere } ]} Transform {translation 0 5 0 children USE sphere9 } Transform {translation 0 10 0 children USE sphere9 } Transform { translation 0 -1 0 children [ Shape { appearance Appearance { material Material { diffuseColor 1 1 1 } } geometry Box {size 20 0.1 20} } ] } 三、 锥光源 SpotLight节点可以在VRML空间中创建一个聚光光源,光源光线将从空间中一个给定的点出发,向着空间中一个给定的方向区域发散,在SpotLight节点中还可以规定这个空间聚光光源的光照强度,光照颜色和光照范围等参数. 其基本语法如下: SpotLight{ on TRUE exposedField SFFBool intensity 1 exposedField SFFloat color 1 1 1 exposedField SFColor location 0 0 0 exposedField SFVect3f direction 0 0 0 exposedField SFVect3f cutOffAngle 0.785398 exposedField SFFloat } 域值说明: on:用来设置在VRML空间中是否打开由这个节点所创建的光源.一个打开的光源将在VRML空间中产生相应的光照效果;反之,一个被关闭 的光源不能在VRML空间中产生任何的光照效果.缺省域值为TRUE,即这个光源是处于打开的状态.on域的域值将通过输出接口on_changed传递出去. intensity:用来指定点光源的光照亮度,缺省域值为1,最大值为100,最小值为0。intensity域的域值可以通过输入接口set_intensity进行重新设置,新的intensity域的域值将通过输入接口intensity_changed传递出去. color: 用来指定点光源的颜色,缺省域值为 1 1 1,即光源光线是和太阳光一样的白光.color域的域值可以通过输入接口set_color进行重新设置,新的color域的域值将通过输出接口color_changed传递出去. location: 用来指定点光源的空间位置的三维坐标值,缺省域值为 0 0 0,即这个PointLight节点所创建的空间点光源将位于当前空间坐标系的原点位置上.location域的域值可以通过输入接口set_location进行重新设置,新的location域的域值将通过输出接口location_changed传递出去. direction: 用来指定这个平行光源发射光线的空间方向,其给出的是一个空间点的坐标值,通过这个点和坐标原点可以确定一个空间向量,并且这个向量的方向规定为坐标原点指向给定的空间点,光源光线的方向将和这个给定的空间向量的方向相一致.缺省域值为 0 0 -1,即平行光源的光线将是沿着当前空间坐标系z轴的方向传播.direction域的域值可以通过输入接口set_direction进行重新设置,新的direction域的域值将通过输出接口direction_changed传递出去. CutOffAngle:用来设置这个聚光光源的聚光光锥扩散角的大小,这个扩散角就是指这个光锥的中心轴与光锥母线之间的夹角,即锥顶角的一半.该域值的单位为弧度,范围在0度(0 rad)~90度(1.570796 rad)之间,较大的域值所创建的光源将有一个较大的照明范围.缺省值为0.785398 rad,即45度.CutOffAngle域的域值可以通过输入接口set_CutOffAngle进行重新设置,新的CutOffAngle域的域值将通过输出接口CutOffAngle_changed传递出去. 下面是关于SpotLight的例子,为了更好的验证聚光光源的光照效果,我们可以在点光源的周围建立一个球阵,从四个方向分别给四种颜色的光,其光照效果如图: 举例如下: #blue SpotLight { on TRUE color 0 0 1 location -5 10 5 intensity 1 direction 1 -1 -1 cutOffAngle 1.0 } #green SpotLight { on TRUE color 0 1 0 location -5 10 -5 intensity 1 direction 1 -1 1 cutOffAngle 0.785 } #yellow SpotLight { on TRUE color 1 1 0 location 5 10 -5 intensity 1 direction -1 -1 1 cutOffAngle 0.785 } #red SpotLight { on TRUE color 1 0 0 location 5 10 5 intensity 1 direction -1 -1 -1 cutOffAngle 0.785 } DEF sphere9 Transform { children [ DEF sphere Transform { children [ Shape { appearance Appearance { material Material { diffuseColor 1 1 1 } } geometry Sphere {radius 1} } ] } Transform {translation 5 0 0 children USE sphere } Transform {translation -5 0 0 children USE sphere } Transform {translation 0 0 5 children USE sphere } Transform {translation 0 0 -5 children USE sphere } Transform {translation 5 0 5 children USE sphere } Transform {translation -5 0 5 children USE sphere } Transform {translation 5 0 -5 children USE sphere } Transform {translation -5 0 -5 children USE sphere } ]} Transform {translation 0 5 0 children USE sphere9 } Transform {translation 0 10 0 children USE sphere9 } Transform { translation 0 -1 0 children [ Shape { appearance Appearance { material Material { diffuseColor 1 1 1 } } geometry Box {size 20 0.1 20} } ] } 第四节 声音节点 一、 声音 CC6浏览器不仅支持3D场景,还支持3D声音。如果需要在场景之中添加声音,可以使用声音节点Sound。Sound节点不仅仅可以设定声音源的位置,还可以设置声音空间传播的相关属性。 其基本语法如下: Sound { exposedField SFVec3f direction 0 0 1#声音传播方向 exposedField SFFloat intensity 1#音量 exposedField SFVec3f location 0 0 0#声源位置 exposedField SFFloat maxBack 1#声音传播的最大后点 exposedField SFFloat maxFront 1#声音传播的最大前点 exposedField SFFloat minBack 1#声音传播的最小后点 exposedField SFFloat minFront 1#声音传播的最小前点 exposedField SFFloat priority 0#声音文件播放优先级 exposedField SFNode source NULL#声源 field SFBool spatialize TRUE#是否经过立体化处理 } source域指定AudioClip节点或MovieTexture节点来描述声音源 location指定了声音源的位置坐标 intensity 定义了声音的音量,其值必须在0和1之间,0时为静声,为1时最大。 direction指出了声音所指向的方向。priority提供了定义适当的声音的一种方式。这个域在不是多个声道时非常有用,它的值必须在0和1之间,值越大,优先级越高。 spatialize指出了声音被作为3D效果处理还是环境声音处理。如果是TRUE时,声音属于3D声音,否则声音将没有方向,也就是说你能通过立体声道听到声音而与位置无关。 minBack和minFront定义了最小的声音前点和声音后点。 maxBack和maxFront定义了最大的声音前点和声音后点。 二、 音频剪辑 AudioClip节点为Sound节点定义了声音源的位置和属性。CC6浏览器不仅支持如wav,mid这样的常见格式的声音源文件,同时还扩展支持了ogg格式这样的新一代声音文件。 其基本语法如下: AudioClip { exposedField SFString description "" exposedField SFBool loop FALSE exposedField SFFloat pitch 1.0 exposedField SFTime startTime 0 exposedField SFTime stopTime 0 exposedField MFString url [ ] eventOut SFTime duration_changed eventOut SFBool isActive } loop 定义了声音是否重复播放 pitch定义了声音播放时的速度,例如如果其值为3,声音播放的速度将是正常情况的3倍。这个域值允许使用正数。 startTime定义了声音的开始时间。这个时间的值是从1970年1月1日零点开始计算 stopTime定义了声音的结束时间。这个时间的值是从1970年1月1日零点开始计算 url定义了声音文件的位置。这里可以定义多个位置,浏览器将会按先后顺序降序寻找声音数据。 description是一个描述声音文件的字符串,浏览器将不会显示这些信息。 以下列出了使用声音的案例文件: #Lyinux V1.1 gb2312 Sound { source AudioClip { url "twang.wav" stopTime -1 loop TRUE } location 0 0 0 intensity 10 direction 0 0 1 minFront 5 minBack 3 maxFront 40 maxBack 20 spatialize TRUE } #盒子处于音源位置 Shape { appearance Appearance { material Material { } } geometry Box {} } 第五节 雾化节点 雾化节点用于在3D虚拟世界中添加真实感,通过属性域的设置来模拟出大气,薄雾或浓雾等效果。 其基本语法如下: Fog{ color l l l # exposed field SFColor fogType "LINEAR" # exposed field SFString # "LINEAR" "EXPONENTAL" visibilityRange 0 # exposed field SFFloat } color 定义了雾的颜色 fogType 定义了如何根据距离变化控制雾的浓度。它的值可以是:LINEAR或者 EXPONENTIAL。“LINEAR”雾随着距离线性增加,而“EXPONENTIAL”雾可以提供更接近自然的效果。 visibilityRange 定义了能见范围,即物体在多远的距离会被雾气完全遮掩。距离用户视角所在位置的差值超出了visibilityRange定义的数值很多,将会被color定义的颜色完全淹没。距离较近时物体的颜色会被定义的color色渲染,渲染的多少决定于距离的远近程度。当它的值为0时表明没有雾。 以下列出了Fog节点的使用案例: #Lyinux V1.1 gb2312 Fog { color 1 1 1 fogType "EXPONENTIAL" visibilityRange 0 } Background {skyColor 1.0 1.0 1.0 } Shape { appearance Appearance { material Material {}} geometry Box { size 20 0.01 20} } Transform { translation 0 2 5 children Shape { appearance Appearance { material Material{diffuseColor 0 1 0}} geometry Sphere {} } } Transform { translation -2 2 0 children Shape { appearance Appearance { material Material {diffuseColor 0 1 0}} geometry Sphere{} } } Transform { translation 2 2 0 children Shape { appearance Appearance { material Material {diffuseColor 1 1 0}} geometry Sphere{} } } 第六节 环境光雾节点 Environment用于设定场景中的光,雾环境,其语法格式如下: Environment{ ambientIntensity SFFloat 环境光强度,缺省是0.2 ambientColor SFColor 环境光颜色,缺省是白色1 1 1。 attenuation 后续光的衰减方式,缺省是指数衰减,0 0 1 fogType 场景雾类型,NONE* | HAZE | FOG | SMOKE fogColor 雾颜色,缺省是白色1 1 1 fogVisibility 雾的可见度,缺省是0 } 第六章 组节点 第一节 Separator Separator节点的作用在于可以将在它其中的子节点与它之外的场景隔离,在Separator节点中几乎可以包含所有其它类型的子节点,在其内部的设置,如对位置,颜色,字体的改变,不会对它之外的节点造成影响。Separator节点的使用案例如下: #Lyinux V1.1 gb2312 Separator { Translation { translation 0 5 0 } BaseColor { rgb 1 1 0 } Cube { } Translation { translation 0 5 0 } Sphere{} } Cube { } 运行后看到的效果如下图: 可以看到在Separator之内首先向上移动了5个单位坐标,接着设定了默认的颜色为黄色,然后加入了正方体形状,这之后,有加入向上移动5个单位坐标的命令,这时是在第一次移动的基础上再次移动5个单位,而且设置的默认颜色黄色仍然有效,因此再加入了一个球体时颜色始终保持不变,而位置则又比第一个黄色方块高出5个单位。在Separator之外,有加入了一个正方体,它的坐标和颜色都没有被Separator中的设定所影响。 第二节 Group Group节点是一个基本的组节点,在大括号之内的所有内容被视为一个整体,利用这个节点可以把整个场景分成条理更为清晰的树状结构。在children域中用中括号包含着Group节点的所有子节点。以下是一个Group的案例: Group节点可以用来将VRML节点汇集在一起。这样的一组节点在虚拟世界中通常是某个特定的空间场景,其基本的语法如下: Group{ addChildren MFNode eventIn removeChildren MFNode eventIn Children MFNode exposedField [ ] bboxCenter SFVect3f field 0 0 0 bboxsize SFVect3f field -1 -1 -1 } 域值说明: 1) addChildren:输入接口,将指定的节点加到组的子节点列表中。如果该节点已在组的子节点列表中,该事件被忽略。 2) removeChildren:输入接口,将指定节点从组的子节点列表中删除。如果该节点没在组的子节点列表中,该事件被忽略。 3) Children:包含于该Group节点的子节点。 4) bboxCenter:包围该组子节点的包围盒的中心。 5) bboxsize:包围该组子节点的包围盒在X、Y、Z方向的大小。 Group节点在开发Lyinux脚本过程中最大的好处在于可以使整个场景节点的构架更为清晰。 第三节 Transform Transform节点用于建立一个新的坐标,来对它的子节点进行移动,旋转及缩放操作。同时,还可以把它当作是一个组节点来使用,它包含以下一些常用属性域: 1.childre域 其中列出了所有子节点。 2.translation 域为SFVec3f类型,列出了X, Y, Z 轴的坐标。 3.rotation域为SFRotation类型,每个SFRotation类型的值共有四部分组成,前三位代表XYZ三个坐标轴,为0或为1,1时代表物体将绕该轴旋转,最后一位给出了旋转弧度。 4.scale域为SFVec3f类型,由三个数值构成,分别给出了X,Y, Z方向上的缩放系数。默认值为1 1 1。 5.scaleOrientation域为SFRotation类型,域值设定了物体在缩放之前的旋转角度。 6.center域 为SFVec3f类型,用于设定新坐标系的原点,旋转和缩放都将绕着这个中心点来执行。 7.bboxCenter域为SFVec3f类型,域值设定包围在该Transform中的所有子节点所占区域的最大包围盒的中心点坐标 8.bboxSize域为SFVec3f类型,域值设定包围在该Transform中的所有子节点所占区域的最大包围盒尺寸。 9.addChildren入事件需要接收一个MFNode类型的值,并将接收到的节点集增加到Transform的children[]中。 10.removeChilden入事件需要接收一个MFNode类型的值,并将接收到的节点集Transform的children中删除。 以下列出了使用Transform的例子: #Lyinux V1.1 gb2312 Transform { translation 0 4 0 rotation 0 1 0 0.78 scale 2 2 2 children [ Shape { appearance DEF app Appearance { material Material {} } geometry Box {} } ] } Shape { appearance USE app geometry Box{} } 本案例中,Transform中的Box在X, Y, Z轴上各放大了2倍,并沿Y轴向上平移了4个单位,旋转了并沿着Y轴旋转了约45度角。 第四节 TransformSeparator 同Separator节点一样,TransformSeparator节点的作用同样在于可以将在它其中的子节点与它之外的场景隔离,唯一不同的是TransformSeparator只能将位置设置隔离而对材质颜色等设置的隔离还是需要利用Separator来完成。还引用前一部分的例子,只是将Separator换做TransformSeparator,代码如下: #Lyinux V1.1 gb2312 TransformSeparator { Translation { translation 0 5 0 } BaseColor { rgb 1 1 0 } Cube { } Translation { translation 0 5 0 } Sphere{} } Cube { } 其效果如下 可以看出TransformSeparator中对位置的隔离起到了作用,最后插入的正方体的位置没有受到TransformSeparator节点中位置变化的影响,但TransformSeparator中改变的默认颜色,在TransformSeparator节点之外还是起了作用,最后插入的正方体也变为了黄色。 第五节 Billboard Billboard布告牌节点是一种具有特殊功能的组节点,Billboard布告牌节点中创建的各种造型,无论场景如何移动,始终面向浏览者,便于观察并引起人们的关注。因此,使用该节点创建的造型,适于作场景的提示、路标指示、布告牌、广告牌及帮助信息等。 Billboard布告牌节点语法格式如下: 节点名称 域名称或事件 域值 #域、域值或事件类型 Billboard{ children [ ] # exposedField MFNode axisOfRotation 0 1 0 # exposedField SFVec3f bboxCenter 0.0 0.0 0.0 # exposedField SFVec3f bboxSize -1.0 -1.0 -1.0 # exposedField SFVec3f addChildren #eventIn MFNode removeChildren #eventIn MFNode } 域值说明: 1)children域的域值用于设定场景中的布告牌造型列表。这些子节点创建的造型,都受Billboard节点局部坐标系的影响,始终面向浏览者。该域值的默认值为空列表,即没有布告牌造型。 2)axisOfRotation域的域值用于设定一个旋转轴。当用户移动的时候,Billboard节点自动地以其局部坐标系的Z轴围绕该轴旋转,从而保证布告牌造型始终面向浏览者。该域值的默认值为0 1 0,表示绕Y轴旋转。 3)bboxCenter域的域值用于设定包围该编组节点所有造型的包围盒的中心点坐标。其默认值为(0.0 0.0 0.0),即中心点位于当前坐标原点。 4)bboxSize域的域值用于设定包围盒子在当前坐标系中X、Y、Z方向上的尺寸。包围盒是一个立方体。该域值的默认值为(-1.0 -1.0 -1.0),即不人为设置包围盒尺寸,由浏览器自动设置。 5)addChildren入事件用于将指定的节点增加到该编组节点的子节点列表中。若该节点已在子节点列表中,则该事件将被忽略。 6)removeChildren入事件用于将指定的节点从该编组节点的子节点列表中删除。若该节点不在子节点列表中,则该事件将被忽略。 例子: Transform { children [ Billboard { children [ Shape { appearance Appearance { material Material { diffuseColor .32 .23 .27 specularColor .86 .33 .23 emissiveColor .32 .23 .27 ambientIntensity .0967 shininess .24 } } geometry Box {size 1 1 0.1} } ] } ] } Transform { translation 2 0 0 children [ Shape { appearance Appearance { material Material { diffuseColor 0 .36 .42 specularColor .31 .28 .26 emissiveColor 0 .1 .11 ambientIntensity .0133 shininess .07 } } geometry Box {size 1 1 1} } ] } 第六节 MultipleCopy MultipleCopy节点可以在不同位置重画多次它的子节点,它的好处在于多次复制它的子节点并不会占用附加的内存资源。它能够为它的这些子节点设置基本的坐标变换,例如移动,旋转,缩放,但在外形上保持一致。以下是一个应用例子: #Lyinux V1.1 gb2312 Separator { Translation { translation 0 10 0 } BaseColor { rgb 1 1 0 } Separator { MultipleCopy { matrix [ 0.866 0 -0.5 0 0 1 0 0 0.5 0 0.866 0 0 0 0 1, 1 0 0 0 0 1 0 0 0 0 1 0 5 0 0 1, ] Cube { } } } } 运行此文件时会看到两个黄色的正方体,第一个旋转了绕Y轴逆时针旋转了30度,而第二个正方体则相对沿X轴正方向平移了5个单位。案例中的Cube节点按照距阵集matrix中的四元数共复制2次,每次复制根据四元数的不同有不同的效果。 四元数矩阵中各个位置的值共同影响着形状节点最后的显示效果,以下就各种变换效果做出了说明: 沿X轴旋转矩阵: [ 1 0 0 0 0 cosø sinø 0 0 -sinø cosø 0 0 0 0 1 ] 沿Y轴旋转矩阵: [ cosø 0 -sinø 0 0 1 0 0 sinø 0 cosø 0 0 0 0 1 ] 沿Z轴旋转矩阵: [ cosø sinø 0 0 -sinø cosø 0 0 0 0 1 0 0 0 0 1 ] 如果需要将复制的某一个物体旋转角度时,只需将对应矩阵中的数值按照上述方法替代其中的数值即可。例如如果想让某一物体沿Y轴旋转45度角。计算得出它的sin和cos值均为0.7075,根据上述方法套用后得出矩阵为: [ 0.7075 0 -0.7075 0 0 1 0 0 0.7075 0 0.7075 0 0 0 0 1 ] 移动坐标: [ 1 0 0 0 0 1 0 0 0 0 1 0 X Y Z 1 ] 其中X,Y,Z分别代表X轴,Y轴,Z轴的坐标位置 整体缩放 [ 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 scale ] scale为缩放比例 第七节 Geo系列节点 Geo系列节点是为适应GIS绘制需求而引入,可以让我们建立GIS所常用的坐标系与绘制坐标系之间的关联,系统负责将坐标换算到需要绘制的地方.方便实现GIS类的需求.应3D城市规划,建筑规划等市场需求而引入。 一、 GeoCoordinate 在一个场景中GeoCoordinate可以替换Coordinate,从而产生基于GIS坐标的效果。 我们支持三个坐标系统: GD - 测地坐标,也就是经纬度坐标. UTM - 通用墨卡托坐标系,大地测绘中常用的坐标系统. GC - 也就是WGS84,GPS定位采用的标准坐标系. GeoCoordinate的语法格式如下: GeoCoordinate{ geoSystem MFString 坐标系统选择 point MFVec3f 各点的经纬与高度坐标 } 二、 GeoSeparator 类似于Transform,GeoSeparator定义了一个基于GIS坐标系的坐标变换,不同于Transform的是GeoSeparator每次都指示一个绝对变换。这首先是一个Separator,其语法格式如下 GeoSeparator{ geoSystem MFString坐标系统选择 geoCoords SFVec3f经纬与高度坐标 } 三、 GeoOrigin GeoOrigin用于将GIS坐标系统中的一个点映射到绘制坐标的原点,从而构造两个坐标系的映射关系.其语法格式如下: GeoOrigin{ geoSystem MFString 坐标系统选择 geoCoords SFVec3f 经纬与高度坐标 } 四、 GeoLocation GeoLocation类似与Translation,GeoLocation用于指定一个基于GIS坐标系统的位移。 GeoLocation的语法格式如下: GeoLocation{ geoSystem MFString坐标系统选择 geoCoords SFVec3f 经纬与高度坐标 } 下面我们举一个例子,来体现地理坐标的用处。 #Lyinux V1.1 gb2312 GeoOrigin { geoSystem "GD" geoCoords 39.92 116.46 0 } GeoSeparator { # 北京 geoSystem "GD" geoCoords 39.92 116.46 0 BaseColor { rgb 0 1 0 } Sphere { radius 2000} Transform{ translation 0 0 10000 children[ Text2 { string "北京" } ] } } GeoSeparator { # 昌 平 geoSystem "GD" geoCoords 40.22 116.2 0 BaseColor { rgb 1 0 0 } Sphere { radius 2000} Transform{ translation 0 0 10000 children[ Text2 { string "昌平" } ] } } GeoSeparator { # 房 山 geoSystem "GD" geoCoords 39.72 115.98 0 BaseColor { rgb 0 1 1 } Sphere { radius 2000} Transform{ translation 0 0 10000 children[ Text2 { string "房山" } ] } } 第八节 细节层次控制 一、 LOD 在创建VRML虚拟现实空间造型的时候,需要兼顾浏览器的渲染速度和造型刻画真实度之间的关系。造型刻画越细致就越接近于现实,然而相应的VRML文件的体积也越大,浏览器的渲染速度就越低,占用计算机CPU的时间就越长,LOD(Level of Detail)细节层次控制节点主要任务就是解决这个问题,该节点可以根据浏览者与造型距离的远近,选择按照不同的细致度刻画的造型。当造型距离比较的时候,选择用较低层次细节描述方法创建的造型,忽略一些细节而只刻画造型的轮廓,形状和大小,这与在真实世界中的观察极为相似。远距离的物体只能看到模糊的轮廓而不到细节,可以减小造型文件的体积,提高浏览器的速度。当造型距离比较近的时候,选择用较高层次细节描述方法创建的造型,清晰地刻造型的纹理和细微特征,保证造型描述的逼真性,这一点也与我们在真实世界中的观察相一致,物体距离越近,能够看到的细节越多,越清晰。 LOD细节层次节点语法格式如下: 节点名称 域名称或事件 域值 #域及域值类型 LOD{ level [ ] #exposedField MFNode center 0 0 0 # exposedField SFVec3f range [ ] # exposedField MFFloat whichChoice [ ] # exposedField SFInt32 } 域值说明: (1)level用于设定细节层次造型列表。 (2)center用于设定细节层次造型的中心点坐标。该坐标作为参照点,用于计算浏览者与造型之间的距离。 (3)range域的域值用于设定浏览者与造型之间距离的列表。浏览器依据这个距离列表选择需要显示的level域中的不同细节层次的造型。 (4)whichChoice域的域值用于跟踪当前哪个造型被激活。按照先后顺序从0开始,修改这个域不会导致激活造型的变化,会在下次渲染时自动重置为当前激活造型。 举个例子来看, #Lyinux V1.1 gb2312 Background { skyColor 0 0.7 0.8} LOD { level [ Inline {url "带刻度的钟表造型.cc6"} Inline {url "clock2.wrl"} Inline {url "clock3.wrl"} ] range [ 20 40] } Shape { appearance Appearance { material Material {diffuseColor 0.6 0.2 0.2} } geometry Box {size 4 4 2} } Transform { translation 0 0 1.1 children [ Shape { appearance Appearance { material Material { diffuseColor 0.5 0.3 0 } } geometry Sphere { radius 0.1 } } Transform { translation 0 085 0 children [ Shape { appearance Appearance { material Material { diffuseColor 0.5 0.5 0.7 } } geometry Cylinder { height 1.5 radius 005 } } ] } Transform { translation 0.6 0 0 rotation 0 0 -1 1.57 children [ Shape { appearance Appearance { material Material { diffuseColor 0.5 0.5 0.7 } } geometry Cylinder{ height 1.0 radius 0.05 } } ] } ] } Shape { appearance Appearance { material Material { diffuseColor 0.5 0.2 0.2 } } geometry Box {size 4 4 2 } } 二、 LevelOfDetail LevelOfDetail 是一个与LOD类似的节点,从VRML 1.0系统中集成而来。用于设定相应物体随着其离摄像机距离的远近显示不同的模型。 LevelOfDetail { screenArea [ 2000, 500, 50 ] #确定切换距离,三点分割成4个距离,需要四个子模型。 DEF version-0 Separator { # 复杂图形的版本 } DEF version-1 Separator { # 开始简化 } DEF version-2 Separator { # 比较远了 } DEF version-3 Separator { # 最简化版本。 } } 举例: #Lyinux V1.1 gb2312 LevelOfDetail { screenArea [ 19000, 6000, 400 ] Shape { appearance DEF BLUE Appearance { material Material { diffuseColor 0 0 1 } } geometry Box {} } Shape { appearance USE BLUE geometry Sphere {} } Shape { appearance USE BLUE geometry Cone {} } Shape { appearance USE BLUE geometry Cylinder {} } } 第九节 小结 以上我们讲述了关于创建一个逼真的虚拟现实场景的必备知识,包括各种造型节点、组节点和环境设计节点。 动画篇 第七章 动画节点 第一节 事件和路由的基本概念 对象是具有属性(比如高度、宽度、颜色等)、方法(可以进行的行为动作)的实体。在Lyinux中的节点就是对象。 有的对象具有接收和发出信息的功能,对象收发信息是通过对象本身的事件完成的。事件是操作者、节点、系统本身、程序代码产生的行为动作。比如说点击鼠标是事件,由操作者施加;时间传感器的定时时间是事件,由系统本身产生;坐标值变化是事件,可由节点(如位置插补器节点)产生。 一些节点通过产生事件来响应环境的变化或者用户的交互。事件路由机制与场景层级分离,使得它可以去影响其它节点。能够接收入事件的节点,都至少应具有类型为eventIn或exposedField的域,同样,能够发出事件的节点,都至少应具有类型为eventOut或exposedField的域。当事件发生时,产生这个事件的节点输出一个或一组值,值的数据类型取决于这个事件的数据类型。事件传递给某一个节点,由这个节点决定这个事件应该做什么来处理这些值。一旦事件产生,事件将按时间顺序被传送给它们的路由目的地(TO之后的部分),并且接收的节点作相应处理。这个处理可能是改变节点的状态,产生新的事件,或者改变场景的结构。 入事件和出事件需要经过路由连接起来。路由是一种简单的方式,通过在一个节点产生的事件和一个节点要接收的事件间定义一条路径来实现,用ROUTE … TO … 语句格式来实现,格式如下: ROUTE 出事件TO 入事件 注意:在同一ROUTE语句中出现的出事件和入事件的数据类型必须一致,否则就会出错。 一个动画的事件传递路径一般为下图所示: 触发:产生一个事件。通常是一些传感器(Sensor) 逻辑:事件上的处理。通常是Script节点 计时:告知TimeSensor节点开始计,接着产生时间事件 引擎:路由时间事件给那些需要运动相关的节点,通常是一些插入器(Interpolator) 目标:浏览器传递由引擎发出的输出给相关的节点,节点的域值根据收到的值作相应变化。 事件和路由构成了CC6的动画体系,这个体系再加上交互传感器和脚本,就构成了CC6的交互体系,然后再加入原型和网络通信部分,才能构成一个整体的CC6结构体系。 第二节 时间传感器 一、 TimeSensor TimeSensor { exposedField SFTime cycleInterval 1 # (0,)每个周期的长度 exposedField SFBool enabled TRUE exposedField SFBool loop FALSE#是否循环 exposedField SFTime startTime 0 # (-,)起始时间 exposedField SFTime stopTime 0 # (-,)终止时间 eventOut SFTime cycleTime eventOut SFFloat fraction_changed #当前时间的完成比(从0到1) eventOut SFBool isActive #是否在运行 eventOut SFTime time } 效果:当时间经过时会发出事件,时常用于动画的生成,控制周期性事件,和执行一次性事件 二、 DrawSensor DrawSensor{ enabled TRUE # exposedField SFBool 是否有效 pause FLASE # exposedField SFBool 暂停开关 cycleInterval 1 # exposedField SFTime时间周期 loop 1 # exposedField SFInt32循环次数,0表示无限循环 startTime 0 # exposedField SFTime起始时间 stopTime 0 # exposedField SFTime终止时间 cycleCount # eventOut SFInt32 循环计数器。(每个循环开始的时候记数) fraction_changed # eventOut SFFloat当前时间的完成比(从0到1) isActive # eventOut SFBool是否在运行 time # eventOut SFTime 运行时输出当前时间 } loop域值 startTime, stopTime, cycleInterval的关系 运行状态 TRUE startTime ≥stopTime 无限循环 TRUE startTime <stopTime 循环到stopTime为止 FLASE startTime ≥stopTime 只运行一个周期 FLASE startTime <(startTime+ cycleInterval)≤stopTime 只运行一个周期 FLASE startTime < stopTime <(startTime+ cycleInterval) 不到一个周期,stopTime为止 DrawSensor确保随着时间的流动在isActive=false前会发出fraction=1.0。这将使得使用DrawSensor驱动的动画无需响应isActive来设置终值。 域pause说明:当pause为true时,当前sensor暂停,当设为false时,当前sensor继续.需要注意的是:如果有暂停行为,time域不再恒等于当前时间,而是等于当前时间减去总共暂停的时间.暂停仅仅在isActive(TRUE)->isActive(FALSE)的一个循环中有效,跨越这一循环,pause自动清除 第三节 坐标系变换类 一、 PositionInterpolator PositionInterpolator位置插补器节点用于产生场景造型位移的动画效果。该节点并不创建造型,可以作为任何组节点的子节点。 PositionInterpolator位置插补器节点语法格式如下: PositionInterpolator{ key [ ] #exposedField MFFloat keyValue [ ] #exposedField MFVec3f set_fraction #eventIn SFFloat value_changed #eventOut SFVec3f enable TRUE #exposedField SFBool } 域值说明: (1)key域的域值用于设定一组时间关键点的列表。每一个关键点是一个浮点时刻值,与set_fraction相对应。时刻值一般在 0.0~1.0范围内取值,代表一个时间周期中的相对时刻,要求依次递增排列。该域值默认值为空列表。 (2)keyValue域的域值用于设定一组关键位置的列表。每一个关键位置都是一组三维坐标值,与key域的时间关键点一一对应。该域值默认值为空列表。 (3)set_fraction为入事件,用于不断接收来自时间传感器发出的时刻比例数值。 (4)value_changed为出事件,用于输出计算后新的位置的坐标值。 (5) 当enable为TRUE时,value_changed才会与set_fraction连动。 样例文件中,用两个长条的box表示坐标系,小球在坐标系中做平移运动,文件中还用到了TimeSensor节点和ROUTE功能。 例: #Lyinux V1.1 gb2312 DEF x Shape { geometry Box {size 20 .1 .1} } DEF y Shape { geometry Box {size .1 20 .1} } DEF ball Transform { children [ Shape { appearance Appearance { material Material { diffuseColor .63 .8 0 specularColor .5 .5 .5 emissiveColor .12 .15 0 ambientIntensity 0 } } geometry Sphere {} } ] } DEF time TimeSensor {cycleInterval 2 loop TRUE } DEF move PositionInterpolator { key [0 .25 .5 .75 1] keyValue [0 0 2,3 0 2,3 3 2, 0 3 2,0 0 2] } ROUTE time.fraction_changed TO move.set_fraction ROUTE move.value_changed TO ball.translation 二、 OrientationInterpolator OrientationInterpolator朝向插补器节点用于产生场景造型旋转的动画效果。该节点并不创建造型,可以作为任何组节点的子节点. OrientationInterpolator颜色插补器节点语法格式如下: 节点名称 域名称或事件 域值 #域、域值或事件类型 OrientationInterpolator{ key [ ] #exposedField MFFloat key Value [ ] #exposedField MFVec3f set_fraction #eventIn SFFloat value_changed #eventOut SFVec3f enable [TRUE] #exposedField SFBool } 域值说明 (1)key域的域值用于设定一组时间关键点的列表.每一个关键点是一个浮点时刻值,与set_fraction相对应.时刻值一般在0.0~1.0范围内取值,代表一个时间周期中的相对时刻,要求依次递增排列. (2)key Value域的域值用于设定一组三维旋转关键值的列表.一组旋转关键值包含四个数值,分别代表X ,Y, Z三个轴和旋转的角度. (3)set_fraction为入事件,用于不断接收来自时间传感器发出的时刻比例数值. (4)value_changed为出事件,用于输出计算后新的旋转值子列表. (5)当enable为TRUE时,value_changed才会与set_fraction连动。 例: #Lyinux V1.1 gb2312 Transform{ children[ DEF Shape{ appearance Appearance{ material Material{} } geometry Cylinder{ height 5 radius 0.2} } ] } DEF bar2 Transform{ children USE b } DEF clock TimeSensor{ cycleInterval 9 loop TRUE } DEF path1 OrientationInterpolator{ key [0 0.5 1] key Value[0 0 1 0 0 0 1 3.14 0 0 1 6.28] } DEF path2 OrientationInterpolator{ key [0 0.5 1] key Value[ 0 0 1 1.57 0 0 1 4.71 0 0 1 7.85] } ROUTE clock.fraction_changed TO path1.set_fraction ROUTE clock.fraction_changed TO path2.set_fraction ROUTE path1.value_changed TO bar1.rotation ROUTEpath2.value_changed TO bar2.rotation 第四节 参数变换类 一、 SCALARINTERPOLATOR ScalarInterpolator标量插补器节点用于产生标量改变的动画.适合对用简单浮点值定义的域值参数(如宽度,高度,半径,亮度和透明度)进行动画控制,例如改变造型的透明度等.该节点不创建造型,可以作为任何组节点的子节点. ScalarInterpolator标量插补器节点语法格式如下: 节点名称 域名称或事件 域值 #域 域值或事件类型 ScalarInterpolator{ key [] #exposedField MFFloat key Value [] #exposedField MFFloat set_fraction #eventIn SFFloat value_changed #eventIn SFFloat enable [TRUE] #exposedField SFBool } 域值说明 (1)key域的域值用于设定一组时间关键点的列表.每一个关键点是一个浮点时刻值,与set_fraction相对应.时刻值一般在0.0~1.0范围内取值,代表一个时间周期中的相对时刻,要求依次递增排列,默认值为空. (2)key Value域的域值用于设定一组浮点值.每一个浮点值与key域的时间关键点一一对应.该域值的默认值为空列表. (3)set_fraction为入事件,用于不断接收来自时间传感器发出的时刻比例数值. (4)value_changed为出事件,用于输出计算后新的旋转值子列表. (5)当enable为TRUE时,value_changed才会与set_fraction连动。 例: #LyinuxV1.1 gb2312 Background { skyColor 1 1 1 } DEF box Transform { children [ Shape { appearance Appearance { material Material { diffuseColor 1 1 0} } geometry Box {size 1.5 1.5 1.5} } ] } Transform { scale 1.2 2 1.2 children [ Shape { appearance Appearance { material DEF ball Material { diffuseColor 1 0 0 transparency 0.4} } geometry Sphere {radius 1.5} } ] } DEF clock TimeSensor { cycleInterval 8 loop TRUE } DEF path1 ScalarInterpolator { key [0 0.2 0.6 1 0] } DEF path2 OrientationInterpolator { key [ 0 0.125 0.25 0.375 0.5 0.625 0.75 0.875 1 ] keyValue [ 1 1 0 0 1 1 0 0.79 1 1 0 1.57 1 1 0 2.35 1 1 0 3.14 1 1 0 3.93 1 1 0 4.71 1 1 0 5.49 1 1 0 6.28 ] } ROUTE clock.fraction_changed TO path1.set_fraction ROUTE clock.fraction_changed TO path2.set_fraction ROUTE path1.value_changed TO ball.transparency ROUTE path2.value_changed TO box.rotation 二、 COLORINTERPOLATOR ColorInterpolator颜色插补器用于产生场景造型旋转的动画效果。该节点并不创建造型,可以作为任何组节点的子节点。 ColorInterpolator颜色插补器节点语法格式如下: 节点名称 域名称或事件 域值 #域、域值或事件类型 ColorInterpolator { key [] # exposedField MFFloat从0到1的一组浮点数 keyValue [] # exposedField MFColor它将随着key值得变化而从一个值变化到另一个值,与key值数量对应 set_fraction # eventIn SFFloat一般接收一个TimeSensor发出的fraction_changed事件 value_changed # eventOut SFColor当keyValue中的值开始随着key值变化而变化时,该事件发出 enable TRUE # exposedField SFBool当enable为TRUE时,value_changed才会与set_fraction连动。 } 常用格式: DEF colorChanging ColorInterpolator { key [ 0, 0.5, 1] keyValue [ 0 1 0, 1 1 1, 0 1 0] } 效果:随时间的完成比的变化,key的值从0到1,使对应keyValue的颜色值随之变化。 例 #Lyinux V1.1 gb2312 DEF PITCH_HALF_TRANS Transform { children [ Transform { translation -3 1.5 -5 children [ Shape { appearance Appearance { material DEF HALFMATERIAL Material { ambientIntensity 1 diffuseColor 0 1 0 } } geometry DEF HALF Box { size 1 1 0.1 } } Transform { children Shape { appearance Appearance { material Material { ambientIntensity 1 diffuseColor 0 0 0 } } geometry Text { string ["click" "me"] fontStyle FontStyle { size 0.2 } } } translation -0.35 -0.1 0.07 } ] } DEF TOUCHHALF TouchSensor { } DEF HALFTIMER TimeSensor { cycleInterval 1.0 } DEF HALFFLASH ColorInterpolator { key [ 0, 0.5, 1] keyValue [ 0 1 0, 1 1 1, 0 1 0] } ] } ROUTE TOUCHHALF.touchTime TO HALFTIMER.set_startTime ROUTE HALFTIMER.fraction_changed TO HALFFLASH.set_fraction ROUTE HALFFLASH.value_changed TO HALFMATERIAL.set_diffuseColor 第五节 坐标插补器 CoordinateInterpolator坐标插补器节点用于设定各点的运动轨迹,形成变形动画。 语法格式如下: CoordinateInterpolator { set_fraction #eventIn SFFloat key [] #exposedField MFFloat keyValue [] #exposedField MFVec3f value_changed #eventOut MFVec3f enable [TRUE] #exposedField SFBool #当enable为TRUE时,value_changed才会与set_fraction连动。 } 效果:随时间的完成比的变化,key的值从0到1,使对应keyValue的点坐标值随之变化。举例如下: #Lyinux V1.1 gb2312 DirectionalLight { ambientIntensity 1} Shape { geometry IndexedFaceSet { solid FALSE coord DEF CD_1 Coordinate { point [ -2 -2 2, -2 2 2, 2 2 2, 2 -2 2, -2 -2 -2, -2 2 -2, 2 2 -2, 2 -2 -2 ] } coordIndex [ 0 1 2 3 -1, 4 5 6 7 -1,0 1 5 4 -1, 7 6 2 3 -1, 0 4 7 3 -1, 1 5 6 2 ] color Color { color [ 0 0 1, 0 1 0, 0 1 1, 1 0 0, 1 0 1, 1 1 0, 1 1 1, 0 1 0 ] } } } DEF COD_INT CoordinateInterpolator { key [ 0 0.25 0.5 0.75 1 ] keyValue [ -2 -2 2, -2 2 2, 2 2 2, 2 -2 2, -2 -2 -2, -2 2 -2, 2 2 -2, 2 -2 -2, -2 -2 -2, 0 0 2, 0 0 2, 2 -2 -2, -2 2 -2, 0 0 2, 0 0 2, 2 2 -2, 0 2 0, -2 -2 -2, 2 -2 -2, 0 2 0, 0 2 0, -2 -2 2, 2 -2 2, 0 2 0, -2 2 2, 0 0 -2, 0 0 -2, 2 2 2, -2 -2 2, 0 0 -2, 0 0 -2, 2 -2 2, -2 -2 2, -2 2 2, 2 2 2, 2 -2 2, -2 -2 -2, -2 2 -2, 2 2 -2, 2 -2 -2 ] } DEF TIMER TimeSensor { cycleInterval 6 loop TRUE } ROUTE TIMER.fraction_changed TO COD_INT.set_fraction ROUTE COD_INT.value_changed TO CD_1.set_point 第六节 法向量插补器 NormallInterpolator法向量插补器节点用于产生光线明暗变化的动画效果.该节点并不创建造型,可以作为任何组节点的子节点. NormallInterpolator 插补器节点语法格式如下 节点名称 域名称或事件 域值 #域 域值 或事件类型 NormallInterpolator{ key [ ] #exposedField MFFloat keyValue [ ] #exposedField MFVec3f set_fraction #eventIn SFFloat value_changed #eventOut SFVec3f enable [TRUE] # exposedField SFBool } 域值说明 (1)key域的域值用于设定一组时间关键点的列表.每一个关键点是一个浮点时刻值,与set_fraction相对应.时刻值一般在0.0~1.0范围内取值,代表一个时间周期中的相对时刻,要求依次递增排列. (2)key Value域的域值用于设定一组法向量的列表.每一个法向量都包含X,Y,Z三个分量,关键法向量与key域的时间关键点一一对应. (3)set_fraction为入事件,用于不断接收来自时间传感器发出的时刻比例数值. (4)value_changed为出事件,用于输出计算后新的法向量子列表. (5)当enable为TRUE时,value_changed才会与set_fraction连动。 例: #Lyinux V1.1 gb2312 Shape { appearance Appearance { material Material { diffuseColor 1 1 0 } } geometry IndexedFaceSet { coord Coordinate { point [ -2 -2 0 2 -2 0 2 2 0 -2 2 0] } colorIndex [0 1 2 3] normal DEF bright Normal { vector [0 0 1] } normalPerVertex FALSE } } DEF clock TimeSensor { cycleInterval 6 loop TRUE } DEF path NormalInterpolator { key [0 0.5 1] keyValue [0 0 1 0 1 1 0 1 0] } ROUTE clock.fraction_changed TO path.set_fraction ROUTE path.value_changed TO bright.vector 第八章 骨骼节点 第一节 骨骼动画介绍 骨骼动画(Skeletal Animation),又叫Bone Animation,它与关键帧动画(Key-frame Animation)相比,占用空间小,因为它不需要象关键帧动画那样要存储每一帧的各个顶点的数据,而是只需要存储每一帧的骨骼,骨骼与顶点相比,当然要少得多。所以骨骼动画有很多优势,当然其技术难度也很高。不管是在游戏、电影动画还是虚拟现实中,生动逼真的动画(人、动物等)会使之增色不少。 骨骼动画的实现思路是从我们人的身体的运动方式而来的。动画人物的身体(肉、皮肤)是一个网格(Mesh)模型,网格的内部是一个骨架结构。当人物的骨架运动时,身体就会跟着骨架一起运动。骨架是由一定数目的骨骼组成的层次结构,每一个骨骼的排列和连接关系对整个骨架的运动有很重要的影响。每一个骨骼数据都包含其自身的动画数据。和每个骨架相关联的是一个“蒙皮”(Skin)模型,它提供动画绘制所需要的几何模型(Vertex, Normal, etc.)和纹理材质(Material)信息。每个顶点都有相应的权值(Weight),这些权值定义了骨骼的运动对有关顶点的影响因子。当把动画人物的姿势和全局运动信息作用到骨架上时,这个“蒙皮”模型就会跟随骨架一起运动。 第二节 Bone 引入一个骨骼模型。其定义如下: Bone{ skeleton SFString 定义了骨骼文件的路径。 base SFString 支持基础路径,如果不指定,以当前路径为基路径。 animation MFString 指定动画文件路径。 mesh MFString 指示绑定的Mesh信息文件路径。 material MFString 指示绑定的材质信息(包含贴图,贴图路径处理同Bone). meshSet MFInt32 以-1为分割符的Mesh集合,方便整体替换。可不设(全部绑定) materialSet MFInt32 以-1为分割符的材质集合,方便整体替换材质,可不设(全部绑定)。 loading SFBool 是否正在加载骨骼信息.开发者可以通过本域来显示一些加载信息. appendMaterialSet MFInt32 追加一组以-1为分割符的材质集合,可以运行期增加。需要注意顺序与mesh顺序一致。因此建议动态mesh放在后边。追加之后可以使用BoneInstance.materialSet来引用新定义的材质组。 boneParts MFInt32 (推荐)用于保存本骨骼组中各部件的数量。其长度为本骨骼组中总共拥有的部件类型数量。本域仅提供存储空间,推荐骨骼定义者填写本域信息并且骨骼实例使用本域来动态判定。 } 第三节 BoneInstance 然后引入一个骨骼实例: BoneInstance{ classname SFString 骨骼类名。使用DEF xxx Bone 定义的xxx. classnode SFNode 骨骼类,优先级高于classname(classname/classnode使用一个即可) meshSet SFInt32 使用的meshSet.(缺省0). attachMesh SFInt32 绑定一个新的Mesh. detachMesh SFInt32 删除一个Mesh. materialSet SFInt32 使用的材质集合号。 meshMaterial SFVec2f 虽然是2f,但是我们将其作为SFVec2d来对待.设定meshIndex对应的material的Index. lod SFFloat lod信息(1为最细,0为不显示). animation SFVec3f 执行一个动画. 0是动画ID,1是淡入时间,2是淡出时间. animationCycle SFVec3f 循环执行一个动画.0是动画ID,1是动画权重,2是延迟时间. animationClear SFVec2f 删除一个动画,0是动画ID,1是淡出时间. animationClear SFVec2f 删除一个动画,0是动画ID,1是淡出时间. animRemove SFInt32 删除一个执行动画。(eventIn) animInterp SFFloat 动画当前插值。范围(0,1.0). (eventOut) animTime SFTime 动画持续时间。单位(秒). (eventOut) animOver SFBool 一次动画播放完毕时设置TRUE. (eventOut) refreshTime SFTime 最小刷新间隔.(缺省0,即全力更新). speed SFFloat 速度倍率. selfMaterial SFBool (default TRUE).使用自身的材质属性。(设为FALSE,则使用最近的材质属性). BBoxCheckTimer? SFInt32 检测间隔.由于骨骼大多在动,因此本Timer为1000(1s). attachedMesh MFInt32 保存了当前绑定的网格.脚本设定本值将导致批量绑定指定网格(旧网格绑定被清除). } 这样就可以构建出一个带有骨骼、网格、贴图和动画的造型,并可以通过Script节点对其进行控制。 交互篇 第九章 传感器节点 第一节 TouchSensor TouchSensor触摸传感器节点用于感知用户鼠标触发的动作。当用户用鼠标触摸、单击、按下、松开被感应的造型时,将触发一个动画插补器节点,造型会产生各种动画效果。 节点语法格式如下: TouchSensor { enabled TRUE #exposedField SFBool isOver #eventOut SFBool isActive #eventOut SFBool touchTime #eventOut SFTime hitPoint_changed #eventOut SFVec3f hitNormal_changed #eventOut SFVec3f hitTexCoord_changed #eventOut SFVec3f } 域值说明: enabled域的域值用于设定传感器的开关,该域值为TRUE时,表示传感器处于打开状态,对用户的操作行为做出反应并产生各种事件输出。该域值为FALSE时,表示传感器处于关闭状态,对用户的操作行为无反应。默认该值为TRUE。 isOver为出事件,当用户移动鼠标到被感应的造型上时,引发isOver=TRUE的事件;鼠标离开时,引发isOver=FALSE的事件。 isActive为出事件,当用户在被感应的造型上按下鼠标按键时,引发isActive=TRUE的事件;松开按键时,引发isActive=FAlse的事件。 touchTime为出事件,当用户在被感应的造型上点击鼠标左键放开后,引发该事件,所发送的是当前时间。 hitPoint_changed为出事件,当用户在被感应的造型上点击鼠标左键时,引发该事件,所发送的是造型上点击处的坐标。 hitNormal_changed为出事件,当用户在被感应的造型上点击鼠标左键时,引发该事件,所发送的是造型上点击处的法向量。 hitTexCoord_changed为出事件,当用户在被感应的造型上点击鼠标左键时,引发该事件,所发送的是造型上点击处的纹理坐标。 在样例文件中,hitPoint_changed出事件发送鼠标在造型上的坐标,赋予小正方体,使其随鼠标在造型上移动,isActive出事件引发小正方体旋转。 例: #Lyinux V1.1 gb2312 Background {skyColor 1 1 1} DEF ball Transform { children [ Shape { appearance Appearance { material Material { diffuseColor .33 .3 .28 specularColor .31 .25 .13 ambientIntensity .687 shininess .1 } } geometry Box {} } DEF touch TouchSensor { enabled TRUE } # 设定触摸传感器 DEF time TimeSensor { # 设定时间传感器 cycleInterval 1 loop TRUE enabled FALSE } DEF cycle OrientationInterpolator { # 设定朝向插补器,产生旋转动画 key [0 .25 .5 .75 1] keyValue [0 0 1 0 0 0 1 1.571 0 0 1 3.142 0 0 1 4.713 0 0 1 6.282 ] } ] ROUTE touch.isActive TO time.enabled #按下鼠标左键事件 ROUTE time.fraction_changed TO cycle.set_fraction ROUTE cycle.value_changed TO ball.rotation } DEF bigbox Transform { children [ Shape{ appearance Appearance { material Material { diffuseColor 1 .45 .4 specularColor .69 .4 .42 ambientIntensity .153 shininess .9 } } geometry Box {size 20 20 1} } DEF touchball TouchSensor {} ] ROUTE touchball.hitPoint_changed TO ball.translation # 输出造型上鼠标所在坐标 } 第二节 PlaneSensor 节点默认结构: PlaneSensor { exposedField SFBool autoOffset TRUE exposedField SFBool enabled TRUE exposedField SFVec2f maxPosition -1 -1 exposedField SFVec2f minPosition 0 0 exposedField SFVec3f offset 0 0 0 eventOut SFBool isActive eventOut SFVec3f trackPoint_changed eventOut SFVec3f translation_changed } PlaneSensor可以实现物体在Z轴为0的平面内(XY轴组成的平面)进行移动。拖动的物体需要为PlaneSensor的兄弟节点,并需要使用ROUTE或者脚本在PlaneSensor与需要移动的物体之间建立关系。其主要域和事件如下: 域 minPosition 是一个2维坐标,限定在xy平面内运动时向上和向右的translation事件。 maxPosition是一个2维坐标,限定在xy平面内运动时向下和向左的translation事件。 当设minPosition 与maxPosition值在X或Y方向相等时,可以实现物体在一维空间中的运动,即沿着Y或X方向运动,实际中可以用来制作例如一个来回滑动的调节按钮。 enabled 指示传感器当前是否有效,当设为FALSE时将关闭传感器,传感器将不再跟踪用户输入或送出的事件。 offset 该域指出关物体被移动后相对于初始点的位置。 autoOffset 指示是否在拖动结束时自动保存当前位置(TRUE表示跟踪)。若autoOffset值为FALSE,则用户每次开始新一轮拖动时,被拖动的物体会先自动复位到初始位置。 事件 isActive指示鼠标是否按下。此事件仅当鼠标按下或释放时才发出,拖动期间则不生成。 trackPoint_changed 拖动期间发出,给定任意时刻用户在在拖拽平面上的实际位置。 translation_changed 拖动期间发出,给定任意时刻用户在拖拽平面的坐标(数值在minPosition和 maxPosition之间变化)。 第三节 CylinderSersor CylinderSensor圆柱体传感器节点用于感知用户绕中心轴拖拽旋转的动作。当用户用鼠标拖拽被感应的造型时,造型会按用户的动作绕中心轴(一般是造型所在坐标系的Y轴)任意旋转,造型旋转的轨迹类似于圆柱体。 CylinderSensor圆柱体传感器节点语法格式如下; 节点名称 域名称或事件 域值 #域、域值或事件类型 CylinderSensor { enabled TRUE #exposedField SFBool offset 0 #exposedField SFFloat autoOffset TRUE #exposedField SFBool minAngle 0 #exposedField SFFloat maxAngle -1 #exposedField SFFloat diskAngle 0.262 #exposedField SFFloat isActive #eventOut SFBool trackPoint_changed #eventOut SFVec3f rotation_changed #eventOut SFRotation } (1)enabled域的域值用于设定传感器的开与关。该域值为TRUE时,表示传感器处于打开状态,将对用户的操作行为做出反应并生各种事件输出。该域值为FALSE时,表示传感器处于关闭状态,对用户的操作为无法做出反映。该域值的默认值为TRUE。 (2)offset域的域值用于设定造型的初始旋转角度。该域值是一个旋转角度,表示当用户首次在被感应的三维造型上点击鼠标时,造型绕圆柱体中心轴,相对于初始位置旋转的弧度值。该域值的默认值为0,表示没人为设置初始旋转角度。 (3)autoOffset域的域值用于设定是否自动记忆上次旋转的终点角度。该域值的默认值为TRUE,表示自动记忆上次旋转的终点角度,在次旋转时,造型由原始位置开始新的旋转。 (4)minAngle 域的域值用于设定造型绕中心轴旋转的最小角度。该域值是一个弧度值,其功能在于限制造型的旋转范围。 (5)maxAngle域的域值用于设定造型中心轴旋转的最大角度。该域值是一个弧度值,其功能在于限制造型的旋转范围。 注意:若minAngle的域值小于maxAngle的域值,则造型绕中心轴旋转的范围被限制在两个角度之间;若minAngle的域值等于maxAngle的域值,则造型不能旋转;若minAngle的域值大于maxAngle的域值,则造型可以任意旋转而不受限制。 (6)diskAngle域的域值用于设定圆柱体传感器在圆柱和圆盘两种旋转行为之间的切换角度。该域值决定被感应的造型绕中心轴旋转的轨迹像圆柱体还是像圆盘。该域值的默认值为0.262(15°)。 (7)isActive为出事件。当用户在被感应的造型上按下鼠标的按键时,将引发isActive=TRUE的事件;当用户松开鼠标按键时,引发isActive=FALSE的事件。 (8)trackPoint_changed为出事件。当用户在被感应的造型上单击鼠标时,输出该事件。发送的事件值为造型上所击点的坐标。 (9)rotation_changed为出事件。当用户鼠标拖拽造型时,传感器不断输出该事件。发送的事件值为造型旋转的角度。 例: 利用cylindersensor圆柱体传感器节点,创建一个旋转门的场景。旋转门造型的玻璃门扇在鼠标拖拽下可以旋转任意角度,因为设置了初始旋转角度offset-0.781,所以当鼠标首次点击时,玻璃门扇自动顺时针旋转45。 #Lyinux V1.1 gb2312 Background { skyColor 0.6 0 0 } Transform { translation 0 2.1 0 children [ DEF up Shape { appearance Appearance {material Material {diffuseColor 0.3 0.2 0.0 ambientIntensity 0.4 specularColor 0.7 0.7 0.6 shininess 0.2 } } geometry Cylinder { radius 3.8 height 0.2 } } ] } Transform { translation 0 -2.1 0 children [ DEF right Shape { appearance Appearance { material Material { diffuseColor 0.3 0.2 0.0 ambientIntensity 0.4 specularColor 0.7 0.7 0.6 shininess 0.2 } } geometry Cylinder { radius 0.4 height 4 } } ] } Transform { translation -3.4 0 0 children [ USE right ] } DEF door Transform { children [ DEF doorl Shape { appearance Appearance { material Material { diffuseColor 0.05 0.46 0.73 shininess 0.31 specularColor 1 1 1 emissiveColor 0.03 0.04 0.2 transparency 0.45 } } geometry Box { size 6 4 0.1 } } Transform { rotation 0 1 0 1.571 children [ USE doorl ] } Shape { appearance Appearance {material Material {diffuseColor 0.5 0.5 0.7 ambientIntensity 0.4 shininess 0.2 specularColor 0.8 0.8 0.9 } } geometry Cylinder { radius 0.15 height 4 } } ] } DEF clock TimeSensor { cycleInterval 5 } DEF path CylinderSensor { offset -0.781 } ROUTE path.rotation_changed TO door.rotation 第四节 SphereSensor SphereSensor球体传感器节点用于感知用户绕中心点拖拽旋转的动作。 SphereSensor节点语法格式如下: SphereSensor { enabled TRUE # exposedField SFBool offset 0 1 0 0 # exposedField SFRotation autoOffset TRUE # exposedField SFBool isActive # eventOut SFBool trackPoint_changed # eventOut SFVec3f rotation_changed # eventOut SFRotation } 域值说明: (1)enabled域的域值用于设定传感器的开关。 (2)offset域的域值用于设定造型的初始旋转角度。 (3)autoOffset域的域值用于设定是否自动记忆上次旋转的终点角度。默认值为TRUE,表示再次旋转时,造型由上次旋转的终点角度开始新的旋转。 (4)isActive是出事件,当用户在被感应的造型上按下鼠标的按键时,引发isActive=TRUE的事件;当用户松开鼠标按键时,引发isActive=FALSE的事件。 (5)trackPoint_changed是出事件,用户在拖动过程中任意时刻定点设备在假想的球体表面上的实际位置。 (6)rotation_changed是出事件,用户在拖动过程中任意时刻假想球体的当前朝向。 第五节 ProximitySensor ProximitySensor接近传感器节点的语法格式如下: 节点名称 域名称或事件 域值 #域及域值类型 ProximitySensor { center 0 0 0 #exposedField SFVec3f 中心点位置 size 0 0 0 #exposedField SFVec3f 感应区域的大小 enabled TRUE #exposedField SFBool 传感器开关 proxy NULL #SFNode 如果proxy为空(缺省),则检测摄像机离目标的位置。否则检测proxy指定物体(Transform)离目标点的位置 isActive #eventOut SFBool TRUE/FALSE出事件 position_changed #eventOut SFVec3f 浏览者当前位置 orientation_changed #eventOut SFRotation 浏览者当前朝向 enterTime #eventOut SFTime 进入感应区域时间 exitTime #eventOut SFTime 离开感应区域时间 } 常用格式: DEF SENSOR ProximitySensor { center 0 1 0 size 1 2 1 enabled TRUE } 效果:随着视角移动时,当进入感应区域,可发出事件以触发其它事件的发生。 第六节 VisibilitySensor VisibilitySensor传感器在某一物体出现的浏览窗口中时触发,它可以帮助我们实现一些很奇妙的特效。例如,我们设计了一个虚拟的三维迷宫,让浏览者以第一人称视角的方式尝试穿越迷宫,当迷宫的终点标志出现在浏览者眼前时,VisibilitySensor传感器被触发了,一阵令人振奋的音乐响起…… VisibilitySensor节点语法格式如下: 节点名称 域名称或事件 域值 #域及域值类型 VisibilitySensor{ enabled TRUE #exposedField SFBool size 0 0 0 #exposedField SFVec3f 传感器的大小尺寸 center 000 #exposedField SFVec3f 传感器的中心位置 enterTime #eventOut SFTime 记录进入的时间 exitTime #eventOut SFTime 记录消失时间 isActive #eventOut SFBool 物体状态 } 当物体进入浏览者视野时,enterTime字段将记录进入的时间;同样,exitTime字段将记录物体从浏览者视野中消失的时间。isActive字段用于指示物体的状态,如果物体在浏览者视野中,isActive的值为True,否则为FALSE。 第七节 高亮节点 LocateHighlight高亮鼠标所指节点 格式: LocateHighlight { renderCaching AUTO #是否缓冲绘制指令.(AUTO,ON,OFF),一般而言,不变化的时候可以强制ON. boundingBoxCaching AUTO #是否缓冲当的BBox(AUTO,ON,OFF),不形变的一般都可以缓冲裁减信息. renderCulling AUTO #是否缓冲裁剪信息.(AUTO,ON,OFF),不形变的一般都可以缓冲裁减信息. pickCulling AUTO #是否缓冲用于判定命中的裁剪信息.(AUTO,ON,OFF),不形变的一般都可以.PickStyle优先级高于本设定. color 0.3 0.3 0.3 #高亮显示时的颜色 style EMISSIVE # EMISSIVE 漫射光 EMISSIVE_DIFFUSE(漫射,散射) mode AUTO # AUTO 关联鼠标移动命中,ON(永远变色) OFF(永不变色),CUSTOM(用户指定) highlight SFBool # 当前是否变色.也可以赋值(Custom mode下) } 效果:可以设某个物体高亮显示,当鼠标在相应物体之上时,高亮显示 第八节 输入控制节点 为了更好的响应输入设备(如键盘或鼠标)发出的事件,CC6浏览器支持Lyinux扩展的节点System来完成这项工作,本章将主要介绍System的几种用法。 一、 响应键盘鼠标按键消息 System.keyup 当键盘或鼠标按键弹起时发出此事件,数值类型为SFInt32 System.keydown 当键盘或鼠标按键被按下时发出此事件,数值类型为SFInt32 System.isGUIBlock 用来控制是否允许GUI阻挡消息 System.sendRepeat 是否发送重复按键,缺省发送。当本值被设为FALSE时,重复按键将不再发送,意味着按一次按钮只发送一次keydown消息。 System.wheel SFInt32 1为向上滚动一个单位,-1为反方向。 在使用System节点时首先应在文件中定义一个System节点,格式可以参考如下: DEF system System{} 之后,使用ROUTE将system.keyup和system.keydown发出的事件分别与Script中的处理函数相连即可,具体例子如下: #Lyinux V1.1 gb2312 NavigationInfo { steady TRUE } BaseColor {rgb 1 1 1} Font {name "黑体" size 15 } DEF text Text2 { string "操作结果" justification LEFT spacing 1 } DEF system System{} DEF script Script { eventIn SFInt32 onkeyup eventIn SFInt32 onkeydown field SFNode text USE text field SFString info "操作结果 : " url "javascript: function onkeyup(s){ var rs = '按键弹起响应此消息 : '+s; showMsg(rs); } function onkeydown(s){ var rs = '按键按下响应此消息 : '+s; showMsg(rs); } function showMsg(rs){ text.string = new MFString(info+rs); } " } ROUTE system.keyup TO script.onkeyup ROUTE system.keydown TO script.onkeydown 其中,script脚本中,首先声明了两个用来接收事件的函数: eventIn SFInt32 onkeydown eventIn SFInt32 onkeyup 它们将被用来分别处理鼠标按下和松开时发出的两个事件。只有当用ROUTE将system地发出事件与script中的这两个处理函数相连,建立路由之后,鼠标的keydown按下和keyup松开才能真正的传递给script中的onkeydown和onkeyup。需要注意的一点是keyup和keydown是System节点自身的属性,名字是不能更改的。而onkeydown和onkeyup是用户再Script中定义的,名称可以自定义。 点击鼠标按键事件发出的值如下: 鼠标主键(一般情况下为左键): 2 中键: 3(滚轮滚动无效) 鼠标次键(一般情况下为右键): 4 对于空间球类的输入设备。保留5-9为其按键码值。 以下是输入键对应码: 以下是功能键对应码: 二、 响应鼠标在屏幕中移动的轨迹消息 Lyinux对鼠标姿势的支持.如果用户打开了鼠标姿势识别,那么当用户的鼠标姿势符合某个特定姿势时,系统System节点会得到响应,其gesture域会改变. 可以通过脚本来定制自己的姿势.在场景关闭时间自定义姿势自动失效 System.gesture 当鼠标滑动时响应此消息,返回值类型SFInt32 System.gestureTime 完成鼠标运动轨迹所用的时间,返回毫秒值 在Script中的Javascript部分CC6浏览器专门为自定义鼠标滑动轨迹定制的addGesture函数,它的基本格式如下: addGesture(actioncode,'n{minCount-maxCount,minSpeed-maxSpeed}...') 其中,actioncode 为自定义的actioncode编码,类型SFInt32,注意:自定义actioncode应为大于500的整数 n 表示方向,用数字0-7表示,它的方向分布如下图所示: *minCount 该方向上的最小匹配次数-度 *maxCount 该方向上的最大匹配次数 *minSpeed 最小移动速度 *maxSpeed最大移动速 以下是一个捕获鼠标运动轨迹,返回给用户鼠标运动方式的事例: #Lyinux V1.1 gb2312 …….. DEF system System{} DEF script Script { eventIn SFInt32 onGesture field SFNode text USE text field SFNode system USE system field SFString info "操作结果 : " url "javascript: function initialize(){ addGesture(506,'0{2}2{2}4{2}6{2}'); } function onGesture(s){ var rs = s+' = '; switch(s){ case 9: rs += '逆时针圆圈'; break; case 10: rs += '顺时针圆圈'; break; case 506: rs += '顺时针方形'; break; } rs += ',此操作用时'+system.gestureTime/1000; rs += '秒'; showMsg(rs); } function showMsg(rs){… } "} ROUTE system.gesture TO script.onGesture 本例中,在javascript的初始化中首先自定义了一种用户描述的鼠标运动轨迹,并给了它一个编码506。在用户移动鼠标时,System节点会判断这个鼠标移动的方式是否满足系统内部描述的运动轨迹或自定义的运动轨迹,并将与运动轨迹匹配的编码以事件的形式发出。在Script节点中,定义了函数onGesturer,用于对system.gesture传出的事件作进一步处理。OnGesture在接收到system.gesture发出的事件后会得到鼠标运行轨迹匹配的编码,通过编码推断出鼠标运行轨迹。系统目前可识别的鼠标运行轨迹及其对应编码在下表中列出: 编码 鼠标运行轨迹 9 逆时针圆圈 10 顺时针圆圈 下图为为lyinux定义的标准姿势。 第九节 变换操作节点 变换物体,指的是将物体进行平移,缩放或旋转操作,这几种操作可以通过只变换其坐标系来完成。有三种方法: 1) 使用PlaneSensor节点 2) 使用Dragger系列节点 3) 使用Manip系列的节点 PlaneSensor是平面传感器,可以实现物体在Z轴为0的平面内(XY轴组成的平面)进行移动。但这也是它的局限性,它更多用于同其他节点或代码的交互中。关于这个节点在传感器章节有详细介绍。本节主要引入后两种变换物体的方法,介绍Dragger系列以及Manip系列的的节点。 一、 Dragger系列节点 在3D世界中要想实现在空间中拖放物体的效果,用PlaneSensor不能满足这种需求,因为它只是在一个平面内来拖放的, Dragger和Manip系列的节点,弥补了这方面的不足。 Dragger是用来使终端用户可以与3D应用中的物体进行交互(通过缩放,旋转,移动几何形状或其他实体,如摄像机和光源)的一种机制。 为dragger节点配备的Manip节点基本上增加了两个方便的功能: 它使得用dragger进出场景变得非常简单 它能自动的缩放去配合所要操作的几何形状 #Lyinux V1.1 gb2312 Separator { # 维护器,x方向离开控制物体-4个单位。也可以直接和物体在一起。 Separator { Translation { translation -4 0 0 } DEF cbdragger JackDragger { } } # 受控物体子图,可以是任意正规的图,包括seperator,highlight,switch..... TransformSeparator { #将控制物体的位置参数与维护器连接起来。连接的不同方式可以达成同步/反向等等不同效果。 #这是根本原理,与维护器所处位置无关(当然引用的时候必须已经定义)。 Rotation { rotation 0 0 1 0 = USE cbdragger . rotation } Translation { translation 0 0 0 = USE cbdragger . translation } Cone {} } } 值得注意的是,使用Dragger节点时要将物体为位置参数与维护器连接起来才能在拖拽Dragger构成的维护器时带动物体运动 二、 Manip操作器系列 首先,TransformManip变换操作器是一个Transform。因此具有Transform的全部域,含义也一致。 TransformManip节点语法格式如下: TransformManip{ translation 0 0 0 rotation 0 0 0 0 scale 1 1 1 center 0 0 0 manipulator NORMAL #SFEnum dragger FALSE #SFBool isManip #eventOut SFBool } 域值说明: manipulator 指示维护器类型。目前有效: (NORMAL, CENTERBALL, HANDLEBOX, TABBOX, TRACKBALL, TRANSFORMBOX, TRANSFORMER) 缺省为NORMAL. dragger 指示维护器是否有效.(用户可以开始维护). isManip 指示当前是否处于维护状态.(用户正在改变位置). 举例: #Lyinux V1.1 gb2312 Transform { translation -3 -2 0 children[ DEF info Text2 { string ["translation 0 0 0" "rotation 0 0 0 1" "scale 1 1 1" "scaleOrientation 0 0 0 1"] spacing 1.5 justification LEFT } ] } Separator{ DEF sen TouchSensor{} DEF manip TransformManip { translation 0 0 0 manipulator NORMAL dragger FALSE children[ DEF bc BaseColor {rgb 0 1 0} Cube {} ] } } DEF sc Script{ eventIn SFBool touch eventIn SFBool isManip field SoSFNode manip USE manip field SoSFNode bc USE bc field SoSFNode info USE info url "javascript: function touch(u){ var id = manip.manipulator + 1; if(id > 6) id = 0; manip.manipulator = id; } function isManip(u){ if(u){ bc.rgb = new MFColor(new SFColor(0,0,1)); }else{ bc.rgb = new MFColor(new SFColor(0,1,0)); var t = 'translation ' + manip.translation; var r = 'rotation ' + manip.rotation; var s = 'scale ' + manip.scale; var so = 'scaleOrientation ' + manip.scaleOrientation; info.string = new MFString(t,r,s,so); } } " } ROUTE sen.isOver TO manip.dragger ROUTE manip.isManip TO sc.isManip ROUTE sen.isClick TO sc.touch 1. DirectionalLightManip平行光源操作器 默认格式: DirectionalLightManip { on TRUE intensity 1 color 1 1 1 direction 0 0 -1 } 描述:本节点用于手动操作DirectionalLight节点 举例: #Lyinux V1.1 gb2312 DirectionalLightManip { on TRUE intensity 1 color 0.5 0.7 1 direction 0 0 -1 } DEF pointer Cube { height 1 } 1. PointLightManip点光源操作器 语法格式: PointLightManip{ on TRUE # exposed field SFFBool intensity 1 #exposed field SFFloat color 1 1 1 # exposed field SFColor location 0 0 0 # exposed field SFVec3f } 描述:本节点用于手动操作DirectionalLight节点(位置),其域及域值类型同PointLight节点。 举例: #Lyinux V1.1 gb2312 PointLightManip{ on TRUE intensity 1 color 1 1 1 location 0 0 0 } Box{} 2. SpotLightManip 锥光源操作器 语法格式: SpotLightManip{ on TRUE #exposed field SFFBool intensity 1 #exposed field SFFloat color 1 1 1 # exposed field SFColor location 0 0 0 # exposed field SFVect3f direction 0 0 0 # exposed field SFVect3f cutOffAngle 0.785398 # exposed field SFFloat } 描述:本节点用于手动操作DirectionalLight节点(位置,目标点,照射范围),其域及域值类型同SpotLight节点。 举例: #Lyinux V1.1 gb2312 SpotLightManip{ on TRUE intensity 1 color 1 1 1 location 0 0 0 direction 0 0 0 cutOffAngle 0.785398 } Box{} 3. ClipPlaneManip剪切平面操作器 剪切平面是一个无限大的平面,在其背部的形状将被遮挡。默认值时该平面为YZ平面,其法线正方向(即X轴正向)部分被显示出来,法线负方向(即X轴负向)部分将不可见。 本节点用来手动操作剪切平面,包括其位置和旋转。节点语法格式: ClipPlaneManip { } 应用举例: #Lyinux V1.1 gb2312 Separator { ClipPlaneManip { } Sphere { } } Sphere {radius .8} 三、 Controller控制器系列 在还没有MoveController,TurnController,Follow,ObstructMonitor这样的节点之前,我们在实现通过键盘控制物体移动,旋转,跟随的效果 时往往要花费大量的精力,例如物体的匀速移动,我们一般会先定义一个时间传感器TimerSensor,通过它的不断变化,带动脚本中的函数根据时间差和 速度计算出每一时刻的物体位移,然后在为物体重新定位。而引入这些节点之后,代码量将大大下降。 下面我们将结合实例讲解MoveController,TurnController,Follow,ObstructMonitor这四个节点的使用方法 1. MoveController 移动控制器 MoveController用于控制物体移动,其作用对象可以是Camera, Translation, Transform, Rotation等 以下列出了它所拥有的域: collision SFBool 是否检测碰撞 (缺省TRUE) gravitation SFVec3f 重力方向(缺省0,-1,0) upVelocity  SFFloat 向上移动的速度.(缺省0,意味着自动计算) downVelocity SFFloat 向下移动的速度.(缺省0,意味着自动计算) leftVelocity SFFloat 向左移动的速度.(缺省0,意味着自动计算) rightVelocity SFFloat 向右移动的速度.(缺省0,意味着自动计算) forwardVelocity  SFFloat 向前移动的速度.(缺省0,意味着自动计算) backwardVelocity SFFloat 向后移动的速度.(缺省0,意味着自动计算) collisionDistance SFFloat 碰撞距离。离目标方向距离小于这个值视为碰撞。缺省为0,意味着由速度*factor决定 cacheTime SFTime 缓冲时间,缺省是0.3秒 collisionHeight SFloat 跨越高度。(default 0,表示忽略高度值)。指定了可以跨越的高度,大于这个高度无法跨越。 height SFFloat 当前离下方物体高度值.(缺省0,意味着自动计算:注意,本值计算出0以后缓冲无法启动,这将严重影响效率,因此应避免高度为0的情况) collisioned SFNode 碰撞的物体 object SFNode 控制对象. default NULL bind SFBool 是否全局绑定,可以响应全局控制消息.default TRUE. state SFInt32 当前状态.0为停止.1向前,2向后。 4向左,8向右。16向上,32向下。可以使用或来多向同时运动。 jumpHeight SFFloat 跳跃高度。如果不设置,缺省为高度的3倍 jumpTime SFTime 跳跃所需时间,如果不设置,缺省为1s.意味着从开始到最高点需要1秒的时间。 jumpRandom SFFloat 随机附加高度,跳跃的最高点为跳跃高度+随机数(小于jumpRandom),缺省为0.0,意味着禁止随机高度。 jumpMethod SFInt32 跳跃方式,目前仅支持匀速和匀加速运动。(UNIFORM_ACCELERATE[*缺省] : 0 ) UNIFORM_SPEED : 1 jumpState SFInt32 当前跳跃状态,可以用来控制动作。0: 无跳跃。1 : 向上跳跃。2 : 向下跌落。 doJump SFBool 激活一次跳跃,在跳跃时不可跳跃。脚本可以控制跳跃时继续跳跃。(设定jumpState = 1). matchString SFString 名称匹配串,一个正则表达式,在设定collisioned域之前检查这个串,如果发现其祖先匹配这个串,则设置返回祖先节点。 ignores MFString 忽略名称,包含若干正则表达式,凡是匹配的节点(包括其孩子)将被碰撞检测忽略。 在应用中,我们一般将MoveController和某一个已有的物体绑定,这需要用MoveController的object属性来决定是作用在哪个物体上的,例如: DEF green Transform{ translation 3 1 0 children[ box{diffuseColor 0 1 0} ] } DEF mover MoveController { object USE green } 上面的代码将一个叫mover的MoveController作用在了一个叫green的物体之上。 注意,这里的green最好是一个Transform,如果是一个原型: DEF green box{ diffuseColor 0 1 0 translation 3 1 0 } 当在脚本中希望打印出当前物体的位置时 function state_changed(v){ print(green.translation); } 打印出来的值将始终是3 1 0,如果green是按第一种方式定义的一个Transform,这里打印出的值将是随着移动发生变化的值 在MoveController节点中,collision域决定了是否碰撞有效,默认情况下为TRUE。gravitation域规定了重力的方向,默认情况下为(0,-1,0)即沿着Y轴向下的方向,如果希望把重力方向变为沿着X轴正向,可以重新对其复值为(1,0,0)。在默认情况下,物体移动的速度是自动计算的,因此,在前方有物体时会稍快于前往没有物体时,如果像设置固定的移动速度,需要手工设置leftVelocity, rightVelocity,upVelocity,downVelocity,forwardVelocity,backwardVelocity这样和速度有关的域值。collisionDistance用于设置碰撞检测的距离。bind设置为FALSE后,按上下方向键时改变的将是摄像机的位置,而非物体的位置。物体前后移动时,state会一直发出1或2的值,停止移动后会发出0。默认情况下,按空格键被MoveController绑定的物体会发生跳跃,jumpHeight用来设置它的跳跃高度,jumpRandom可以定一个随机的跳跃高度,jumpTime用来设定完成一次跳跃需要花费的时间。jumpMethod与可以在匀速和匀加速的状态间切换。通过jumpState域可以了解到跳跃物体当前的状态。若设置doJump为TRUE,则物体会在还未激活跳跃时就执行一次跳跃 2. TurnController 旋转控制器 通过TurnController节点可以改变物体的旋转角度。它与某个物体的绑定方式和MoveController类似,也是通过将物体赋给object域。通过 leftVelocity,rightVelocity,upVelocity,downVelocity域改变物体的旋转速度。当bind设为 FALSE时,按左右方向键旋转的是视角而不是物体本身。通过state域的不断变化,可以得到当时的物体旋转角度。以下列出了它所拥有的域: leftVelocity SFFloat 弧度/秒 rightVelocity SFFloat upVelocity SFFloat downVelocity SFFloat object SFNode 控制对象 bind SFBool 是否全局绑定,可以响应全局控制消息. state SFInt32 当前状态.0为停止.1为左转/2为右转;4上转/8下转;16顺时针/32逆时针 3. Follow 跟随控制器 Follow节点可以设定object域对应的节点跟踪target域设定的节点,使用velocity域可以制造出例如镜头缓慢跟随的效果,distance域设定了跟随与被跟随物体间的距离,如果距离不等于物体初始时的位置距离,object物体会自动先移到distance说设定的位置上。可以通过设定 lookAtTarget让object物体始终朝向target所对应的物体 以下列出了它所拥有的域: enabled SFBool 开关设定,默认为开 object SFNode 控制物体。(跟随者,例如摄像机) target SFNode 被跟随对象。 velocity SFFloat 跟随速度。(default 0.0f,表示立即跟随,瞬间同步) distance SFFloat 被跟随者"身后"的距离,object将跟踪被跟随者"身后"disntance距离的点(小于0,则是身前distance距离的点);当距离为0时, 旋转不会影响跟随者的位置,此时,position保存了相对于target的偏移。因此我们规定,0距离时object不跟随target的方向--除 非lookAtTarget为TRUE,否则0距离不改变object的方向。当距离不为0时,position中的y分量保存了object在"身后 "distance点上的偏移(本偏移沿着Y轴上下偏移),其它两个分量被忽略。( default 0.0f) lookAtTarget SFBool 是否始终盯着目标。(default is FALSE)。(如果设为TRUE,则object的方向始终朝向target,否则由distance决定策略: distance为0,则方向保持不变,distance> 0,则目标方向与target保持一致). position SFVec3f 相对位置。(在distance不等于0时,本值只有y有效,保存相对高度)。本值自动刷新,或者手工调用saveRelation刷新。本值为object相对于target的位置。 autoRelation SFBool 是否自动更新相对关系(default is TRUE)。(在object发生变动的时候自动更新相对位置position的值,当此设为FALSE时,不影响saveRelation, saveRelation依然可以强制更新相对位置以反映调用时的相对位置关系。) saveRelation SFBool 保存当前相对关系,根据目前object与target的相对位置关系(以及distance的值)计算position。 4. ObstructMonitor ObstructMonitor 用于监测任意两个对象(Transform/Camera..)之间是否有阻挡物体。定义了如下域: object SFNode 监测对象。 target SFNode 监测对象的目标对象。 obstructObjects MFNode 保存当前阻挡对象。 removed MFNode 上次阻挡两个物体,但是不再阻挡的对象 added MFNode 上次不阻挡,但是开始阻挡的对象 period SFTime 监测间隔(缺省0.5秒) 第十章 脚本 第一节 Script 所谓脚本(Script)节点指包含语言程序设计的节点,而且这个程序设计应该能被浏览器解释并运行。在CC6系统中引入程序设计,将会充分发挥编程灵活、控制手段多样、实现范围更广的特点,设计出更加生动、复杂的动画与交互。 Script脚本节点的语法格式如下: DEF <节点名> Script{ runtimeSize SFInt32 内存值(缺省是4M,请至少定义1M(1024 * 1024),没有上限,除非脚本特别多,否则本域无需理会). mustEvaluate SFBool(Default FALSE). 事件变化立即触发脚本.(改为TRUE,可以延迟触发脚本执行). directOutput SFBool(Default FALSE). 保持与VRML一致,因为我们取消了出入事件的概念,本域无效. 域、入事件、出事件定义 url ”<脚本语言声明>: 脚本语言程序 ” } Script支持两个特殊类型SFPath/MFPath,使用上与SFString/MFString一致,但是SFPath/MFPath类型的域会更新相关的路径值,这对于原型中的script对象而言是很有意义的(可以确保调用者使用自己的相对路径而不是原型的相对路径)。 在实际应用中,一般都要给Script节点命名。 Script节点主要包含两个部分,前面是域、入事件、出事件的定义,主要是为脚本程序的运行做准备工作,建立脚本程序和场景之间的联系。域、入事件、出事件定义的格式一般是: field <域类型> <域名> eventIn <入事件类型> <入事件名> eventOut <出事件类型> <出事件名> 这里域名,入事件名和出事件名可以自定义。 以关键字url开头,双引号内的是用某种脚本语言编写的脚本程序,主要支持的语言是javascript。 下面我们对javascript脚本语言进行一些基础的了解。 第二节 Javascript Javascript 是由Netscape开发的对象脚本语言,最早被广泛应用于网页上。JavaScript并不是Java的解释,而是一种动态的支持基于对象和事件驱动的具有安全性能的的脚本语言。基本的语法类似于java和c++,像条件语句,循环语句,捕获异常语句都和这些语言的用法一致,减少了学习新概念新语言的必要。 一、 变量的声明和使用 与Java和C++不同,在Javascript中声明变量时不需要指定变量的数据类型。声明变量格式如下: var a=2, b; 其中var是保留字,它表示此句未声明变量。本例表示声明了变量a和b,其中a被赋了初始值2。 命名规则: 1. 第一个字母必须是英文字母或者下划线_(但不能是数字和其他字符) 2. 其后的字符可以是英文字母、数字或下划线 3. 变量名不能与Javascript的保留字相同 4.Javascript对大小写敏感,因此要注意myName与MyName是不同的 二、 常用运算符和类 算术运算符 运算符 运算符说明 示例 + 加法 x+y - 减法 x-y * 乘法 x*y / 除法 x/y % 两者相除求余数 x%y ++ 递增 x++ -- 递减 y-- 逻辑运算符 运算符 运算符说明 示例 == 等于 x==y = 全等于(值相等,数据类型也相等) x===y > 大于 x>y >= 大于等于 x>=y < 小于 x 1 || 或 x==8 || y==8 ! 非 !(x==y) 赋值运算符 运算符 运算符说明 示例 = 赋值 x=5 数组对象 成员方法: join() 将数组的所有元素放进一个字符串中,这些元素被特殊的分隔符分隔 reverse() 反转数组中的元素顺序 sort() 分类数组中的元素 push() 在数组最后添加一个或多个元素,并返回新的长度 pop() 移走并返回数组中的最后一个元素 shift() 移走并返回数组中的第一个元素 unshift() 在数组开头添加一个或多个元素并返回新的长度 splice() 移走并添加新的元素到数组中 concat() 连接两个或多个数组,并作为结果返回 slice() 从一个存在的数组中返回被选中的元素 indexOf(var v) 返回传递参数v在数组中的索引,数组中没有时为-1 lastIndexOf(var v) 返回传递参数v在数组中最后一次出现的索引,数组中没有时为-1 forEach() map() filter() some() every() 日期时间对象 Date time = Date.now() ; 当前日期距1970年1月1日零点的秒数 Date() 按当前时间创建日期对象 Date(time) 按给出时间创建日期对象,time是自标准时间基准(1970/1/1/0:0:0)以来的秒数。 getTime() 期望日期距1970年1月1日零点的秒数 getTimezoneOffset() 本地时间与格林威治时间的分差 getYear() 日期对象返回年份 getFullYear() 日期对象返回4位年份 getUTCFullYear() 根据UTC从日期对象返回4位年份 getMonth() 日期对象返回月份 getUTCMonth() 根据UTC从日期对象返回月份 getDate() 日期对象返回月中的某天 getUTCDate() 根据UTC从日期对象返回月中的某天 getDay() 日期对象返回星期几 getUTCDay() 根据UTC从日期对象返回星期几 getHours() 日期对象返回小时 getUTCHours() 根据UTC从日期对象返回小时 getMinutes() 日期对象返回分钟 getUTCMinutes() 根据UTC从日期对象返回分钟 getSeconds() 日期对象返回秒数 getUTCSeconds() 根据UTC从日期对象返回秒数 getMilliseconds() 日期对象返回毫秒数 getUTCMilliseconds() 根据UTC从日期对象返回毫秒数 setTime() 设定日期对象距1970年1月1日零点的秒数 setYear() 设定日期对象年份 setFullYear() 设定日期对象4位年份 setUTCFullYear() 根据UTC设定日期对象4位年份 setMonth() 设定日期对象月份 setUTCMonth() 根据UTC设定日期对象月份 setDate() 设定日期对象月中的某天 setUTCDate() 根据UTC设定日期对象月中的某天 setHours() 设定日期对象小时 setUTCHours() 根据UTC设定日期对象小时 setMinutes() 设定日期对象分钟 setUTCMinutes() 根据UTC设定日期对象分钟 setSeconds() 设定日期对象秒数 setUTCSeconds() 根据UTC设定日期对象秒数 setMilliseconds() 设定日期对象毫秒数 setUTCMilliseconds() 根据UTC设定日期对象毫秒数 toUTCString() 根据UTC把日期对象转换为字符串 toLocaleString() 根据本地时间格式把日期对象转换为字符串 toLocaleDateString() 根据本地时间格式把日期对象的日期部分转换为字符串 toLocaleTimeString() 根据本地时间格式把日期对象的时间部分转换为字符串 toLocaleFormat() 根据本地时间格式对日期对象进行转化 toDateString() 把日期对象的日期部分转换为字符串 toTimeString() 把日期对象的时间部分转换为字符串 toSource() 返回创建这个日期对象的原始代码 toString() 把日期对象转化为字符串 valueOf() 返回日期对象的原始值 数学运算对象Math 成员常量:(例如:if( 2 * Math.PI > xxx)) E 自然对数的底数 LOG2E 以2为底的e的对数 LOG10E 以10为底的e的对数 LN2 2的自然对数 LN10 10的自然对数 PI 圆周率 SQRT2 2的平方根 SQRT1_2 2的平方根除1 静态方法: abs(x) 返回x的绝对值 acos(x) 返回x的反余弦值 asin(x) 返回x的反正弦值 atan(x) 用介于 -PI/2 与 PI/2 弧度之间的数值来返回 x 的反正切值 atan2(x) 返回从 x 轴到点 (x,y) 的角度(介于 -PI/2 与 PI/2 弧度之间) ceil(x) 对x进行向上的舍入 cos(x) 返回x的余弦值 exp(x) e的x次幂 floor(x) 对x进行向下舍入 log() 返回x的自然对数(底为e) max(x,y) 返回 x 和 y 中的最大值 min(x,y) 返回 x 和 y 中的最小值 pow(x,y) 返回x的y次幂 random() 反悔0到1之间的随机数 round(x) 返回x经过4舍5入后最接近的值 sin() 返回x的正弦值 sqrt() 返回x的平方根 tan() 返回x的正切值 toString(x) 与x等价的字符串 正则表达式对象RegExp class RegExp 静态属性: input 正则表达式没有匹配的字符串 multilane lastMatch 最后匹配的字符 lastParen 最后的括起的子字符串匹配 leftContext 在最近一次匹配之前的子字符串 rightContext 在最近一次匹配之后的子字符串 $1-$9 括起的子字符串匹配 成员属性: source(readonly) 文本模板 global(readonly) 是否在字符串中所有可能的匹配上测试正则表达式(全局匹配),或者只是第一个 ignoreCase(readonly) 当试图匹配一个字符串是是否忽略大小写 lastIndex 下一个匹配的开始索引 multiline(readonly) 是否跨多行寻找 成员方法: toSource() toString() compile() 解析一个正则表达式对象 exec() 在它的字符串参数中执行一个匹配的搜索 test() 在它的字符串参数中为一个匹配的测试 三、 程序控制流 Javascript的程序控制流类似于Java或C++的语法,这里只作简单介绍,若想深入了解请参考Javascript的相关文档 1. if …else 一般结构: if(表达式){ 语句体1 }else{ 语句体2 } 其中表达式值为true时执行语句体1,否则执行语句体2,else部分若无需要,可以省略不写 *switch * 一般结构: switch (表达式) { case 值1 : 语句体1 break case label2 : 语句体2 break ... default : 默认语句体 } 其中表达式一般返回一个整数,如果表达式的值与值1相等,则执行语句体1,直到碰到break语句,跳出switch语句。若表达式的值与值2相等,则执行语句体2,直到碰到break语句。若表达式的值和case后列出的所有值都不相同,则执行default中的默认语句体。 for循环 一般结构: for(初始值赋值表达式;循环执行条件;改变数值表达式){ 语句体 } 当循环执行条件满足时,始终执行语句体部分,每次执行完语句体后会执行改变数值表达式,之后再次检查是否满足执行条件,若是,继续执行语句体,如否,跳出for循环执行下一条命令 do while循环 一般结构: do{ 语句体 }while(逻辑表达式) 其效果为执行语句体中的命令直到不满足逻辑表达式。 while循环 while(逻辑表达式){ 语句体 } 其效果为当满足逻辑表达式时执行语句体 break和continue语句 使用break语句使得循环从For或while中跳出,continue使得跳过循环内剩余的语句而进入下一次循环。 四、 函数 函数定义格式: function 函数名称(参数表) { 函数执行部分 } 说明:  当调用函数时,所用变量或字面量均可作为变元传递。  函数由关键字function定义。  函数名:不能与保留字重复。  参数表,是传递给函数使用或操作的值,其值可以是常量 ,变量或其它表达式。  通过指定函数名(实参)来调用一个函数。  函数名对大小写是敏感的 第三节 脚本的运用 本节我们用一个例子来研究Script节点的运用。 动画控制代码 本段代码实现的功能是鼠标动作对于往复运动的实时控制,当鼠标放在球体上时,球体向右移动直至横轴右端;当鼠标离开球体时,球体向左移动直至横轴左端。代码如下: #Lyinux V1.1 gb2312 Box {size .05 10 .1} Box {size 10 .05 .1} DEF startgame Transform { children [ Shape { geometry Sphere {} appearance Appearance { material Material { diffuseColor .12 .6 0 specularColor .5 .5 .5 } } } DEF touch TouchSensor{} ] } DEF time1 DrawSensor {cycleInterval 2} DEF move1 PositionInterpolator { key [0 1] keyValue [-5 0 0, 5 0 0] } DEF time2 DrawSensor {cycleInterval 2} DEF move2 PositionInterpolator { key [0 1] keyValue [5 0 0, -5 0 0] } DEF thescript Script { eventIn SFBool over field SFNode time1 USE time1 field SFNode time2 USE time2 field SFNode move1 USE move1 field SFNode move2 USE move2 field SFNode sgame USE startgame url "javascript: var cycle = time1.cycleInterval; function over(v) { if(v){ time1.enabled = true; var os = time2.startTime; if(Date.now() - os > cycle) { time1.startTime = Date.now(); } else{ time1.startTime = 2 * Date.now() - cycle- os; } time2.enabled = false; } else{ var os = time1.startTime; time2.enabled = true; if(Date.now() - os > cycle){ time2.startTime = Date.now(); } else{ time2.startTime = 2 * Date.now() - cycle- os; } time1.enabled = false; } } " } ROUTE touch.isOver TO thescript.over ROUTE time1.fraction_changed TO move1.set_fraction ROUTE move1.value_changed TO startgame.translation ROUTE time2.fraction_changed TO move2.set_fraction ROUTE move2.value_changed TO startgame.translation 代码说明: 在本例中,设置两个细长的box模拟坐标轴,可以更清楚地观察球体的运动轨迹。球体的运动(PositionInterpolator)有两个:向右平移move1和向左平移move2,这两个运动是等时互逆运动。分别由两个时间传感器(DrawSensor)绑定。当鼠标在球体上时,time1.enabled为true,并将time1.startTime设定为当前时间,球体开始从最左端向右平移;鼠标离开球体时,thescript代码判断球体运动的时间是否达到一个周期,即球体是否运动到最右端,是则将time2.startTime设定为当前时间,球体从最右端向左平移,否则time2.startTime将被设定为当前运动的逆向运动的起始时间,球体即从当前位置开始向左平移。这是因为: 目前运动经过时间 = 当前时间 - 当前运动的起始时间, 目前运动剩余时间 = 逆向运动经过时间 = 当前时间 - 逆向运动的起始时间, 运动周期 = 目前运动经过时间 + 目前运动剩余时间。 逆向运动的起始时间 = 2 * 当前时间 - 运动周期 - 当前运动的起始时间。 第四节 扩展函数——自定义光标 Lyinux语法中自定义光标的体系必须依赖Javascript才可以完成,且在文件中必须由TouchSensor节点的使用。 为了实现光标的创建与加载,扩充了以下函数: //ID必须大于500.小于500为内建光标. BOOLEAN loadCursor(Integer ID,String fileURL). //ID必须大于500.小于500为内建光标. BOOLEAN createCursor(Interger ID,Interger xHotSpot,Interger yHotSpot,Interger width, Interger Height,MFInt32 andBits,MFInt32 xorBits) //设置不匹配任何名字时的光标. BOOLEAN setCursor(Interger ID) //当光标当前物体的名字匹配正则表达式pattern时的光标. BOOLEAN matchCursor(String pattern,Interger ID) //检查ID下是否有光标. BOOLEAN hasCursor(Interger ID) removeMatch(cursorID,matchString). 实际应用中,我们时常希望当鼠标在某一个物体之上光标的表示方式会随之改变,如当鼠标放在一个有超链功能的物体上时我们希望光标会变为手型等等,以下是自定义光标的一个简单的例子: #Lyinux V1.1 gb2312 TouchSensor {} DEF box Transform { translation 0 0 0 children [ Shape { geometry Box {} } ] } DEF theScript Script{ url "javascript: function initialize() { //loadCursor(502,'busy.ani',TRUE); matchCursor('.*box.*',3); // setCursor(2) // alert(hashCursor(555)); } " } 这里首先加入了一个TouchSensor,只有加上它,之后的改变光标才能有效。接着我们加入了一个名为box的方块,我们希望鼠标放在上面时会变为手型,这就需要在Script节点中加入相关操作了。 Script脚本中定义了initialize方法,它在程序初始化时开始执行,通过CC6浏览器所支持的扩展函数matchCursor来设置光标,格式为: matchCursor(‘正则表达式’,光标类型号); 它的作用是检查凡是满足正则表达式的节点名称所对应的节点,在光标放在它的上面时显示光标类型号所对应的光标。 如果希望添加自定义的光标,可以先通过loadCursor函数加载一个自定义光标到一个光标类型号上,之后就可以使用这个光标类型号了。在定义光标类型号时应确保自定义的类型号使用得数值在500之后,之前的数值用于存储描绘系统光标的类型号。loadCursor的格式为:loadCursor(光标类型号,’光标文件路径’). 它的作用是将光标文件路径指向的光标符号于一个光标类型号连接,以后想用到这个光标符号可以直接通过使用这个光标类型号。 另一方面,普通区域的默认光标也可以来自定制。通过使用setCursor函数来实现改变默认光标的效果,setCursor的格式如下: setCursor(光标类型号); 它的作用是设定默认光标。 如果想查看某个光标类型号是否有对应的光标可以使用hashCursor函数,它的格式是: hashCursor(光标类型号); 它将返回一个布尔类型的变量,为true时表示有匹配的光标,为false时表示没有匹配的光标 以下列出系统定义的光标号所对应的光标 光标类型号 光标图标 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 如果希望删除光标的匹配,可以使用removeMatch函数,它的格式如下: removeMatch(cursorID,matchString). 当cursorID传-1表示在匹配表中删除所有匹配 matchString的。仅传一个cursorID表示在匹配表中删除所有匹配cursorID的,两个都传表示在匹配表中删除 matchString,cursorID的项,仅传一个-1,表示匹配表清空。 第五节 常用全局函数介绍 上节中提到的光标相关的函数如:loadCursor,createCursor都属于全局函数,它在脚本中可以直接调用,本节将介绍几种在实际应用中常用的其他类型的全局函数。 一、 print与alert函数 在脚本中可以通过print和alert两个函数来打印应用或调试数据,print的打印结果将出现在应用程序的log文件中,它是在后台默默执行,并不会打断程序的正常运行,而alert的执行,将会弹出信息对话框,并打断程序的正常执行。它们的用法如下: print(‘Hello World!’); alert(‘Hello World!’); 二、 fullScreen函数 fullScreen函数允许用户对场景进行全屏显示与浏览器显示的切换,它可以有一个参数,如果参数为true,则全屏显示,如果为false则浏览器显示,如果没有参数,系统将返回当前的显示状态,true为全屏显示,false为浏览器显示。 如果需要在一进入场景就显示全屏,可以将设定全屏的代码放置在initialize初始函数中,代码如下: function initialize(){ fullScreen(true); } 三、 thisNode函数 应用中我们经常会遇到这样的情况:一个原型的多个实例,以不同的表现形式分布在场景各个位置,通过对它们的交互动作,如点击,给出用户信息告知是谁被点击了。显然我们不可能给每一个原型实例上添加传感器,再为每一个加上路由和对应的事件脚本,这样只会大大增加工作量和代码量。把以上这些加入到原型文件是最为合理的解决办法,因为每个原型实例都有着相同的感应事件,只是通过外部接口,使自身有着各自不同的属性设置。 这时,就引来了新的问题,交互动作发生时,原型中该如何得到当前是哪个原型实例在被使用呢?thisNode函数为我们解决了这一问题,它返回当前Script所处原型创建的实例对象,如果隶属全局,返回false,可以使用if(返回值)来判定是否获取成功。下面我们来举个例子详细说明它的功效。 我们要实现这样一个效果,场景中有两个物体a 和b,它们都是用了原型ball,ball有translation和ballName两个对外参数,来决定两个物体的位置和名称,我们这里分别给出不同的名字A和B。下面我们希望在点击物体a或b时,它们的名字A或B出现在一个GUI窗体上显示。下面来看具体代码: 场景脚本: #Lyinux V1.1 gb2312 EXTERNPROTO ball []["ball.cc6"] DEF a ball{ translation 0 5 0 ballName "A" } DEF b ball{ ballName "B" } DEF grp1 GUIGroup{ imagesets ["datas/imagesets/Simple.imageset" ] lookfeels ["datas/looknfeel/Simple.looknfeel" ] schemes ["datas/schemes/Simple.scheme"] tooltipType "Simple/Tooltip" children[ DEF info GUIWindow{ type "Simple/SimpleText" text "what is touched" position 0.2 0.2 size 0.2 0.2 properties ["BoxBackground" "set:_file image:icon.jpg"] } ] } 原型代码: #Lyinux V1.1 gb2312 PROTO ball[ exposedField SFString ballName "" exposedField SFVec3f translation 0 0 0 ] { Transform{ translation IS translation children[ DEF touch TouchSensor{} Shape{ appearance Appearance { material Material { diffuseColor 0.8 0.8 0.8 transparency 0 } } geometry Sphere { } } ] } DEF theScript Script{ eventIn SFBool isClicked url "javascript: function isClicked(v){ SFNode.get('info').text=thisNode().ballName; } " } ROUTE touch.isClick TO theScript.isClicked } 在原型的脚本中,当原型的实例被点击后触发isClicked,通过SFNode.get方法获得名为info的节点,它可以去到使用这个原型的场景中的名为info的GUI节点,我们希望它的text设为被点击实例的ballName,因此做了如下设置: SFNode.get('info').text=thisNode().ballName; 四、 setTimeout函数 通过setTimeout函数可以设定定时器,让一个函数每间隔一段时间后执行,它的格式如下: setTimeout(functinName,delay[,count]) 第一个参数为字符串类型,是要调用的方法。 第二个参数是间隔时长,值得注意一点的是,这里我们以秒为单位。 第三个参数是执行次数 我们来举一个简单的例子: #Lyinux V1.1 gb2312 Transform{ translation 3 -3 0 children[ DEF touch TouchSensor{} Cube{} ] } DEF theScript Script{ eventIn SFBool isClicked field SFInt32 count 0 url "javascript: function isClicked(v){ setTimeout('loopIt()',5,3); } function loopIt(){ alert(count); count++; } " } ROUTE touch.isClick TO theScript.isClicked 本例中当点击正方体后,每隔5秒执行一次loopIt方法,一共执行3次 五、 获得当前用户信息函数 脚本中可以通过userName函数和publicUUID函数获得当前用户的用户名和PublicUUID,它们没有参数。 实例如下 function test(){ alert('userName:'+userName()+'\n'+'pubicUUID:'+ publicUUID()); } 通过basepath函数可以获得当前打开文件所在文件夹的路径。 version函数可以获知当前浏览器的版本号 buildtime函数可以获知当前浏览器生成日期 Vnumber函数可获知当前浏览器内部版本号 FriendCount函数获得朋友数量 getFriend函数获得具体的某个朋友 removeFriend删除某个朋友 isFriend判断是否是朋友 第六节 SFNode类的使用 类SFNode在应用中十分重要,通过它可以对场景动态添加删除物体,还可以通过它快捷的定位想要获得的节点对象。本节将详细介绍它的成员函数静态函数: 成员函数: getName() :获得该节点实例的名称,例如下面这段代码: #Lyinux V1.1 gb2312 Transform{ translation 3 -3 0 children[ DEF touch TouchSensor{} DEF box Cube{} ] } DEF theScript Script{ eventIn SFBool isClicked field SFNode b USE box url "javascript: function isClicked(v){ alert('getName : '+b.getName()); } " } ROUTE touch.isClick TO theScript.isClicked 当点击方体,将弹出对话框显示b对象实际的名字:box setName() :改变该节点实例的名称。例如下面的案例: #Lyinux V1.1 gb2312 Transform{ translation 3 -3 0 children[ DEF touch TouchSensor{} DEF box Cube{} ] } DEF theScript Script{ eventIn SFBool isClicked field SFNode b USE box url "javascript: function isClicked(v){ alert('getName : '+b.getName()); b.setName('boxChanged'); alert('getName : '+b.getName()); } " } ROUTE touch.isClick TO theScript.isClicked getChildNum() 返回当前节点对象包含的子节点数,例如下面的例子: #Lyinux V1.1 gb2312 DEF tran Transform{ translation 3 -3 0 children[ DEF touch TouchSensor{} DEF box Cube{} ] } DEF theScript Script{ eventIn SFBool isClicked field SFNode tran USE tran url "javascript: function isClicked(v){ alert('child number : '+tran.getChildNum()); } " } ROUTE touch.isClick TO theScript.isClicked 通过点击,弹出提示框,告知名为tran的节点对象共有2个子节点 addChild() 用于添加子节点,例如下面的例子: #Lyinux V1.1 gb2312 DEF tran Transform{ translation 0 0 0 children[ DEF touch TouchSensor{} DEF box Cube{} ] } DEF container Transform{ translation 0 1 0 children[ ] } DEF theScript Script{ eventIn SFBool isClicked field SFNode container USE container url "javascript: function isClicked(v){ var newone=new SFNode('Cube{}'); container.addChild(newone); } " } ROUTE touch.isClick TO theScript.isClicked 本例中有一个名为container的没有子节点的节点,通过点击事件的触发,先用new SFNode构造函数构造一个新的节点对象,再通过addChild方法将这个对象添加到container节点中。 getChild( int index) 用于获得节点中的某个子节点,可以跟一个参数,给出子节点的索引,它返回的是一个SFNode的值。例如上例中,通过tran.getChild(1)可以得到box的节点对象。 findChild() 用于查找某一个子节点,可跟一个参数,给出子节点的对象,它返回的是该子节点的索引,如果没有这个子节点,返回-1,例如上例中,若使用tran.findChild(touch),可得到touch的索引值为0 removeChild() 用于删除某一个子节点,可以跟一个参数,给出所要删除子节点的索引,或者直接给出子节点的对象都可。例如上面的例子中,若想删除box,使用以下两句话都可达到相同效果: tran.removeChild(box); tran.removeChild(1); replaceChild() 用于替换一个子节点的对象为另一个对象。要跟两个参数,第一个是要被替换的对象名或索引,第二个要替代的对象。例如下面这段代码,点击方体后tran中的box将被替换为一个新创建的圆锥体。 #Lyinux V1.1 gb2312 DEF tran Transform{ translation 0 0 0 children[ DEF touch TouchSensor{} DEF box Cube{} ] } DEF container Transform{ translation 0 1 0 children[ ] } DEF theScript Script{ eventIn SFBool isClicked field SFNode tran USE tran field SFNode box USE box url "javascript: function isClicked(v){ var newone=new SFNode('Shape {geometry Cone {}}'); tran.replaceChild(box,newone); } " } ROUTE touch.isClick TO theScript.isClicked equal() 用于比较两个节点对象是否相等。要跟一个参数,要进行比较的节点对象。相等时返回true,不等时返回false 例如 box.equal(box);//true box.equal(touch);//false fieldCount() 返回节点所拥有的域数量。如果错误,返回-1。例如一个Transform类型的节点返回的值是14 fieldName(int index) 返回指定索引的域名称。如果错误,返回空字符串。 bool hasField(name) 判断是否有域名为name的域 var getField(name) 获得域名为name的域的值 setField(name,var) 设置域名为name的域的值 bool getBoundingBox([out,SFVec3f]center,[out,SFVec3f,optional]size); 获取本节点(含所有子节点)的约束盒。需要传入两个SFVec3f类型的变量,第一个参数返回中心点坐标,第二个返回三个方向的尺寸(可选参数)。需要注意的是,返回的坐标点为当前Node的对象空间坐标(如果之上没有Transform之类的坐标变换节点,对象空间等同于世界坐标).如果希望获取世界坐标,请配合getMatrix使用。 matrix getMatrix(void); 用于获取当前节点的对象坐标系与世界坐标系之间的坐标变换矩阵。无参数,返回一个VrmlMatrix类型的对象。 bool pointAt([in,SFVec3f]target,[in,SFVec3f,optional]upVector];(only for camera) 用于调整摄像机的方向,使得摄像机指向目标点,但是方向与upDir保持一致. (如果可能的话). call() 仅仅对HtmlTexture和WWWAnchor节点有效,用于调用HTML中的脚本 静态方法: create()  ?? get() 用于通过节点的名称来获得节点的对象,需要一个字符串参数,其为需要得到的对象名称。如果在原型中使用这个方法,同样可以获得引用这个原型的主场景中的节点对象。例如上面例子中的box就可以通过如下方法获得: SFNode.get('box'); createRoute() 用于动态创建路由,共4个参数,前两个是发出事件的对象和发出事件名称,后两个是接收事件对象和接收事件名称,例如下面的例子: #Lyinux V1.1 gb2312 DEF tran Transform{ translation 0 0 0 children[ DEF touch TouchSensor{} DEF box Cube{} ] } DEF timer TimeSensor { loop TRUE } DEF theScript Script{ eventIn SFBool isClicked field SFNode tran USE tran field SFNode timer USE timer field SFNode theScript USE theScript eventIn SFFloat move url "javascript: function isClicked(v){ SFNode.createRoute(timer,'fraction_changed',theScript,'move'); } function move(v){ tran.translation[1]=v; } " } ROUTE touch.isClick TO theScript.isClicked 在开始时,对象timer和对象theScript并没有建立任何路由关系,当点击方块之后,通过SFNode.createRoute方法动态建立了它们之间的路由,让timer发出的事件fraction_changed路由指向theScript的move方法,通过move方法,改变方体的坐标,从而实现运动效果 removeRoute() 用于动态删除两对象之间的路由。共4个参数,前两个是发出事件的对象和发出事件名称,后两个是接收事件对象和接收事件名称,例如下面的例子: #Lyinux V1.1 gb2312 DEF tran Transform{ translation 0 0 0 children[ DEF touch TouchSensor{} DEF box Cube{} ] } DEF timer TimeSensor { loop TRUE } DEF theScript Script{ eventIn SFBool isClicked field SFNode tran USE tran field SFNode timer USE timer field SFNode theScript USE theScript eventIn SFFloat move url "javascript: function isClicked(v){ SFNode.removeRoute(timer,'fraction_changed',theScript,'move'); } function move(v){ tran.translation[1]=v; } " } ROUTE touch.isClick TO theScript.isClicked ROUTE timer.fraction_changed TO theScript.move 第七节 VrmlMatrix类的使用 class VrmlMatrix VrmlMatrix 对象提供了一些有用的方法去执行操作4*4的矩阵。每个矩阵的元素可以通过C风格的数组访问。(例如vMatrix[0][2]是第0行,第2列的元素),如果用一个index来取值,结果将是未定义的(undefined)。位移元素处于第四行。例如vMatrix[3][0]是X轴的偏移 构造: vMatrix=new VrmlMatrix (numeric v11,numeric v12,numeric v13,numeric v14, numeric v21,numeric v22,numeric v23,numeric v24, numeric v31,numeric v32,numeric v33,numeric v34, numeric v41,numeric v42,numeric v43,numeric v44,); 一个新的矩阵用v11到v44初始化,被创建和返回。位移为v41,v42,v43 vMatrix=new VrmlMatrix () 一个被初始化为单位矩阵的矩阵被创建和返回。 成员方法: void setTransform(SFVec3f translation, SFRotation rotation, SFVec3f scale, SFRotation scaleOrientation, SFVec3f center) 通过传递的参数设定VrmlMatrix。 任何最右边的参数可以被省略。本方法可以有0到5和参数。例如定义了0个参数的结果将使该对象为单位矩阵,定义1个参数将有位移,定义2个矩阵有位移和旋转。任意没有指定给的参数默认值与Tranform节点的默认值相同。 void getTransform(SFVec3f translation, SFRotation rotation, SFVec3f scale) 分解一个VrmlMatrix并返回传递位移,旋转和缩放对象。这些传递的对象与setTransform的参数一样。如果任何传递的参数没有被送出,或者如果一个空对象被送给任意值,这个值将不会被返回。任何发出的信息都将被忽略 VrmlMatrix inverse() 返回一个这个对象取反后的VrmlMatrix VrmlMatrix transpose() 返回这个对象的转置矩阵 VrmlMatrix multLeft(VrmlMatrix matrix) 返回该对象左乘传递的参数后得到的VrmlMatrix VrmlMatrix multRight(VrmlMatrix matrix) 返回该对象右乘传递的参数后得到的VrmlMatrix SFVec3f multVecMatrix(SFVec3f v) 返回一个本对象乘以一个行向量得到的SFVec3f SFVec3f multMatrixVec(SFVec3f v) 返回一个本对象乘以一个列向量得到的SFVec3f 第八节 JavaScript的数据类型 本文将介绍Javascript中的数据类型及其成员函数和属性域。 class SFVec2f SFVec2f对象对应着cc6文件中的SFVec2f域,用属性x或y来访问其中的值,或者用C样式的数组格式来访问。(如v[0],v[1]) 构造: v2f=new SFVec2f(numeric x, numeric y); numeric的类型可以是整型或浮点型。对缺省的值默认为0.0 成员方法: SFVec2f add(SFVec2f v) 返回传递参数域值对应的加到对象上的结果 SFVec2f divide(numeric n) 返回对象被传递参数除之后的结果 numeric dot(SFVec2f v)点乘 返回这个向量和传递参数的点乘结果 numeric length() 返回这个向量的长度 SFVec2f multiply(numeric n) 返回这个对象被传递参数乘的结果 SFVec2f normalize() 返回转化为单位长度后的对象。 SFVec2f subtract(SFVec2f v) 返回从对象中域对应的减去传递参数的结果 property: x 或者v2f[0] 表示向量中的第一个值 y 或者v2f[1] 表示向量中的第二个值 class SFVec3f SFVec3f对象对应着cc6文件中的SFVec3与。用属性x,y,z来访问其中的值,或者用C样式的数组格式来访问。(如v[0],v[1],v[2]) 构造: v3f=new SFVec3f(numeric x, numeric y, numeric z); //num的类型可以是整型或浮点型。 成员方法: SFVec3f add(SFVec3f v) 返回传递参数域值对应的加到对象上的结果 SFVec3f divide(numeric n) 返回对象被传递参数除之后的结果 numeric dot(SFVec3f v) 返回这个向量和传递参数的点乘结果 numeric length() 返回这个向量的长度 SFVec3f multiply(numeric n) 返回这个对象被传递参数乘的结果 SFVec3f normalize() 返回转化为单位长度后的对象 SFVec3f negate() 返回各对应域取反之后的对象 SFVec3f cross(SFVec3f v) 返回对象和传递参数的差乘结果 SFVec3f subtract(SFVec3f v) 返回从对象中域对应的减去传递参数的结果 property: x 或者v3f[0] 表示向量中的第一个值 y 或者v3f[1] 表示向量中的第二个值 z 或者v3f[2] 表示向量中的第三个值 class SFVec4f 用来存储需要4个值表示的对象,例如,我们可以讲一个描绘颜色和透明度的对象用这个类来声明。或者我们可以通过存取左上和右下角来确定一个长方形区域。 成员方法: dot() 返回这个向量和传递参数的点乘结果 length() 返回这个向量的长度 normalize() 返回转化为单位长度后的对象 negate() 返回各对应域取反之后的对象 属性: left 表示向量中的第一个值 top 表示向量中的第二个值 right 表示向量中的第三个值 bottom 表示向量中的第四个值 class SFVec3d 成员方法: add() 返回传递参数域值对应的加到对象上的结果 divide() 返回对象被传递参数除之后的结果 dot() 点乘 返回这个向量和传递参数的点乘结果 length() 返回这个向量的长度 multiply() 返回这个对象被传递参数乘的结果 normalize() 返回转化为单位长度后的对象 negate() 返回各对应域取反之后的对象 subtract() 返回从对象中域对应的减去传递参数的结果 property: x 表示向量中的第一个值 y 表示向量中的第二个值 z 表示向量中的第三个值 class SFRotation SFRotation对象对应着cc6中的SFRotation域。它有4个数字属性:x,y,z,angle。这些可以用C风格标识,例如v[0],v[1],v[2],v[3] 构造: vRot=new SFRotation(SFVec3f axis, numeric angle); 或 vRot=new SFRotation(SFVec3f from, SFVec3f to); 成员方法: SFVec3f getAxis() 返回旋转轴的向量 SFRotation inverse() 反转这个对象的旋转 SFRotation multiply(SFRotation rot) 返回这个对象被传递参数乘的结果 SFVec3f multVec(SFVec3f v) 返回传递参数被这个对象的旋转对应的矩阵乘的值 void setAxis(SFVec3f v) 设置旋转轴的向量 SFRotation slerp(SFRotation dest, numeric t) 当0 <= t <= 1 时返回值是对象的 rotation 和 destRotation 之间的球形线性插值的 SFRotation 。 当t = 0 ,值是这个对象的 rotation 。 当t = 1 ,值是 destRotation 。 property: x 返回轴的第一个值 y 返回轴的第二个值 z 返回轴的第三个值 angle 旋转角度对应的 SFFloat 值 我们用摄像机的例子来讲这些方法的运用: 要做的是是摄像机跟随在目标物体后面(假设目标物体在水平面上运动),主要解决目标物体移动旋转时计算摄像机的位置; 目标物体位置与朝向:dt = dest.translation dr = dest.rotation 当前摄像机的位置:cp = camera.position 求出二者的差向量:st = cp.subtract(dt) 目标物体旋转转化为单位向量:nm=dr.multVec(new SFVec3f(0,0,-1)) 取负向量:nm = nm.negate() 求摄像机水平相对位置:stH = new SFVec3f(st[0],0,st[2]) 求出从stH到nm之间的旋转:rotH = new SFRotation(stH,nm) 将摄像机转到目标物体正后面:stNew = rotH.multVec(st) 求出摄像机的绝对位置:cpNew = stNew.add(dt) 将摄像机朝向目标物体:co = new SFRotation(new SFVec3f(0,0,-1), stNew) (本例不保证机头正置) 样例代码: #Lyinux V1.1 gb2312 DEF camera PerspectiveCamera { position 0 3 5 } DEF obj Transform {children [ Material{ diffuseColor .8 0 0 specularColor .5 .5 .5 emissiveColor .15 0 0 ambientIntensity 0 } Box{} ] } Box{size 20 .1 20} DEF mc MoveController { object USE obj bind TRUE } DEF tc TurnController { object USE obj bind TRUE } DEF scr Script { field SFNode obj USE obj field SFNode mc USE mc field SFNode tc USE tc field SFNode camera USE camera field SFVec3f st 0 0 0 eventIn SFVec3f trchanged eventIn SFRotation rochanged eventIn SFInt32 state url "javascript: function trchanged(){ rochanged(); } function rochanged(){ nm=obj.rotation.multVec(new SFVec3f(0,0,-1)); nm = nm.negate(); stH = new SFVec3f(st[0],0,st[2]); rotH = new SFRotation(stH,nm); stNew = rotH.multVec(st); cpNew = stNew.add(obj.translation); co = new SFRotation(new SFVec3f(0,0,-1), stNew.negate()); camera.position = cpNew; camera.orientation = co; } function state(){ dt = obj.translation; dr = obj.rotation; cp = camera.position; st = cp.subtract(dt); } " } ROUTE obj.translation TO scr.trchanged ROUTE obj.rotation TO scr.rochanged ROUTE mc.state TO scr.state ROUTE tc.state TO scr.state class SFColor SFColor对象时对应着cc6文件中的SFColor域。用red,green,blue三个属性来决定一个SFColor对象,还可以通过数组形式对这些属性进行访问。index为0对应red, 为1时对应green, 为2时对应blue。 构造 sfcolorObj=new SFColor(float r, float g, float b); 缺省的参数默认值为0 成员方法: void setHSV(float h, float s, float v) 通过色调,饱和度和值设定颜色 numeric[3] getHSV() 返回一个有3个元素的数组,index为0时对应hue, 为1是对应saturation,为2是对应值 基本数据类型 SFInt32 作为整型(Number class) SFFloat 作为浮点型(Number class) SFString 作为字符串型 SFTime 是一个double类型的数值. 除了以上的数据类型外,还对应着一组数组形式的数据类型。 class MFColor class MFFloat class MFInt32 class MFNode class MFRotation class MFString class MFTime class MFVec2f class MFVec3f class MFVec3d 所有的MF开头的类型都有属性length,可读可写,并且它们都可以用下列形式来构造: new MFXXX(SFXXX,SFXXX...) 第十一章 GUI二维界面 第一节 3D场景中的2D元素 一、 Text2 在创建文本造型的章节中,我们已经讲过Text2节点。在这里,我们主要强调Text2节点的平面性,无论是字体大小还是位置,都是以屏幕像素为单位的,这是2D的显著特点。 二、 Image Image节点可以通过使用image域或指定一个文件来画出一个2D图像。它的宽和高可以限定,默认时图像将按原比例显示。值得注意的一点是,Image节点在场景中的位置受当前的视点和摄像机的影响,这对于如何布置你的场景从而达到尽可能好的效果有很重要的意义。 默认格式: Image { width -1 #宽 height -1 #高 vertAlignment BOTTOM #垂直位置 BOTTOM|HALF|TOP horAlignment LEFT #水平位置 LEFT|CENTER|RIGHT image 0 0 0 #二维像素图像 filename "" #图片路径 }  图形用户界面GUI 之前的章节中我们介绍了使用接近传感器ProximitySensor和平行摄像机OrthographicCamera实现HUD的效果,但是在使用时会发现这样的实现方式制作的用户界面在调节时很不方便,如果变换使用场景,特别是在场景比例变化之后,用户界面有可能需要重新调节,另一方面就是还需要将很多精力放在对用户界面的风格设计,布局摆放上,制作用户界面往往变得耗时耗力。 图形用户界面(GUI)的这套体系,能够很好的帮我们解决上述情况带来的问题,在很大程度上提高了用户界面的开发效率,原来繁琐的工作变得轻松快捷。 GUI的外观部分主要由三个文件决定:imageset文件,scheme文件和looknfeel文件,而在实际开发中,开发人员不需要考虑这三个文件的具体该如何使用,仅需要考虑它的逻辑实现,对这三个文件的详细描述请参考《CC6开发应用教材进阶篇》 本节我们将详细介绍GUI节点的使用方法 l GUIGroup 所有GUI类节点必须位于一个GUIGroup内,它拥有以下属性 imagesets MFString 字符串数组中列出了可用的.imageset文件的存放路径 lookfeels MFString 字符串数组中列出了可用的.looknfeel文件的存放路径 schemes MFString 字符串数组中列出了可用的.scheme文件的存放路径 fonts MFNode 字符串数组中列出了可用的.font文件的存放路径 tooltipType SFString 可用的Tooltip children MFNode 节点数组,可以包含多个GUI节点 以下是一个简单的GUIGroup实例 #Lyinux V1.1 gb2312 DEF grp1 GUIGroup{ imagesets ["datas/imagesets/ Simple.imageset"] lookfeels ["datas/looknfeel/ Simple.looknfeel"] schemes ["datas/schemes/ Simple.scheme"] children[ DEF grp4 GUIWindow{ type " Simple /Button" position 0.2 0.8 size 0.1 0.1 } ] } 它的目录结构是 应用目录 ----cc6文件 ----datas ----imagesets ----looknfeel ----schemes l GUIWindow GUIWindow是所有GUI控件(除GUIListboxitem)的基类,它们会继承那些GUIWindow所拥有的特性,以下列表中列出了GUIWindow的基础域,输出域和输入域: 基础域 type SFString 声明类型,对应着looknfeel文件中定义的WidgetLook text SFString 文字显示部分 position SFVec2f 位置(0-1) size SFVec2f 尺寸(0-1) maxSize SFVec2f 最大尺寸(0-1) minSize SFVec2f 最小尺寸(0-1) topmost SFBool enabled SFBool 是否可用 visible SFBool 是否可见 active SFBool 是否当前被激活 alpha SFFloat 透明程度 inheritAlpha SFBool 是否继承透明度 cursor SFInt32 光标对应的编码 zorderEnabled SFBool 纵向层叠顺序是否可用 tooltip SFString 提示栏显示内容 tooltipType SFString 提示栏的类型 inheritTooltip SFBool 是否继承提示栏 riseOnClick SFBool processMouse SFBool lookfeel SFString font SFString 显示字体样式 horizontalAlignment LEFT | CENTRE | RIGHT 水平位置 verticalAlignment TOP | CENTRE | BOTTOM 竖直位置 generateMousemove SFBool properties MFString 需要特殊定义的控件属性名称和它们的值 输入域 propertyValue SFString 可以将某一个值赋给这个域 setProperty SFString 可以将looknfeel文件中出现过的Property或PropertyDefinition的名字赋给这个域,它的值将变为之前赋给propertyValue域的值 getProperty SFString 得到一个looknfeel文件中Property或PropertyDefinition的值 subscribe MFString 输出域 customEvent SFString 会发出自定义事件对应的字符串名称 isOver SFBool 鼠标放上去时为true,离开时为false mouseMove SFVec2f 鼠标在窗口移动时,返回相对于窗口的坐标。 mouseWheel SFFloat 滚动鼠标滚轴,向上为1,向下-1 isLeftActive SFBool 点击主键(一般为左键)时发出 isMiddleActive SFBool 点击中间键时发出 isRightActive SFBool 点击次键(一般为右键)时发出 isClick SFBool 单击时发出 isDoubleClick SFBool 双击控件时发出 isTripleClick SFBool 连击3次控件后发出 keydown SFInt32 (定义同System) keyup SFInt32 (定义同System) input SFString l GUICheckbox 本节点用于定义多选框,用户可以通过这个节点实现多项选择。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 selected SFBool 多选框选中时为true,未选中时为false 以下是一个简单的多选框节点的应用 DEF group2_2 GUICheckbox{ type "Simple/Checkbox" position 0.15 0.35 size 0.15 0.05 text "阅读" alpha 0.9 } 其中,type定义了使用什么类型的控件,position定义了控件在父节点中的相对位置(从0到1)size制定了它的大小,text的内容将会出现在多选框旁边,alpha表明透明度。 l GUICombobox 该节点用于定义下拉框,通过在items属性中包含GUIListboxitem节点来实现下拉菜单效果。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 readonly SFBool 设为True时为只读 caratIndex SFInt32 光标位置 maxtextLength SFInt32 最大文字长度 selectionStart SFInt32 选择开始位置 selectionLength SFInt32 选择的长度 sort SFBool 是否排序 vertScroll SFBool 垂直滚动条是否显示 horzScroll SFBool 水平滚动条是否显示 singleClick SFBool 单击 droplistVisible SFBool 下拉列表是否显示 items MFNode 列表项的集合 itemSelected SFInt32 选中的列表索引 textAccept SFBool 是否允许输入文字 当用户输入文字并且回车之后,textAccept被设置为TRUE。 itemAccepted SFInt32 当用户在下拉框一个选项上点击之后,itemAccepted被设置为用户点击的索引。 addItem MFNode 添加列表项 removeItem MFNode 删除列表项 以下是一个GUICombobox的应用: DEF combo GUICombobox{ type "Simple/Combobox" position 0.01 0.1 size 0.2 0.4 text "abc" inheritTooltip TRUE inheritAlpha FALSE alpha 0.9 textAccept FALSE items[ DEF listItem0 GUIListboxitem{ text "c编辑" highlightImage " Simple -> MultiListSelectionBrush" } DEF listItem1 GUIListboxitem{ text "d编辑" highlightImage " Simple -> MultiListSelectionBrush" } ] } l GUIComboDroplist GUIComboDroplist实际上是下拉列表控件GUICombobox中存储列表的控件部分,查看looknfeel文件就可以发现一个Combobox控件实际是由ComboEditbox,ComboDroplist,和ImageButton共同构成的。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 sort SFBool 是否排序 multiSelect SFBool 是否允许多选 vertScroll SFBool 垂直滚动条是否显示 horzScroll SFBool 水平滚动条是否显示 selectedItems MFInt32 以选择项的集合 items MFNode 包含的项 addItem MFNode 添加项 removeItem MFNode 删除项 ensureVisible SFInt32 卷滚下拉框使得ensureVisible指示的选项可见 l GUIEditbox 本节点用于定义编辑框。用户可以用它实现输入框的效果。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 readonly SFBool 当readonly为TRUE时,此编辑框变为只读,用户不能在其中输入字符 caratIndex SFInt32 光标所处位置 maxtextLength SFInt32 可输入字符串的最大长度,例如,值为4时,最多只能输入4个字符 selectionStart SFInt32 反选的开始位置,此项与selectionLength结合使用可以设置初始时选中默认字符串的某一部分 selectionLength SFInt32 设定对反选的开始位置之后多少个字符串起作用 textAccept SFBool 用户回车事件 textColor SFColor selectColor SFColor l GUIFrameWindow 本节点用于定义窗口。在它的域children中可以包含其他的GUI节点,且chilren中的控件会跟随父窗体的移动一起移动。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 sizingEnabled SFBool 默认值为TRUE, 为TRUE时可以改变窗体大小 titlebarEnabled SFBool 默认值为TRUE, 为FALSE时不显示标题兰内容 closeEnabled SFBool 默认值为TRUE, 为TRUE时窗口提供关闭按钮, 为FALSE时关闭窗口不显示 rollupEnabled SFBool 默认值为TRUE, 为TRUE是双击窗口标题栏,窗口收起,再次双击时窗体打开,为FALSE时双击标题栏不起作用 dragEnabled SFBool 默认值为TRUE, 为TRUE是可以托拽,为FALSE时不可托拽 cursorLeftright SFInt32 cursorTopbottom SFInt32 cursorTopleft SFInt32 cursorTopright SFInt32 closed SFBool TRUE为用户请求关闭,FALSE为用户未请求 rolledup SFBool 默认值为TRUE, 窗体打开,设为FALSE时窗体收起 titleFont SFBool 默认值为TRUE,titleBar的字体是否与frameWindow保持一致,设为FALSE时不跟随FrameWindow的字体变化而变化 l GUIItemEntry GUIItemEntry节点一般作为GUIItemListbox的子节点出现,它是列表框中的一个个列表项,以下时它的一个简单应用: DEF favText GUIItemListbox{ type "Simple/ItemListbox" position 0.01 0.1 size 0.96 0.5 children [ DEF listItem1 GUIItemEntry{ type "Simple/ListboxItem" text "文件 aaa " selected TRUE children [ GUIWindow{ type "Simple/StaticText" position 0 0 size 1 1 text "jjjj" properties ["BackgroundEnabled" "False" "FrameEnabled" "False"] } ] } DEF listItem2 GUIItemEntry{ type "Simple/ListboxItem" text "编辑" selectable FALSE } ] } 由于GUIItemEntry是一个GUIWindow,使它拥有children域,上例中第一个GUIItemEntry包含了子节点,这和后面将要提到的GUIListboxitem节点不同,GUIListboxitem和虽然在使用上表面看不出什么不同,但GUIListboxitem并不是一个GUIWindow,这使得GUIListboxitem不能有其他的子节点。GUIItemEntry除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 selected SFBool 是否被选中 selectable SFBool 是否可选 l GUIItemListbox 本节点用于定义列表框。它与GUIListbox在用途上很相似,GUIListbox占用的资源相对较少,而且操作起来比较方便。而GUIItemListbox的好处在于可以包含比较复杂GUIWinodw控件。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 sort SFBool 是否排序 sortMode ASCENDING | DESCENDING 正序或倒序 multiSelect SFBool 是否允许多选 autoResize SFBool 是否自动改变尺寸 vertScroll SFBool 垂直滚动条是否显示 horzScroll SFBool 水平滚动条是否显示 l GUIListbox 本节点同样用于定义列表框。它占用的资源相对较少,但是由于它使用GUIListboxitem作为它的列表项,GUIListboxitem并不是一个GUIWindow,这使得它的表现形式上会受到限制。GUIListbox除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 sort SFBool 是否排序 multiSelect SFBool 是否允许选择多项 vertScroll SFBool 如果为True,垂直滚动条将一直出现 horzScroll SFBool 如果为True,水平滚动条将一直出现 selectedItems MFInt32 被选中项的索引集 items MFNode 包含的列表项 addItem MFNode 添加列表项 removeItem MFNode 删除列表项 ensureVisible SFInt32 autoHeight SFBool 自动设定高度(缺省是FALSE) autoWidth SFBool 自动设定宽度。(缺省是FALSE) l GUIListboxitem 本节点用于描述列表项。值得注意一点的是,GUIListboxitem并不是一个GUIWindow,所以它也没有继承GUIWindow的属性域。以下列出了它所拥有的域: 扩展域 text SFString 列表项的内容 tooltip SFString 提示框中出现的内容 font SFString 字体 highlightImage SFString 高亮时的图片 highlightTopleft SFVec4f 高亮左上角位置颜色(RGB)及透明度的值 highlightTopright SFVec4f 高亮右上角位置颜色(RGB)及透明度的值 highlightBottomleft SFVec4f 高亮左下角位置颜色(RGB)及透明度的值 highlightBottomright SFVec4f 高亮右下角位置颜色(RGB)及透明度的值 textTopleft SFVec4f 文字左上角位置颜色(RGB)及透明度的值 textTopright SFVec4f SFVec4f 文字右上角位置颜色(RGB)及透明度的值 textBottomleft SFVec4f SFVec4f 文字左下角位置颜色(RGB)及透明度的值 textBottomright SFVec4f SFVec4f 文字右下角位置颜色(RGB)及透明度的值 l GUIMenubar 本节点用于定义菜单栏。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 itemSpace SFFloat item之间的距离,单位是像素 multiplePopup SFBool 是否支持多个弹出窗口,设为TRUE,则可以弹开多个子菜单 l GUIMenuItem 本节点用于定义菜单项,一般情况下,它作为GUIMenubar的子节点出现。如果它需要有下拉菜单,可以在GUIMenuItem的chilren域中使用GUIPopupMenu节点。GUIMenuItem同样用在GUIPopupMenu中描述子菜单项。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 popup SFBool l GUIMultiLineEditbox 本节点用于定义多行文本框。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 readonly SFBool 为True时编辑框为只读状态 caratIndex SFInt32 光标所处位置 caratIndex既是出事件,又是入事件(IOC普通域)。由于窗口失去焦点之后caratIndex隐藏(由looknfeel决定),因此使用外部设置是看不到效果的。但是使用route,我们可以轻松实现无法编辑10以上位置的情况). maxtextLength SFInt32 在编辑框中显示的最大字符长度 selectionStart SFInt32 选择开始的索引位置 selectionLength SFInt32 选择多长的字符串 textColor SFColor 用于定义字体颜色 selectColor SFColor 用于定义选中的字体颜色 l GUIPopupMenu 本节点用于定义下拉菜单。它的children域可以用GUIMenuItem作为子节点定义菜单项。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 fadeIn SFFloat 下拉菜单淡入所需的时间,以秒为单位 fadeOut SFFloat 下拉菜单淡出所需的时间,以秒为单位 l GUIProgressBar 本节点用于定义进度条。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 stepValue SFFloat 步长 设置每次调用doStep的步进 progress SFFloat 进度条的当前位置(0-1) doStep SFBool 步长是否有效。 设置一次True(调用一次)将菜单步进一次。读值得时候本值恒为FALSE.初始化无效。 vertical SFBool 是否垂直增长 reverse SFBool 是否反向增长 l GUIPushButton 本节点用于定义按钮。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 l GUIRadioButton 本节点用于定义单选按钮。通过设置相同的group的值,使不同的GUIRadioButton定义在同一个组中,在同一组中的项只可能同时选中其中的一个。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 selected SFBool 是否被选中 group SFInt32 所在组的ID l GUIScrollPane 本节点用于定义滚动面板。可以将像GUIMultiLineEditbox这样的节点作为它的子节点使用。当超过一定界限时,滚动条将会自动出现。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 vertStep SFFloat 垂直滚块步长 vertOverlap SFFloat 垂直滚块跳阶长度 vertPosition SFFloat 垂直滚块位置 horzStep SFFloat 水平滚块步长 horzOverlap SFFloat 水平滚块跳阶长度 horzPosition SFFloat 水平滚块位置 vertScroll SFBool 如果为True时垂直滚动条始终显示 horzScroll SFBool 如果为True时水平滚动条始终显示 autoResize SFBool 是否自动改变尺寸 contentSize SFVec2f 内容的尺寸 l GUIScrollbar 本节点用于定义滚动条。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 documentSize SFFloat 被滚动条处理的文档宽度/高度 pageSize SFFloat 每一页的宽度/高度 stepSize SFFloat 每点击增加或减少按钮时滚动条的变化步长 overlapSize SFFloat 页眉,整页切换时保留的长度(上页尾).跳跃移动时的步长 scrollPos SFFloat 滚动条的当前位置 (0到documentSize-pageSize) vertical SFBool 是否竖向.需要外观定义文件支持. l GUISlider 本节点用于定义滑动条。它一般作为调节工具使用。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 maxValue SFFloat 最大上限值 stepValue SFFloat 步长 value SFFloat 当前值 vertical SFBool 是否竖向.需要外观定义文件支持. l GUISpinner 本节点用于定义微调器。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 maxValue SFFloat 显示数字的最大上限 minValue SFFloat 显示数字的最小上限 stepValue SFFloat 步长 value SFFloat 默认值 textMode NONE | FLOATINGPOINT 小数形式表示| INTEGER 整数形式表示| HEXADECIMAL十六进制表示 | OCTAL八进制表示 l GUITabControl 本节点用于定义分页面板。它的children中的每一个子节点都将作为一个独立的分页,分页所显示的名称为该子节点的text域值。它除继承了GUIWindow的属性域之外还有如下的扩展域: 扩展域 tabOnTop SFBool 是否为当前分页 selctedTab SFInt32 选中的分页栏 tabHeight SFFloat 分页的高度 textPadding SFFloat 文本的间隙值 tabPanePosition SFEnum Top(0,default) | Bottom(1). 设定Tab的位置 调用篇 第十二章 虚拟现实结构体系 第一节 内联节点 Inline为内联节点,从本文件范围之外的其他文件或者互联网的任意位置上,调用不需要进行修改加工素材。 当需要创建包括复杂场景和造型的大型虚拟世界的时候,文件就会变得非常庞大,难于进行管理和调试。采用内联的方法。可以将复杂的场景和造型分解成各自独立的小文件,分别进行设计和调用,作为素材模块存在本地硬盘或者互联网的任意位置上。构建主程序时,在需要插入素材的位置,只需要利用内联节点只明素材文件的地址和文件名即可完成调用和插入素材的过程,素材可以很方便地成为整个场景的一部分。 Inline内联节点语法格式如下: 节点名称 域名称或事件 域值 #域,域值或事件类型 Inline{ url " " #exposedFieldMFString bboxCenter 0.0 0.0 0.0 #SFVec3f bboxsize -1.0 -1.0 -1.0 #SFVec3f asynchronism TRUE #SFBool } url用于设定所有调入的素材文件的url地址和文件名。若素材文件与主程序文件在同一个文件夹下,仅指名素材文件名即可。 bbox Center用于设定包围该编组节点所有造型的包围盒的中心点坐标。 bboxsize域的域值用于设定包围盒在当前坐标系中 X、Y、Z方向上的尺寸,包围盒是一个立方体。 asynchronism用于设定是否异步加载,缺省是true。异步加载不能提高总加载时间,但是可以以最快的速度给用户反馈 另一方面,在一个场景中,往往会出现一个物体使用很多次的情况,如果每次都进行加载将会浪费很大的系统资源,大大影响用户体验,通过使用Inline可以允许我们一次加载,多次使用。下面给出了一个简单的Inline应用,这种方法大大提高了大场景的加载速度: #Lyinux V1.1 gb2312 Switch { choice[ DEF primsea Separator { Inline { url "proto/sea.cc6" } } ] whichChoice -1 } DEF g_10_8 Transform { translation 10 0 8 rotation 1 0 0 1.57 children [ USE primsea ] } DEF g_9_8 Transform { translation 9 0 8 rotation 1 0 0 1.57 children [ USE primsea ] } 这里,我们首先利用Switch将sea.cc6的场景悄悄的加载进内存,每次使用时只需用USE命令即可。 第二节 原型 一、 原型定义 除了使用Lyinux中所支持的基本节点外,用户还可以根据需要,自定义一些新的节点类型,这种功能就是通过原型来实现。原型节点声明了它的域,入事件和出事件。一旦声明为一个原型,就可以当作一个节点一样来用。 原型一旦被定义之后,就可以像普通节点一样被实例化了,一般有两种情况:原型的定义与使用处于同一文件,或者,原型的定义与使用在不同文件。如果在相同文件,定义原型后可以直接使用该原型,如果不在同一文件,需要使用这个原型的文件中在使用之前需要先声明引用的外部原型具体信息。 声明原型语句PROTO分为两部分:原型接口声明部分和原型定义部分。原型接口声明部分紧跟原型名称之后,用中括号[]括起,在其中声明原型接口,包括原型的入事件和出事件的类型和名称,以及原型的域的类型、名称和缺省值。原型的定义部分用大括号{}括起,在其中若要将某一节点的属性定义为接口,需要用关键字IS将该属性与接口连接。以下为一个原型声明的实例: #Lyinux V1.1 gb2312 PROTO ball[ exposedField SFFloat theTransparency 0.2 exposedField SFColor theColor 0.8 0.8 0.8 ] { Shape{ appearance Appearance { material Material { diffuseColor IS theColor transparency IS theTransparency } } geometry Sphere {} } } 本例中声明了原型ball,它共有两个类型为exposedField的接口,theTransparency和theColor。定义部分中定义了一个球体,其中,Material的属性diffuseColor和transparency分别用IS与theTransparency和theColor这两个接口建立了关系。 二、 原型调用 原型可以嵌套,即声明一个原型中可以引用其他的原型,只需将被调用原型的声明部分写入调用它的原型的定义部分即可。 原型只需声明一次,可以多次使用。只要声明一次之后,就可以随意实例化出多个这种原型的引用,而且改变任意一个的值并不会影响到其他引用的状态。 在调用原型时分外部调用和内部调用两种。 当调用发生在同属于声明原型的文件之内时,可以直接引用,接上部分实例,加入如下代码: ball{ theTransparency 0.5 theColor 1 0 0 } 当用CC6浏览器打开这个文件时,将出现一个半透明的红色球体(注意:如果文件中只有声明原型的部分而没有调用原型的部分,打开将看不到任何物体) 当调用发生在声明原型的文件的外部时,需要使用EXTERNPROTO关键字在调用之前声明该外部原型。如某一场景需要使用原型ball,则需要在使用之前作如下声明: EXTERNPROTO ball [ ] ["prototype/ball.cc6"] 第三节 原型与内联节点的区别 PROTO原型和Inline内联节点都可以将其他的3D场景调用至当前场景,但二者有区别,在使用时要根据实际需要选择调用方式。 ü PROTO是同步加载的,虽然它也可以进行异步加载,但不是真正的异步;Inline天生是异步的,这个异步是真正的异步,不同于PROTO的异步加载; ü PROTO是定义一个标签,扩展系统功能,原型可以与场景进行交互,而Inline节点无法实现这个功能。 ü Inline类似于HTML中的IFrame;而PROTO类似于XML DTD。 由于Inline的异步性,可以大大提高场景的加载和运行效率,所以如果要调用的场景和主场景没有交互,请优先使用Inline节点。 第四节 原型构成体系 1. 体系概念 体系在汉语词典中的定义是若干事物或某些意识互相关联而构成的整体。 随着我们的3D虚拟世界的不断扩大,很多资源会出现重复使用的现象,例如一本书存在于一个场景之中,而另一场景同样存在着一本相同的书,又如在实际操作中,体系可以帮助我们的分工明确,由3D建模人员制作出基本的物体原型后,将需要改变的节点属性设为可以被外部修改的接口,交互脚本制作人员在此原型的基础上制作出可交互访问的物体原型。通过在功能实现上的划分,不仅可以是一个原型可以被多次运用到不同实际应用中,还可以使工作人员各司其职,更可以利用广大的用户资源,汇集用户自制的各类原型,将我们的3D虚拟世界日益壮大。 1. 体系与原型 体系是一个由1个或多个原型构成,为了保证良好的可复用性,每个原型应负责完成相对独立的工作。原型之间的关系可以嵌套,即一个原型中还引用了其他的原型。原型提供一些对外的接口(域),这些接口可以允许外部调用原型时向原型传递新的参数值,从而改变那个被引用的原型的某个属性。这些接口,只对所在原型的上一级调用有效。建立体系结构是需要按照严紧,理性,独立,可复用的原则,形成规范,体系中的每个原型,对应一个规范文档,在规范文档中描绘原型的表现形式,哪些属性对外公开,属性的赋值范围和类型是什么。 原型是体系的基础,一个体系的好坏,决定于原型设计的是否合理。当定制一个原型时,应考虑到原型中的哪些属性在不同的应用当中会被经常修改,这样的属性应声明为一个原型的域(exposedField)。 通信篇 第十三章 客户端与服务器端的通信 第一节 WWWAnchor WWWAnchor节点可以实现在一个物体上建立链接,在场景中嵌入一个网页悬浮框。 name属性将定义打开网页的url。 size设定网页悬浮框的大小,SFVec2f类型,单位为像素。 map设定网页链接触发的方式。为POINT时为鼠标点击物体时触发,为NONE时为鼠标在物体之上时触发。 以下例子中。当点击物体Cube,将以点击的位置为中心打开一个200*300的窗口,在其中显示test.html的内容。本节点请慎用,因为本节点不支持跨平台,在控件中也无效 WWWAnchor { name test.html size 200.0 300.0 map POINT Transform{ translation -0.2 -0.5 0 children[ BaseColor {rgb 1 1 1} Cube{} ] } } 第二节 Form节点 引入Form节点,是为了更好地与服务器端传递数据而设,与HTML中的AJAX(Asynchronous Javascript And XML, 异步Javascript和XML)技术类似。 Form节点中域值说明: SFString action : 用来定义要提交到的页面。 SFString selectfile : 用于上传文件。 SFBool recieve : 定义了是否接收返回值,为TRUE时,可以接收到response发回的字符串。 method POST | GET | HEAD | PUT ,比较常用的传输方式是GET和POST。当使用GET时传送的数据会附加在action中的URI之后,而用POST传送的数据将包装在请求的body中,这使在用GET传递的方式时数据的长度受到了一定的限制,并且在传送敏感数据时,会出现在URI部分。所以在传递用户名和密码这类数据时应使用POST方式。 SFInt32 state 表示Form在提交时的不同状态。 SFString response 服务器端的返回值。 SFBool submit 默认值FALSE,表示是否开始向服务器端发送请求,为TRUE时开始发送。 SFBool preLoad默认值FALSE,表示是否将结果预加载,为TRUE时预加载action指示的场景(使用action相对路径)。如果预加载打开,response被清空.result保存了加载完毕后的节点 SFNode result预加载结果.只有preLoad打开的情况下,本域才有效.注意:state为0的时候并不意味着result不为空.比如:提交成功但是加载失败. 以下是一个Form节点的例子: 可以使用CC6浏览器查看示例效果 场景文件 :formtest.wrl #Lyinux V1.1 gb2312 BaseColor {rgb 1 1 1} Font {name "黑体" size 15 } DEF tmp Transform { children [ DEF tt TouchSensor {} Shape { appearance Appearance { material Material { diffuseColor 1 1 1 } } geometry Box { size 0.6 0.2 0.2 } } Transform { translation -0.25 -0.03 0.11 children [ Font {name "黑体" size 0.1 } BaseColor {rgb 0 0 0} DEF uptext Text3{ string "UpdateFile" justification LEFT spacing 1 } ] } ] } DEF tmp1 Transform { translation 1 0 0 children [ DEF tt1 TouchSensor {} DEF box Shape { appearance Appearance { material Material { diffuseColor 1 0 0 } } geometry Box { size 0.2 0.2 0.2 } } ] } DEF tmp2 Transform { translation -1 0 0 children [ DEF tt2 TouchSensor {} USE box ] } DEF form Form{ action "testfile.php" SFString name '' SFInt32 size 0 recieve TRUE method POST } DEF form1 Form{ action "test.php" SFString name '' SFInt32 size 0 recieve TRUE method POST } DEF form2 Form{ action "test.php" SFString name '' SFInt32 size 0 recieve TRUE method POST } DEF script Script { eventIn SFBool touch eventIn SFBool touch1 eventIn SFBool touch2 eventIn SFInt32 formstate eventIn SFInt32 formstate1 eventIn SFInt32 formstate2 field SFNode form USE form field SFNode form1 USE form1 field SFNode form2 USE form2 field SFNode tmp USE tmp field SFNode tmp1 USE tmp1 field SFNode tmp2 USE tmp2 field SFNode uptext USE uptext url "javascript: var str = 'DEF text Text2 {\n'; str += '\tstring \"waiting......\"\n'; str += '\tjustification LEFT\n'; str += '\tspacing 1\n'; str += '}\n'; var text = new SFNode(str); function touch(v){ if(v){ form.selectfile = 'name'; form.size = 1; form.submit = true; uptext.string = new MFString('Waiting....'); } } function touch1(v){ if(v){ form1.name = 'form_tmp1'; form1.size = 2; form1.submit = true; tmp1.removeChild(); tmp1.addChild(text.getChild(0)); } } function touch2(v){ if(v){ form2.name = 'form_tmp2'; form2.size = 3; form2.submit = true; tmp2.removeChild(); tmp2.addChild(text.getChild(0)); } } function formstate(v){ if(v==0){ alert(form.response); uptext.string = new MFString('Success!'); }else{ alert(v); var node = SFNode.get('text'); node.string = new MFString('wrong!'); } } function formstate1(v){ if(v==0){ var node = new SFNode(form1.response); tmp1.removeChild(); tmp1.addChild(node); } } function formstate2(v){ if(v==0){ var node = new SFNode(form2.response); tmp2.removeChild(); tmp2.addChild(node); } } " } ROUTE tt.isActive TO script.touch ROUTE tt1.isActive TO script.touch1 ROUTE tt2.isActive TO script.touch2 ROUTE form.state TO script.formstate ROUTE form1.state TO script.formstate1 ROUTE form2.state TO script.formstate2 服务器端页面 :test.php < for($i=0;$i<10000;$i++){ for($j=0;$j<100;$j++){ $c = $i*$j; } } $name = $_POST["name"]; $size = $_POST["size"]; $str = ""; $str .= "DEF ".$name." Transform {\n"; $str .= "\tchildren [\n"; $str .= "\t\tShape {\n"; $str .= "\t\t\tappearance Appearance {\n"; $str .= "\t\t\t\tmaterial Material {\n"; $str .= "\t\t\t\t\tdiffuseColor 1 1 0\n"; $str .= "\t\t\t\t}\n"; $str .= "\t\t\t}\n"; $str .= "\t\t\tgeometry Box { size 0.05 ".$size." 0.05 }\n"; $str .= "\t\t}\n"; $str .= "\t]\n"; $str .= "}\n"; echo $str; > 服务器端页面 :testfile.php < for($i=0;$i<10000;$i++){ for($j=0;$j<100;$j++){ $c = $i*$j; } } $name = $_FILES["name"]; echo "文件名:".$name['name']."\n"; echo "文件类型:".$name['type']."\n"; echo "文件大小:".($name['size']/1000)."K\n"; > 第三节 Update节点 Update用于检查文件更新.可以集中检查若干的更新文件.不同于Form节点,Update并不加载文件,仅仅保留文件信息,因此除了带宽.Update节点不消耗资源,仅仅可以大幅提高后续场景的加载速度. Update{ resource MFString(保存了需要检查的资源文件,不执行分析动作,因此资源中引用的资源不会被检查). succeeded SFInt32 共成功更新了多少资源. failed SFInt32 更新失败的数量. merge SFBool (Default is TRUE).在resource发生变化时,是否与以前的更新动作合并.如果FALSE,resource的变化将停止以前的更新指令并将succeeded和failed清零,可以用来停止更新. localFirst SFBool (Default is TRUE).是否将更新的文件标示为本地优先,如果是,在系统重启之前,所有对相关资源的请求将不再访问网络,这将大幅提高加载速度,但是也会导致对服务器的更新失去响应. } 第四节 NetSyncer节点 NetSyncer节点为方便网络同步而引入,它拥有以下的域: certFile SFString 连接目标请求的cert文件。要求cert文件必须签名为url中的hostname:port.否则无法连接。 url SFString 连接目标的URL.形式如下 lyinux://hostname:port/spaceuri. script SFNode 接收回调的script节点。如有值,必须是Script节点。 self SFNode 代表了自身数据,如果有值,必须是InfoItem节点。用户只能修改自身的数据,也就是说,只有修改这里的数据才会被同步到网络中。名称为空。 others MFNode 保存了其它用户的数据。类型为InfoItem。不需要创建,当同步到其它用户数据时自动创建。其名称为'_user_'+'用户名'. spaces MFNode 保存了空间数据。类型为InfoItem。不需要创建,当同步到房间数据时自动创建。其名称为'_space_'+'空间名' enteredSpace MFString 保存了当前所处空间的名称。 netState SFInt32 网络状态。 userState SFInt32 用户状态。 delay SFTime 连接的服务器与本机的延时。(本值登陆成功之后刷新,每隔1分钟伴随sync刷新一次。每10分钟为一个累加单元) timeDiff SFTime 连接的服务器与本机的时间差(服务器时间-客户端时间)。本值不忽略时区信息,因此不能用于同步绝对时间(与服务器部处于不同时区会出错),仅用于保持一 个同步时间基准。所有连接进入同一个房间的用户保持同一个时间基准。(本值登陆成功之后刷新,每隔1分钟伴随sync刷新一次。每10分钟为一个累加单 元 ) delayExec SFTime 延时执行。数据附加了绝对时间,确保在所有客户端在同一个基准时间开始执行。本机延时delayExec之后设置相关域值。如果客户端收到同步指令的时差 小于delayExec,将在本时差到达时设置相关域值。否则立即设置,并在调用lyinuxSpaceSync/lyinuxUserSync增加第三 个参数timeouts(MFTime)保存了已超过的时间。缺省0,表示不开启缺省延时。 tryEnterSpace SFString 尝试进入房间 tryLeaveSpace SFString 尝试离开房间 immediate MFString 所有使用立即模式传输的域名。意味着这些域将不会被系统作性能优化,而是确保收到立即发出以保证中间值不会被优化掉 dynamicParent SFNode 自动创建模板父节点(保留,尚未实现) dynamicString SFString 自动模板字符串。(保留,尚未实现) dynamicRoute SFString 自动路由模板。(保留,尚未实现) 本节点将在进阶篇中做更为详细的介绍。 术语表 参考文献

下载文档到电脑,查找使用更方便

文档的实际排版效果,会与网站的显示效果略有不同!!

需要 20 金币 [ 分享文档获得金币 ] 0 人已下载

下载文档