赞
踩
WebGL(全写Web Graphics Library)是一种3D绘图协议,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。
Three.js是一款基于JavaScript可直接运行GPU驱动游戏与图形驱动应用于浏览器的WebGL引擎,其库提供的特性与API以绘制3D场景于浏览器。
Canvas与WebGL的区别是canvas API提供二维绘图方式,图形的绘制主要通过CanvasRenderingContext2D接口完成,通过 canvas.getContext('2d') 获取二维图像绘图上下文;而WebGL API可以在任何兼容canvas中的渲染2d和3d图形,WebGL API 提供三维接口,图形绘制主要通过WebGLRenderingContext接口完成,通过canvas.getContext('webgl')来获取WebGL上下文。
Three.js提供了一系列简化的API和工具,使得创建三维图形更加容易的展现在浏览器端。其抽象了底层的复杂性,提供了简单、一致的接口。提供基本的渲染功能之外,还包括了丰富的扩展,如光照、贴图、粒子系统等,可以满足不同类型的三维图形需求。Three.js有一个活跃的社区,提供了大量的文档、教程和示例,方便开发者学习和解决问题。
随着社会的信息化的发展,在数据可视化、图形/游戏引擎、交互演示、图形渲染、地图、VR、物品展示、室内设计、城市规划等方面Web端展示3D的需求大量增多,人们迫切需求一款能打开浏览器即可使用的便捷式3D开发引擎,而基于JavaScript的WebGL引擎Threejs恰好可以满足这一要求,所以得以大规模应用。
- 1.<script type="importmap">
- 2. {
- 3. "imports": {
- 4. "three": "https://unpkg.com/three@<version>/build/three.module.js",
- 5. "three/addons/": "https://unpkg.com/three@<version>/examples/jsm"
- 6. }
- 7. }
- 8.</script>
npm install three --save
- <script type="module">
- import * as THREE from './node_modules/three/build/three.module.js';
- var scene = new THREE.Scene()
- </script>
- <script src="./node_modules/three/build/three.js"></script>
- <script>
- var scene = new THREE.Scene()
- console.log(scene)
- </script>
Three.js的基本组件有场景(Scene)、相机(Camera)、渲染器(Renderer);
常见的类有Object3D、BufferGeometry、Geometry、BufferAttribute、Layers、Raycaster等;
Object3D类:Object3D是ThreeJs中对物体抽象的基类,包括相机和灯光都是Object3D的子类.一般情况下,我们不会直接使用这个类,对于构造物体,一般我们都是使用的Mesh.
BufferGeometry类:是面片、线或点几何体的有效表述.包括顶点位置,面片索引、法相量、颜色值、UV坐标和自定义缓存属性值.使用BufferGeometry可以有效减少向 GPU 传输上述数据所需的开销.
Geometry类:Geometry 是对 BufferGeometry 的替代,Geometry利用Vector3或Color存储了几何体的相关 attributes(如顶点位置,面信息,颜色等),但比起BufferGeometry更容易读写,但是运行效率不如有类型的队列.
BufferAttribute类:这个类用于存储与BufferGeometry相关联的attribute(例如顶点位置向量,面片索引,法向量,颜色值,UV坐标以及任何自定义attribute).利用BufferAttribute,可以更高效的向GPU传递数据.详情和例子见该页.
在BufferAttribute中,数据被存储为任意长度的矢量(通过itemSize进行定义),下列函数如无特别说明, 函数参数中的index会自动乘以矢量长度进行计算. 当想要处理类似向量的数据时, 可以使用在Vector2,Vector3,Vector4以及Color这些类中的.fromBufferAttribute(attribute,index) 方法来更为便捷地处理.
Layers类:Layers对象为Object3D分配1个到32个图层.32个图层从0到31编号标记.在内部实现上,每个图层对象被存储为一个bit mask,默认的,所有Object3D对象都存储在第0个图层上.图层对象可以用于控制对象的显示.当camera的内容被渲染时与其共享图层相同的物体会被显示.每个对象都需要与一个camera共享图层.每个继承自Object3D的对象都有一个Object3D.layers对象.
Raycaster类:这个类用于进行raycasting(光线投射).光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体).
场景是Three.js 中所有 3D 对象的容器。它定义了 3D 空间中的位置、方向和光照。
相机定义了 3D 场景中的视角。通过设置相机的位置和角度,可以控制场景中的视觉效果。
渲染器将场景和相机中的 3D 对象渲染到屏幕上。Three.js 提供了多个渲染器,包括 CanvasRenderer、WebGLRenderer 和 SVGRenderer。
- var geometry = new THREE.BoxGeometry(1, 1, 1);
- var material = new THREE.MeshBasicMaterial({color: 0xff0000});
- var cube = new THREE.Mesh(geometry,material);
- scene.add(cube);
- var gemo=new THREE.Geometry()
- // 第一步:定义⼏何体的顶点
- var vertices=[new THREE.Vector3(0,0,0),
- new THREE.Vector3(0,0,6),
- new THREE.Vector3(7,0,0),
- new THREE.Vector3(0,8,0)]
- // 第二步:定义顶点的连接顺序,顺时针为向光,逆时针为背光
- var face=[new THREE.Face3(0,1,2),
- new THREE.Face3(0,2,3),
- new THREE.Face3(0,1,3),
- new THREE.Face3(1,2,3)]
- gemo.vertices=vertices;
- gemo.faces=face;
- gemo.computeFaceNormals(); // 重新计算几何对象面
- var Mesh=[new THREE.MeshLambertMaterial({
- color:0x44ff44,opacity:0.6,transparent:true
- }),
- new THREE.MeshBasicMaterial({
- color:0x000000,wireframe:true
- })]
- // 第三步:定义两种材质混和
- var mesh=new THREE.SceneUtils.createMultiMaterialObject(gemo,Mesh)
- mesh.children.forEach((item)=>{ item.receiveShadow=true; })
- // 这样就创建了⼀个四⾯体,
- // 其中THREE.SceneUtils.createMultiMaterialObject(gemo,Mesh)
- // 是创建多种材质的⽹格对象,接下来我们还可以⽤dat.GUI控制它的各个顶点
创建复杂的3D模型和场景需要使用Three.js提供的各种高级功能和技术。可以通过加载外部3D模型文件来创建复杂的模型,如.obj或.fbx文件。可以使用Three.js提供的各种几何体工具来构建自定义模型。对于复杂的场景,可以通过管理多个场景对象、使用光源和阴影、应用材质和纹理等来实现。
通常叫做模型加载器,一般用来加载外部特定格式的模型文件;常用的模型加载器有GLTFLoader GLTF模型加载器、OBJLoader OBJ模型加载器、STLLoader STL模型加载器、 FBXLoader动画模型加载器等等。
以FBX模型加载器为例
第一步:引入fbx模型加载库FBXLoader
<script src="../js/loaders/FBXLoader.js"></script>
第二步:辅助文件
<script src="../examples/js/libs/inflate.min.js"></script>
第三步:加载FBX模型并解析
- var mixer=null;//声明一个混合器变量
- var loader = new THREE.FBXLoader();//创建一个FBX加载器
- loader.load("SambaDancing.fbx", function(obj) {
- // console.log(obj)
- scene.add(obj)
- obj.translateY(-80);
- // obj作为参数创建一个混合器,解析播放obj及其子对象包含的动画数据
- mixer = new THREE.AnimationMixer(obj);
- // 查看动画数据
- console.log(obj.animations)
- // obj.animations[0]:获得剪辑对象clip
- var AnimationAction=mixer.clipAction(obj.animations[0]);
- // AnimationAction.timeScale = 1; //默认1,可以调节播放速度
- // AnimationAction.loop = THREE.LoopOnce; //不循环播放
- // AnimationAction.clampWhenFinished=true;//暂停在最后一帧播放的状态
- AnimationAction.play();//播放动画
- })
- // 创建一个时钟对象Clock
- var clock = new THREE.Clock();
- // 渲染函数
- function render() {
- renderer.render(scene, camera); //执行渲染操作
- requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
- if (mixer !== null) {
- //clock.getDelta()方法获得两帧的时间间隔
- // 更新混合器相关的时间
- mixer.update(clock.getDelta());
- }
- }
- render();
推荐使用GLTF(gl传输格式)来对三维物体进行导入和导出,glTF(gl传输格式)是一种开放格式的规范 (open format specification), 用于更高效地传输、加载3D内容。该类文件以JSON(.gltf)格式或二进制(.glb)格式提供,外部文件存储贴图(.jpg、.png)和额外的二进制数据(.bin).一个glTF组件可传输一个或多个场景, 包括网格、材质、贴图、蒙皮、骨架、变形目标、动画、灯光以及摄像机等。
Three.js常见的光源类型有环境光(AmbientLight) 点光源(PointLight) 聚光灯(SpotLight) 平行光(DirectinalLight)等。
环境光(AmbientLight):类似于漫反射,没有光照起点,环境光可以放在任意一个位置,不会衰减,不需要设置光强,各个点都一样,所以不用设置位置。
点光源(PointLight):类似于照明弹,点光源是从一个点出发,向各个方向发射光线。其第一个参数表示光颜色;第二个参数表示光照强度,范围为0~1;第3个参数表示光照距离,默认为0,表示无限远;第4个参数表示光照强度随着光照防线逐渐衰减的量,默认为1。
聚光灯(SpotLight):聚光灯从开始位置以锥形的照射向目标位置发射光线,默认目标位置为原点。第一个参数表示颜色,默认为白色;第二个参数表示光强,默认为1,范围0~1;第三个参数表示光照距离,默认为根据光源距离,线性衰减光源的最大距离;第4个参数表示Math.PI/2;第5个参数表示根据光照锥形计算的阴影的百分比;第6个参数表示光照强度随着光照防线逐渐衰减的量。
平行光(DirectinalLight):从其位置开始,向目标方向照射,不会随着距离而衰减;目标方向默认是原点,可以自定义,然而对于自定义目标位置,也需要加入到场景中才会生效;类似于太阳光;方向光的创建接收2个参数,第一个表示光照颜色,第二个表示光照强度,光照强度取值范围为0~1,光照递增;
在 three.js 中,实现一个基本的光照模型需要创建一个光源对象 (light),并设置光源的位置,颜色和强度。接下来,需要将光源对象添加到场景对象中,并将场景对象渲染到屏幕上。
点光源,聚光灯,方向光;环境光不支持阴影;
- const light = new THREE.AmbientLight( 0x404040 ); // 柔和的白光
- scene.add( light );
通过纹理贴图加载器TextureLoader的load()方法加载一张图片可以返回一个纹理对象Texture,纹理对象Texture可以作为模型材质颜色贴图. map属性的值。
材质的颜色贴图属性. map设置后,模型会从纹理贴图上采集像素值,这时候-般来说不需要在设置材质颜色. color。. map贴图之所以称之为颜色贴图就是因为网格模型会获得颜色贴图的颜色值RGB。
- // 纹理贴图映射到- -个矩形平面上
- var geometry = new THREE.PlaneGeometry(204,102); //矩形平面
- // TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理
- var textureLoader = new THREE.TextureLoader() ;
- // 执行1oad方法,加载纹理贴图成功后,返回- -个纹理对象Texture
- textureLoader.1oad('Earth. png', function(texture) {
- var material = new THREE .MeshL amber tMaterial({
- // color: 0x0000ff,
- // 设置颜色纹理贴图: Textur e对象作为材质map属性的属性值
- map: texture,//设置 颜色贴图属性值
- }); //材质对象Material
- var mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
- scene.add(mesh); //网格模型添加到场景中
- // 纹理贴图加载成功后,调用渲染函数执行渲染操作
- // render();
- })
法线贴图就是在原物体的凹凸表面的每个点上均作法线,通过RGB颜色通道来标记法线的方向,你可以把它理解成与原凹凸表面平行的另一个不同的表面,但实际上它又只是一个光滑的平面。对于视觉效果而言,它的效率比原有的凹凸表面更高,若在特定位置上应用光源,可以让细节程度较低的表面生成高细节程度的精确光照方向和反射效果。比如红砖墙面。
通过设置场景的背景(background),增强显示效果,环境贴图一般使用全景图,分成6张图片,以立体贴图(CubeTexture)的方式进行加载。比如不锈钢栏杆的扶手球。
材质(Material)是描述物体外观和光学特性的属性集合。它包括物体的颜色、反射属性(如漫反射、高光反射)、透明度、折射率等。材质定义了物体如何与光线进行交互,决定了物体在渲染时的外观效果。
纹理(Texture)是一种图像,用于模拟物体表面的细节和纹理。它可以包含颜色信息、细节图案、纹理细节等。通过将纹理映射到模型表面,可以赋予模型更加真实的外观和细节。
贴图(Texture Map)是将纹理应用到3D模型表面的过程。贴图是通过将纹理图像与模型的顶点或像素相匹配,使得纹理图像覆盖在模型表面,在渲染过程中,根据贴图的坐标信息来确定模型表面的颜色、纹理细节等。
几何体 (geometry) 是 three.js 中的一个基本概念,它表示一个 3D 对象的形状和结构。
材质 (material) 用于定义几何体的外观,例如颜色,纹理等。
网格 (mesh) 是 three.js 中的一个基本对象,它表示一个由多个几何体组成的3D对象。
1.创建集合体
2.引入纹理贴图加载器TextureLoader并加载纹理贴图。
3.使用这个纹理贴图来创建了一个材质对象;
4.使用这个材质对象来创建了一个网格对象;
5.几何体和材质相结合放到场景中并渲染。
例如:
- // 创建一个场景对象
- let scene = new THREE.Scene();
- // 创建一个相机对象
- let camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
- camera.position.z = 5;
- // 创建一个渲染器对象
- let renderer = new THREE.WebGLRenderer();
- renderer.setSize(window.innerWidth, window.innerHeight);
- document.body.appendChild(renderer.domElement);
- // 创建立方体几何体
- let geometry = new THREE.BoxGeometry(1, 1, 1);
- // 创建纹理贴图对象,并加载纹理贴图文件
- let textureLoader = new THREE.TextureLoader();
- let texture = textureLoader.load('path_to_your_texture_file.jpg'); // 请将 'path_to_your_texture_file.jpg' 替换为你的纹理贴图文件的路径
- // 创建材质对象,并使用纹理贴图来设置材质的纹理属性
- let material = new THREE.MeshBasicMaterial({map: texture}); // 使用纹理贴图来设置材质的纹理属性,得到具有纹理效果的材质
- // 创建网格对象,将几何体和材质相结合
- let cube = new THREE.Mesh(geometry, material);
- // 将立方体添加到场景中
- scene.add(cube);
- // 设置渲染循环
- function animate() {
- requestAnimationFrame(animate);
- cube.rotation.x += 0.01; // 让立方体绕自身X轴旋转
- cube.rotation.y += 0.01; // 让立方体绕自身Y轴旋转
- renderer.render(scene, camera); // 渲染场景和相机
- }
- animate(); // 开始渲染循环
镜面反射和折射效果可以使用立方体贴图和反射向量来实现。Three.js 提供了 THREE.CubeCamera 来捕获环境贴图,以实现镜面反射。但是CubeCamera更适用于创建物体自身对环境的反射,但是如果想要创建一面镜子的话使用CubeCamera会难调试所反射物体的位置,而且镜面中的物体不会随着控制器的缩放而变动。
推荐引入Reflector.js实现镜面反射。
第一步:导入 Reflector.js
<script src="../../libs/examples/js/objects/Reflector.js"></script>
第二步:创建镜子形状,以矩形的平面为例
var planeGeometry = new THREE.PlaneBufferGeometry(10, 10);
第三步:配置镜子参数
var options = {
clipBias: 0.03,
textureWidth: window.innerWidth * window.devicePixelRatio,
textureHeight: window.innerHeight * window.devicePixelRatio,
color: 0x889999,
recursion: 1
};
第四步:创建镜子并加入场景
var mirror = new THREE.Reflector(planeGeometry, options);
scene.add(mirror);
平移:设置模型的position或者translateX、translateY、translateZ等;
如果要求沿着自定义方向平移,
var axis = new THREE.Vector3(1, 1, 1); // 向量Vector3对象表示方向
axis.normalize(); // 向量归一化
mesh.translateOnAxis(axis, 100); // 沿着axis轴表示方向平移100
旋转:rotateX、rotateY、rotateZ 沿X、Y、Z轴旋转
沿自定义轴旋转
var axis = new THREE.Vector3(0,1,0); // 向量axis
mesh.rotateOnAxis(axis,Math.PI/8); // 绕axis轴旋转π/8
缩放:修改scale的值,1以上表示放大多少,1以下表示缩小多少
简单动画:利用物体的平移、缩放、旋转、闪烁等创建的动画;
摄像机动画:使用摄像机来实现第一人称视角、飞行视角、翻滚控制、轨迹球、轨道控制等动画;
变形动画:变形动画,要定义网格变形之后的关键位置。对于变形目标,所有顶点位置都会被存储下来。你需要做的就是将所有顶点从一个位置移动到另外一个定义好的关键位置,并重复该过程。
骨骼动画:使用骨骼动画需要定义骨骼,也就是网格的骨头,并将顶点绑定到特定的骨头上。然后移动一块骨头时,任何与其相连的骨头都会做相应的移动,同时骨头上绑定到顶点也会随之移动。网格的变形也是基于骨头的位置、移动和缩放实现的。
帧动画:创建关键帧动画,并控制其播放。
简单动画就是改变物体的长宽高位置颜色等属性,摄像机动画的第一人称视角通过FirstPersonControls(第一视角控制器)或PointerLockControls来实现,该控制器类似于第一视角射击游戏中的摄像机。使用键盘控制移动,使用鼠标转动。飞行视角通过FlyControls(飞行模拟控制器),用键盘鼠标控制摄像机移动。RollControls(翻滚控制器)该控制器是飞行控制器的简化版,允许绕着z轴旋转。TrackBallControls(轨迹球控制器),最常用的控制器,可以用鼠标(或者控制球)来轻松移动、平移和缩放场景。注意,OrtographicCamera摄像机专用控制器为OrtographicTrack BallControls。OrbitControls(轨道控制器)该控制器可以在特定场景中模拟轨道中的卫星,你可以使用鼠标键盘在场景中游走。除了使用控制器,还可以使用修改position属性移动摄像机,空过lookAt()方法改变摄像机的朝向。
three.js提供了三个核心动画类:
THREE.AnimationClip:当具有动画数据的模型被加载后,获得的模型对象往往具有一个名为animations的成员对象。该对象包含了一个THREE.AnimationClip对象集合。一个模型所包含的THREE.AnimationClip对象通常保存有某种特定类型的动画数据,或者是该模型能够执行的某种动作。例如,加载一个小鸟的模型,它可能包含两个THREE.AnimationClip对象,一个是拍打翅膀的动作,另一个是张嘴闭嘴的动作。
THREE.AnimationMixer:THREE.AnimationMixer对象用于控制多个THREE.AnimationClip对象,确保这些动画在适当的时间发生,使动画同步或者控制从一个动画过渡到另一个动画。
THREE.AnimationAction:当THREE.AnimationMixer对象添加一个THREE.AnimationClip对象时,调用者将会获得一个THREE.AnimationAction。很多动画控制功能是通过THREE.AnimationAction来调用的,而THREE.AnimationMixer本身并没有提供很全面的接口。除了添加动画外,THREE.AnimationAction对象也可以随时从THREE.AnimationMixe获取。
你可以使用 requestAnimationFrame 或 Three.js 的动画循环来创建基于时间的动画。骨骼动画则涉及骨骼和动画混合器,用于控制模型的骨骼动作。
three.js可以通过鼠标交互、触摸交互、键盘交互、碰撞检测、物理引擎等方式交互。
鼠标交互:可以使用threeJS中的鼠标事件来实现模型的交互,例如点击、拖拽、旋转等。
触摸交互:对于移动设备,可以使用threeJS中的触摸事件来实现模型的交互,例如滑动、缩放等。
键盘交互:可以使用threeJS中的键盘事件来实现模型的交互,例如按键控制模型的移动、旋转等。
碰撞检测:可以使用threeJS中的碰撞检测功能来实现模型之间的交互,例如模型之间的碰撞、触发事件等。
物理引擎:可以使用threeJS中的物理引擎来实现模型的物理交互,例如重力、摩擦力、弹性等。
通过OrbitControls插件给模型添加缩放,旋转,平移和拖拽等效果;
通过EffectComposer效果组合插件和OutlinePass插件给模型添加光晕等效果;
通过Raycaster光影投射实现鼠标拾取效果;
- //将鼠标点击位置的屏幕坐标转成threejs中的标准坐标,具体解释见代码释义
- mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
- mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
- var raycaster = new THREE.Raycaster();
- raycaster.setFromCamera(mouse, camera);
- //射线和模型求交,选中一系列直线
- var intersects = raycaster.intersectObjects(objects);
- console.log('imtersrcts=' + intersects)
- if (intersects.length > 0) {
- //选中第一个射线相交的物体
- SELECTED = intersects[0].object;
- var intersected = intersects[0].object;
- console.log(intersects[0].object)
- }
- }
在 three.js 中,事件是一种用户交互的方式,它可以在用户执行某些操作时触发。
缓冲区是用于存储和管理数据的一种内存区域。在Three.js中,可以通过BufferGeometry来创建自定义的缓冲区,以实现更高效的渲染。例如,可以通过BufferGeometry来直接操作顶点数据、索引数据和材质数据等。
Three.js中的着色器是用来处理3D模型表面的渲染效果的程序。它们通常用于实现复杂的视觉效果,如阴影、光照、纹理等。可以通过创建ShaderMaterial或RawShaderMaterial来使用自定义着色器。在着色器代码中,可以通过"THREE.uniforms"来传递uniform变量,通过"THREE.vertexShader"和"THREE.fragmentShader"来定义顶点和片段着色器。
1.要选择具有投射阴影效果的材质
我们前面也提到过,基础网格材质MeshBasicMaterial是不受光照影响的,我们如果需要有阴影效果,就不能选择该材质
2.需要投射阴影的物体要设置castShadow属性
castShadow属性用于设置物体是否被渲染到阴影贴图中,默认为false,如果需要投影,则设置为true
3.接收阴影的物体要开启receiveShadow属性
receiveShadow属性用于设置材质是否接收阴影,默认为false,如果需要接收物体的投影,设置为true
4.灯光开启投射阴影castShadow属性
灯光也要设置castShadow为true,默认为false
5.渲染器设置允许在场景中使用阴影贴图
将渲染器的shadowMap.enabled属性设置为true,允许场景中使用阴影贴图
Three是右手坐标系,即Z轴指向自己,X轴指向右方,Y轴指向上方;
在webGL中,世界坐标系是以屏幕中心为原点(0, 0, 0),且是始终不变的。
屏幕坐标系窗口范围按此单位恰好是(-1,-1)到(1,1),即屏幕左下角坐标为(-1-1),右上角坐标为(1,1)。
mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(e.clientY / window.innerHeight) * 2 + 1;
推导过程
设A点为屏幕点击点(x1,y1), x1=e.clintX, y1=e.clientY;
设A点在世界坐标中的坐标值为A'(x2,y2);
由于A点的坐标值的原点是以屏幕左上角为(0,0);
我们可以计算可得以屏幕中心为原点的值A'
x2' = x1 - innerWidth/2
y2' = innerHeight/2 - y1
又由于在世界坐标的范围是[-1,1],要得到正确的B值我们必须要将坐标标准化
x2 = (x1 - innerWidth/2)/(innerwidth/2) = (x1/innerWidth)*2 - 1
y2 = -(y1 / innerHeight)*2 +1
代码上
世界坐标系转换到局部坐标系,用worldToLocal()方法
- var worldPosition = new THREE.Vector3(); // 世界坐标
- var localPosition = new THREE.Vector3(); // 局部坐标
- // 将世界坐标转换为局部坐标
- object.worldToLocal(worldPosition, localPosition);
局部坐标系转换到世界坐标系,用localToWorld()方法
- var localPosition = new THREE.Vector3(); // 局部坐标
- var worldPosition = new THREE.Vector3(); // 世界坐标
- // 将局部坐标转换为世界坐标
- object.localToWorld(localPosition, worldPosition);
屏幕坐标转换为三维场景中的坐标,用project()方法;
- var screenPosition = new THREE.Vector3(); // 屏幕坐标
- var worldPosition = new THREE.Vector3(); // 世界坐标
-
- // 将屏幕坐标转换为世界坐标
- screenPosition.x = (screenPosition.x / window.innerWidth) * 2 - 1;
- screenPosition.y = -(screenPosition.y / window.innerHeight) * 2 + 1;
- screenPosition.z = 0.5; // 需要设置一个深度值,通常为0.5
-
- screenPosition.unproject(camera); // 将屏幕坐标反投影到世界坐标
- screenPosition.sub(camera.position).normalize(); // 获取方向向量
- var distance = -camera.position.z / screenPosition.z; // 计算距离
- // 计算世界坐标
- worldPosition.copy(camera.position).add(screenPosition.multiplyScalar(distance));
第一种:创建一个盒子,然后将图片作为盒子6个面的纹理贴上来创建。
第二种:将纹理作为场景的背景来创建。
第三种:通过着色器的形式
三种方法视觉效果是几乎没区别的,会给人身临其境的效果,感觉身处在这个3维空间里,最明显的区别,就在于当你在用鼠标滚轮缩进的时候,天空盒会“原形毕露”,暴露出其盒子的本性,视觉效果原理展现在你的眼前。
可以使用 THREE.AudioListener、THREE.PositionalAudio 等来实现立体声音效果,根据音源位置和听众位置来计算音频效果。
AudioListener 用一个虚拟的listener表示在场景中所有的位置和非位置相关的音效.
一个three.js程序通常创建一个AudioListener. 它是音频实体构造函数的必须参数,比如 Audio and PositionalAudio.
大多数情况下, listener对象是camera的子对象. Camera的3D变换表示了listener的3D变换.
THREE.PositionalAudio创建一个位置相关的音频对象.
你可以使用 HTML5 <video> 元素或 Three.js 的 THREE.VideoTexture 类来加载和播放视频,然后将视频纹理应用到材质上。
WebGL对于texture的支持是有大小限制的,使用CanvasRenderer也会有同样的限制,只要手机支持WebGL,可以保证允许2048*2048的贴图,因此贴图最好不超过该限制。
模型导入器用于加载外部 3D 模型文件到 Three.js 中。Three.js 支持多种模型导入器,如 THREE.OBJLoader、THREE.FBXLoader 和 THREE.GLTFLoader。
这可能是由于面剔除而导致的。面是具有朝向的,这个朝向决定了哪边是正面或者哪边是背面。 在正常情况下,渲染时会将背面进行剔除。要查看这是不是你所遇到的问题,请将material的side更改THREE.DoubleSide。
material.side = THREE.DoubleSide
创建一个场景(Scene)对象,然后在场景中创建一个摄像机(Camera)对象和一个渲染器(Renderer)对象。接下来,您可以创建一个几何体(Geometry)对象,如立方体或球体,并应用材质(Material)。最后,将几何体添加到场景中,调整摄像机的位置和角度,最终使用渲染器将场景呈现在屏幕上。
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
我们希望所有的物体,无论它们距离摄像机有多远,都能呈现相同尺寸,即使是在窗口被重新调整大小的时候。 解决这个问题的关键,是一个很重要的公式:给定距离,求可见高度
visible_height = 2 * Math.tan( ( Math.PI / 180 ) * camera.fov / 2 ) * distance_from_camera;
如果我们以一定的百分比增加了窗口的高度,那我们所想要的结果便是所有距离的可见高度都增加相同的百分比。 这并不能通过改变摄像机的位置来实现,相反,你得改变摄像机的视野角度(FOV)。
OrthographicCamera:正交相机,在这种投影模式下,无论物体距离相机距离远或者近,在最终渲染的图片中物体的大小都保持不变.这对于渲染2D场景或者UI元素是非常有用的.
PerspectiveCamera:透视相机,这一投影模式被用来模拟人眼所看到的景象,它是3D场景的渲染中使用得最普遍的投影模式。
StereoCamera:双透视摄像机(立体相机),常用于创建 3D 立体影像,比如3D电影之类或VR.
ArrayCamera:包含着一组子摄像机,常用于多人同屏的渲染,更好地提升VR场景的渲染性能.
CubeCamera:有6个渲染,分别是立方体的6个面,常用于渲染环境、反光等。
Three.js 提供了多种相机控制器(例如 OrbitControls、FlyControls),你可以将其添加到你的相机上,以实现用户控制相机的旋转、缩放和平移,从而导航场景。
在threejs中,常用的渲染器WebGLRenderer。通常情况下使用WebGLRenderer非常简单,我们直接对它进行实例化即可,然后调用其render方法进行渲染:
- const renderer = new THREE.WebGLRenderer()
- renderer.render(scene,camera)
渲染循环是一个持续的循环,用于更新和渲染 Three.js 场景.为了优化性能,可以使用 Frustum Culling、LOD和合并几何体等技术来减少不必要的渲染操作。
Three.js基于WebGL构建,因此它与WebGL紧密集成。可以通过创建WebGLRenderer对象来启用WebGL渲染。此外,可以通过使用Three.js提供的各种实用工具和功能来简化WebGL的使用,如场景管理、光照、材质和动画等。
Raycasting 是用于检测光线与场景中对象的交点的技术。在 Three.js 中,你可以使用 THREE.Raycaster 类来执行 raycasting 操作,以确定鼠标点击的物体或光线与物体的交点。
AABB碰撞检测(Axis-Aligned Bounding Box):这是一种简单但高效的碰撞检测方法。它基于物体的边界框,即用一个最小包围盒(AABB)来表示物体,然后检测这些边界框是否相交。在three.js中,可以使用Box3类来表示边界框,并使用intersectBox方法来检测边界框是否相交。
精确的几何体碰撞检测:如果你需要更精确的碰撞检测,可以使用Three.js提供的几何体类,例如Sphere、BoxGeometry等,并使用它们提供的方法来进行碰撞检测。例如,可以使用intersectsSphere、intersectsBox等方法来检测几何体之间是否发生碰撞。
射线与物体的交点检测:在three.js中,可以使用射线(Raycaster)来进行碰撞检测。射线是由一个起点和一个方向向量组成的,可以通过射线与场景中的物体进行相交检测。通过使用Raycaster类的intersectObject方法,可以获取射线与物体发生碰撞时的交点信息。
无论选择哪种方法,都需要在每一帧中进行碰撞检测,通常在渲染循环中调用碰撞检测函数。当检测到碰撞时,可以根据具体需求进行相应的处理,例如停止物体的运动、改变物体的位置等。
需要注意的是,碰撞检测是一个复杂的问题,具体实现取决于你的场景和需求。以上只是一些常用的方法,你可以根据具体情况选择适合的方法来实现碰撞检测。
创建几何体:你需要创建用于检测碰撞的几何体。这可以是简单的形状,如立方体(BoxGeometry)或球体(SphereGeometry)或者是自定义的几何体。
创建物体:将几何体包装在物体(Mesh)中,同时为物体创建一个材质,以便渲染或进行其他操作。
更新物体位置:在每个渲染循环中,确保更新物体的位置和变换,以反映物体的当前状态。
碰撞检测:执行碰撞检测的关键步骤。这通常涉及两个几何体之间的交叉检测,以确定它们是否相交。以下是一些常见的碰撞检测方法:
边界框碰撞检测:这是最简单的碰撞检测方法,它涉及比较两个物体的边界框(Bounding Boxes)是否相交。你可以使用 Box3 类来表示边界框,并使用 intersectsBox() 方法来检测碰撞。
球体碰撞检测:如果你的物体是球体或包含球体的几何体,你可以使用球体碰撞检测,使用 Sphere 类和 intersectsSphere() 方法。
射线碰撞检测:这是一种更精确的方法,允许你发射射线并检测射线是否与物体相交。你可以使用 Raycaster 类来执行射线碰撞检测。
处理碰撞:一旦检测到碰撞,你可以执行相应的操作,例如停止物体的运动、改变物体的属性等。
阻尼效果可以通过逐渐减少物体的速度来实现。在 Three.js 中,你可以使用线性插值(Lerp)或指数衰减来实现阻尼效果。
Three.js 生态系统有许多有用的拓展库和插件,例如 Cannon.js 用于物理模拟,Tween.js 用于动画。可以根据项目需求来集成这些库。
Three.js 可以与 WebXR API 集成,用于创建虚拟现实和增强现实应用。此外,还有一些第三方库,如 A-Frame,用于更轻松地创建 VR 和 AR 内容。
Three.js 是一款用于创建和展示 3D 图形的 JavaScript 库。它基于 WebGL 技术,提供了封装复杂 WebGL 操作的简洁接口,使开发者可以更轻松地构建跨平台的 3D 应用程序。在使用 Three.js 进行渲染时,遵循下面的流程是非常重要的。
1. 创建场景(Scene)
在开始渲染之前,首先需要创建一个场景,用于存放要渲染的所有物体。场景是 Three.js 中的顶级容器,可以包含多个物体、光源和相机。
2. 创建相机(Camera)
相机定义了我们观察场景的视角。Three.js 提供了多种类型的相机,例如透视相机(PerspectiveCamera)和正交相机(OrthographicCamera)。透视相机模拟了人眼观察物体的效果,而正交相机则没有远近距离的视觉差异,适合展示二维图形。
3. 创建渲染器(Renderer)
渲染器负责将场景和相机的内容渲染到屏幕上。在创建渲染器时,可以设置一些参数,例如渲染目标(canvas 或 WebGLRenderTarget)、渲染分辨率和背景色等。
4. 创建几何体(Geometry)和材质(Material)
几何体是物体的形状,而材质决定了物体的外观。Three.js 提供了多种内置几何体和材质,也支持自定义几何体和材质。可以根据需要选择合适的几何体和材质类型,并配置其属性,例如颜色、纹理和光照等。
5. 创建网格(Mesh)
将几何体和材质结合起来,创建网格对象。网格对象是实际渲染的物体,可以添加到场景中,并在渲染时显示出来。
6. 添加光源(Light)
通过添加光源,可以模拟现实世界中的光照效果。Three.js 提供了多种类型的光源,例如环境光(AmbientLight)、平行光(DirectionalLight)和点光源(PointLight)等。可以根据需要选择合适的光源类型,并配置其属性,例如颜色、强度和位置等。
7. 渲染循环(Render Loop)
渲染循环是整个渲染过程的核心。在每一帧中,渲染器会根据相机的视角计算物体的可见性,并根据光照、阴影和材质等参数对物体进行着色。然后,渲染器将渲染结果显示到屏幕上。
8. 响应用户交互
Three.js 提供了丰富的用户交互功能,例如鼠标控制、键盘控制和触摸控制等。通过监听用户输入事件,并根据用户的操作更新相机和物体的状态,可以实现交互式的 3D 应用程序。
9. 优化性能
在渲染大规模 3D 场景时,性能优化是非常重要的。可以通过降低模型的面数、使用LOD(Level of Detail)技术、合并网格对象和使用着色器程序等方式来提高渲染性能。
通过以上流程,我们可以使用 Three.js 创建并渲染出各种复杂的 3D 场景。无论是创建游戏、可视化应用还是实时交互界面,Three.js 都能提供强大的支持,使开发者能够轻松实现令人惊叹的 3D 效果。希望通过本文的介绍,读者能对 Three.js 渲染流程有更清晰的理解。
three.js是一个用于创建3D图形的JavaScript库,它在实时渲染方面有以下几个应用:
游戏开发:three.js可以用于创建各种类型的游戏,包括动作游戏、角色扮演游戏和射击游戏等。
虚拟现实和增强现实:three.js可以用于创建虚拟现实和增强现实应用程序,使用户可以与3D环境进行交互。
建筑和室内设计:three.js可以用于创建建筑和室内设计的3D模型,使客户可以更好地了解和体验设计。
教育和培训:three.js可以用于创建教育和培训应用程序,使学生和员工可以更好地理解和学习复杂的3D概念。
广告和营销:three.js可以用于创建吸引人的3D广告和营销材料,以吸引潜在客户的注意力。
总之,three.js在实时渲染方面的应用非常广泛,可以用于各种需要创建和展示3D图形的领域。
three.js在游戏开发中可以用于创建和渲染3D游戏场景、模型和角色,可以实现各种特效和交互功能,例如:
游戏场景渲染:使用three.js可以轻松创建复杂的3D游戏场景,包括地形、建筑、道路、天空盒等。
游戏角色动画:three.js可以与动画库结合使用,实现游戏角色的动画效果,例如行走、跳跃、攻击等。
物理引擎集成:three.js可以与物理引擎集成,实现游戏物体的物理效果,例如重力、碰撞检测等。
灯光和阴影:three.js可以模拟各种灯光效果和阴影,提升游戏画面的真实感。
用户交互:three.js可以与游戏引擎结合使用,实现用户与游戏场景和角色的交互功能,例如点击、拖拽等。
总之,three.js在游戏开发中可以提供各种3D渲染和交互功能,提升游戏的视觉效果和用户体验。
three.js在虚拟现实和增强现实中可以用于创建和渲染3D虚拟场景和物体,可以实现各种交互功能和特效,例如:
虚拟现实应用:使用three.js可以创建沉浸式的虚拟现实场景,用户可以通过头戴式显示器等设备进入虚拟场景中,与物体进行交互。
增强现实应用:使用three.js可以将虚拟物体叠加在真实场景中,用户可以通过手机或平板电脑等设备观看增强现实场景。
3D模型展示:使用three.js可以将3D模型放置在真实场景中,用户可以通过手机或平板电脑等设备观看3D模型。
交互功能:使用three.js可以实现用户与虚拟场景和物体的交互功能,例如点击、拖拽、旋转等。
特效和动画:使用three.js可以实现各种特效和动画效果,例如火、水、烟等。
总之,three.js在虚拟现实和增强现实中可以提供各种3D渲染和交互功能,提升虚拟场景和物体的真实感和用户体验。
要实现一个自定义的渲染器(Renderer),可以继承three.js中的Renderer类,并重写其中的一些方法以满足自定义需求。下面是一个简单的示例:
- class CustomRenderer extends THREE.Renderer {
- constructor() {
- super();
- }
- // 重写绘制场景的方法
- render(scene, camera, renderer) {
- // 在绘制场景之前可以做一些自定义的操作
- // ...
-
- // 调用父类的方法绘制场景
- super.render(scene, camera, renderer);
- // 在绘制场景之后可以做一些自定义的操作
- // ...
- }
- // 重写计算渲染大小的方法
- computeVisibility(scene, camera) {
- // 在计算渲染大小之前可以做一些自定义的操作
- // ...
- // 调用父类的方法计算渲染大小
- super.computeVisibility(scene, camera);
- // 在计算渲染大小之后可以做一些自定义的操作
- // ...
- }
- // ... 可以继续重写其他方法以满足自定义需求
- }
在上面的示例中,我们重写了render方法和computeVisibility方法,并在其中添加了自定义的操作。你可以根据自己的需求继续重写其他方法。
注意,在重写方法时,应该尽量保持原有方法的功能,并在自定义操作之前调用原有方法。
使用CSS3DRenderer渲染HTML标签
在three.js中进行粒子效果和粒子系统的渲染可以通过以下步骤实现:
创建一个粒子几何体(PointsGeometry),设置顶点数和顶点坐标。
- const geometry = new THREE.PointsGeometry(
- new THREE.BoxGeometry(1, 1, 1, 10, 10, 10),
- 500
- );
创建一个粒子材质(PointsMaterial),设置颜色和透明度。
- const material = new THREE.PointsMaterial({
- color: 0xffffff,
- transparent: true,
- opacity: 1,
- });
创建一个粒子系统(ParticleSystem)对象,并将几何体和材质进行设置。
const particleSystem = new THREE.Points(geometry, material);
将粒子系统添加到场景中。
scene.add(particleSystem);
在每个帧中更新粒子系统的位置和状态。
- function updateParticle() {
- particleSystem.rotation.y += 0.01;
- for (let i = 0; i < particleSystem.geometry.vertices.length; i++) {
- const particle = particleSystem.geometry.vertices[i];
- // 更新粒子的位置和速度
- particle.x += particleSystem.velocity.x
- particle.y += particleSystem.velocity.y
- particle.z += particleSystem.velocity.z
- }
- particleSystem.geometry.verticesNeedUpdate = true;
- }
- function animate() {
- requestAnimationFrame(animate);
- updateParticle();
- renderer.render(scene, camera);
- }
- animate();
通过以上步骤,可以在three.js中进行粒子效果和粒子系统的渲染。可以通过修改粒子系统的速度、颜色和形状等属性,来实现不同的粒子效果。同时,也可以将粒子系统添加到不同的物体上,来实现不同的粒子效果的交互性和动态性。
卡通渲染是一种图像渲染风格,通常用于模拟卡通或手绘风格的渲染。在 Three.js 中,你可以通过编写自定义的着色器来实现卡通渲染效果,例如通过使用阶梯化的光照来模拟阴影。
Three.js 可以与物理引擎集成,例如Cannon.js 或 Ammo.js。你需要加载物理引擎库,并将模型的物理属性和碰撞体积配置正确。
物体层级是Three.js 中对象的父子关系。通过将一个对象添加为另一个对象的子对象,你可以构建复杂的层次结构,使得对象之间可以继承和共享变换等属性。
Three.js 支持多种纹理映射,包括颜色纹理、法线纹理、置换纹理等。你可以使用 THREE.TextureLoader 类来加载这些纹理,并将它们应用于材质。
Three.js 提供了鼠标和触摸事件监听器,你可以使用它们来捕捉用户的输入,例如点击、拖动和缩放等操作。通过事件处理,你可以实现交互性。
WebGL 渲染流水线是一系列的步骤,用于将三维场景转化为最终的图像。这包括几何处理、光照计算、着色器执行和像素绘制等过程
根据three.js的发展趋势和应用前景,可以预测它有以下几个方向的发展:
更好的跨平台支持:three.js已经在WebGL支持的浏览器上实现了出色的效果,但仍然有一些旧版本的浏览器不支持WebGL。因此,未来的发展方向可能是更好地支持这些浏览器,以使其在更广泛的设备和平台上使用。
更好的性能优化:three.js已经被广泛应用于虚拟现实、增强现实、游戏开发等领域,对性能的要求越来越高。因此,未来的发展方向可能是更好地优化性能,以提供更流畅、更快速的用户体验。
更多的扩展功能:three.js已经提供了许多功能,但仍然存在一些扩展功能的需求,例如更好的物理模拟、更复杂的渲染效果等。因此,未来的发展方向可能是增加更多的扩展功能,以满足不同应用场景的需求。
总之,three.js作为WebGL的三维图形库,具有广泛的应用前景和发展空间,可以预见它将在未来继续得到完善和发展。
合并几何体(Geometry Merge) :如果你有多个相似的物体,可以将它们的几何体合并成一个,以减少渲染调用的数量。这可以通过 BufferGeometry 来实现。
使用纹理集合(Texture Atlas) :将多个小纹理图像合并成一个大的纹理图集,减少纹理切换和内存占用。
减少光源数量:光源是渲染成本较高的因素之一。尽量减少不必要的光源,使用平行光或环境光来模拟光照效果。
使用 LOD(Level of Detail) :LOD 技术根据物体距离相机的远近,加载不同级别的细节模型。这有助于减少物体的多边形数量。
开启硬件加速:确保浏览器启用了硬件加速,以充分利用 GPU 渲染。
使用 Web Workers:将一些计算密集型任务放在 Web Workers 中,以防止阻塞主线程。
使用 Occlusion Culling:当物体被遮挡时,不需要渲染它们。使用视锥体剔除和遮挡剔除技术来提高渲染效率。
纹理压缩:使用纹理压缩格式,如 DXT、ETC 或 PVRTC,以减少纹理内存占用。
移动端优化:在移动设备上,要特别小心性能。使用适当的分辨率、减少光源和阴影,以提高性能。
事件处理的最小化:不要在每一帧都附加事件监听器,只在需要时附加。事件处理可能会引入性能开销。
使用 requestAnimationFrame:使用 requestAnimationFrame 来控制渲染循环,以确保在性能允许的情况下渲染。
使用外部模型格式:如果可能的话,使用 GLTF 格式的模型,因为它是 Three.js 中性能较高的模型格式。
内存管理:当你不再需要物体或纹理时,记得手动释放它们的内存资源,以避免内存泄漏。
渲染器设置:在创建渲染器时,选择合适的渲染器设置,如 antialiasing(抗锯齿)和 shadows(阴影),以平衡性能和图形质量。
使用 GPU 功能:尽量使用 GPU 进行计算,例如使用着色器来执行复杂的渲染操作。
避免频繁的渲染大小变化:频繁改变渲染画布的大小可能会导致性能下降,尽量避免这种情况。
压缩和合并着色器:将着色器代码压缩和合并,以减少 HTTP 请求和提高加载速度。
定期检查性能:使用浏览器的性能分析工具(例如 Chrome 的开发者工具)来检查性能瓶颈,并优化应用。
控制粒子数量:如果你使用粒子系统,确保粒子数量不会过多,以避免性能下降。
测试不同设备:在不同设备和浏览器上测试你的应用,以确保它在各种环境中都能正常运行。
后期处理效果是在渲染场景后应用的图像效果,如模糊、色彩校正等。你可以使用 THREE.EffectComposer 来添加和配置后期处理效果。
three.js在移动设备上的兼容性取决于多个因素,包括设备的硬件性能、操作系统、浏览器和three.js的版本等。
就硬件性能而言,高端移动设备通常具有足够的处理能力和显存来支持three.js的运行,而低端设备可能会出现性能问题。
操作系统和浏览器也会影响three.js的兼容性。iOS和Android操作系统上的不同版本可能会对three.js的某些功能产生影响,而不同浏览器的WebGL支持程度也可能会有所不同。
此外,three.js的版本也会影响其在移动设备上的兼容性。较旧的版本可能存在与移动设备相关的问题,而较新的版本可能已经修复了这些问题。
总的来说,如果使用适当的硬件、操作系统、浏览器和three.js版本,并进行适当的优化,three.js在移动设备上的兼容性可以得到保证。建议在开发过程中进行充分的测试,以确保应用程序在各种移动设备上正常运行。
Three.js 可以与 WebXR API 集成,用于创建虚拟现实和增强现实应用。此外,还有一些第三方库,如 A-Frame,用于更轻松地创建 VR 和 AR 内容。
什么是 LOD(Level of Detail),如何在 Three.js 中使用它?
LOD 是一种用于优化性能的技术,它根据物体距离相机的远近来加载不同级别的细节。在 Three.js 中,你可以使用 THREE.LOD 类来实现 LOD 效果。
Three.js中常见的错误和问题包括内存泄漏、渲染效率低下、着色器错误等。解决这些问题的方法包括合理管理内存、优化渲染流程、正确编写着色器代码等。此外,Three.js社区提供了许多资源和支持,可以通过查阅文档、参与论坛和寻求帮助来解决问题。
以下是一些优秀的基于three.js的开源项目:
A-Frame:一个基于Web组件的框架,用于构建虚拟和增强现实应用程序。
three.jsstdlib:一个用于共享和重用three.js资产和工具的库。
GLTFpack:一个用于压缩GLTF文件的工具。
three.js Demos:一个官方的three.js演示集合,包含各种示例和教程。
three.js Blender Addon:一个用于将Blender模型导出为three.js格式的插件。
three.js Post Processing:一个用于应用后期处理效果的库。
three.js VR Gallery:一个用于创建虚拟现实画廊的库。
three.js Stats.js:一个用于显示游戏统计信息的库。
three.js OrbitControls:一个用于控制相机移动和旋转的库。
three.js loaders.js:一个用于加载各种文件格式的库,包括GLTF,JSON和OBJ等。
这些项目都有活跃的社区和广泛的文档支持,可以帮助你更好地理解和使用three.js。
在使用three.js时,最大的挑战之一是理解和配置WebGL渲染管线。WebGL是一种基于GPU的渲染技术,需要正确设置和配置才能产生高质量的图像。
为了克服这个挑战,我开始研究WebGL的基础知识,包括顶点着色器、片段着色器和缓冲区对象等概念。我还学习了如何在three.js中配置这些对象以及如何编写着色器代码。
此外,我还参考了three.js的官方文档和示例代码,以了解如何使用WebGL渲染管线创建复杂的场景和效果。我还参加了一些在线课程和培训,以加强我的技能和理解。
通过这些努力,我能够更好地理解和配置WebGL渲染管线,并在three.js中创建出更具视觉冲击力和真实感的场景和效果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。