初识three.js

Three.js是一款webGL框架,由于其易用性被广泛应用。Three.js在WebGL的api接口基础上,又进行的一层封装,所以不用担心他得性能,和主机游戏一样都是支持硬件加速的。它是由居住在西班牙巴塞罗那的程序员Ricardo Cabbello Miguel(https://ricardocabello.com/) 开发的,Three.js以简单、直观的方式封装了3D图形编程中常用的对象。Three.js在开发中使用了很多图形引擎的高级技巧,极大地提高了性能。Three.js还是完全开源的。
里面有很多图形学的概念,比如坐标变换,光照计算,同样可以创建自己的Shader,调用底层的图形接口,框架具有相当高的灵活性。

Webgl和Three.js的关系

Webgl和Three.js的关系,相当于JavaScript和Jquery的关系

创建一个场景

为了真正能够让你的场景借助three.js来进行显示,我们需要以下几个对象:场景、相机和渲染器,这样我们就能透过摄像机渲染出场景。

//创建场景
 const scene = new THREE.Scene();
 //创建一个立方体
 const geometry = new THREE.BoxGeometry( 1, 1, 1 );    //几何形状
 const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); //材质
 const cube = new THREE.Mesh( geometry, material );
 scene.add( cube );

scene以树结构存放所有可见的和不可见的三维物体,包括光源等等


image.png
 //创建一个摄像机
 const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
 camera.position.z = 5;

摄像机决定了我们从什么位置,什么角度观察三维物体

const renderer = new THREE.WebGLRenderer();
 renderer.setSize( window.innerWidth, window.innerHeight );
 document.body.appendChild( renderer.domElement );

渲染器负责将我们的看到的场景树渲染成二维图像

const animate = ()=> {
   requestAnimationFrame( animate );
   //因为JavaScript是单线程的,所以用requestAnimationFrame来请求浏览器定时回调这里的这个animate()
   cube.rotation.x += 0.01;
   cube.rotation.y += 0.01;
   renderer.render( scene, camera );
   //在循环中调用renderer的render()函数来渲染每一帧图像
 }
 animate();

三角网Mesh

立方体是用Mesh(三角网)表示的


image.png

因为三角形的三个点可以空间中唯一地确定一个平面,所以也是最常见的用于表示三维物体的一种方式

Geometry

Geometry代表几何形状,由下面的一个个三角形和构成他们的所有顶点组成


image.png

three.js里内置了很多几何形状

http://www.webgl3d.cn/threejs/docs/#api/zh/geometries/CircleGeometry
    //创建场景
    const scene = new THREE.Scene();
    var geometry = new THREE.CircleBufferGeometry( 5, 32 );
    var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
    var circle = new THREE.Mesh( geometry, material );
    scene.add( circle );
    //创建一个摄像机
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.z = 50;
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    const animate = () => {
        requestAnimationFrame(animate);
        circle.rotation.x += 0.01;
        circle.rotation.y += 0.01;
        renderer.render(scene, camera);
    }
    animate();

Material

Material代表三维物体几何材质,不同的材质在光照下会呈现不一样的效果,通过材质可以给物体表面设定不同的颜色,光泽度,或者给物体加上贴图


1632492310(1).png

基础网格材质(MeshBasicMaterial) 不参与光照计算,不会产生阴影,使用这种材质三维物体看上不去很不真实。

要想有光照效果可以使用下面的两种材质:

  • Phong网格材质(MeshPhongMaterial)
  • Lambert网格材质(MeshLambertMaterial)
    可以用shininess属性来调节物体表面光泽度
    也可以使用map添加贴图
    const material = new THREE.MeshBasicMaterial({ 
        map:new THREE.TextureLoader().load('1.png'),
    }); //材质

MeshStandardMaterialMeshPhysicalMaterial类是PBR物理材质,可以更好的模拟光照计算,相比较高光网格材质MeshPhongMaterial渲染效果更逼真。

emissive默认黑色,设置为白色 发光颜色

emissiveMap 自发光贴图

roughnessMap 粗糙度贴图 设定表面不同位置的粗糙程度

normalMap 法线贴图 给每个像素点设置不同的法向量 法线会影响光照的计算 可以用它模拟物体表面凹凸不平的效果

displacementMap 高度贴图 它会上下偏移物体表面的顶点坐标,从而做到真正的物体表面的起伏

aoMap 环境光遮罩贴图 他会让被遮蔽的区域看起来更暗,进一步提升场景的真实感

    //创建场景
    const scene = new THREE.Scene();
    var geometry = new THREE.SphereBufferGeometry( 5, 32, 32 );
    var texLoader = new THREE.TextureLoader()
    const material = new THREE.MeshPhongMaterial({ 
        emissive:0xffffff,
        // // 发光贴图
        emissiveMap: texLoader.load("wenli.png"),
        // 法线贴图
        normalMap: texLoader.load("faxian.png"),
        // 粗糙度贴图
        roughnessMap: texLoader.load("cucao.png"),
        // //高度贴图
        displacementMap:texLoader.load("weiyi.png"),
        //光罩贴图,会让深坑得地方更暗,更有真实感
        aoMap:texLoader.load("aoMap.png"),
    }); //材质
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    //创建一个摄像机
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.z = 17;
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    const animate = () => {
        requestAnimationFrame(animate);
        //因为JavaScript是单线程的,所以用requestAnimationFrame来请求浏览器定时回调这里的这个animate()
        cube.rotation.x += 0.01;
        cube.rotation.y += 0.01;
        renderer.render(scene, camera);
        //在循环中调用renderer的render()函数来渲染每一帧图像
    }
    animate();

几何转换

创建Mesh之后,我们可以通过position修改几何物体在空间的位置

    const material = new THREE.MeshPhongMaterial({ 
        emissive:0xffffff,
        // // 发光贴图
        emissiveMap: texLoader.load("wenli.png"),
        // 法线贴图
        normalMap: texLoader.load("faxian.png"),
        // 粗糙度贴图
        roughnessMap: texLoader.load("cucao.png"),
        // //高度贴图
        displacementMap:texLoader.load("weiyi.png"),
        //光罩贴图,会让深坑得地方更暗,更有真实感
        aoMap:texLoader.load("aoMap.png"),
    }); //材质
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    cube.position.set(4,0,0)

scale用来转换物体的大小 rotation旋转物体

       const material = new THREE.MeshPhongMaterial({ 
        emissive:0xffffff,
        // // 发光贴图
        emissiveMap: texLoader.load("wenli.png"),
        // 法线贴图
        normalMap: texLoader.load("faxian.png"),
        // 粗糙度贴图
        roughnessMap: texLoader.load("cucao.png"),
        // //高度贴图
        displacementMap:texLoader.load("weiyi.png"),
        //光罩贴图,会让深坑得地方更暗,更有真实感
        aoMap:texLoader.load("aoMap.png"),
    }); //材质
    const cube = new THREE.Mesh(geometry, material);
    scene.add(cube);
    cube.scale.multiplyScalar(2)

摄像机

摄像机决定了我们应当从什么角度观察这个三维场景

three.js中提供了两种不同类型的摄像机

PerspectiveCamera

PerspectiveCamera和我们人眼成像原理类似,看到的物体呈远小近大的透视效果。


1632492626(1).png

创建相机的时候先创建视锥


1632492654(1).png

在渲染的时候,计算机会将视锥中的所有三维物体投影到二维屏幕上
1632492676(1).png
    const camera = new THREE.PerspectiveCamera(
        75, //fov  代表垂直方向上视角的大小
        window.innerWidth / window.innerHeight, //aspect ratio 代表投影平面的纵宽比
        0.1, //near  代表相机能看到的最近的平面
        1000 //far   代表相机能看到的最远的平面,超出这个平面的场景会被自动裁剪掉
    );

OrthographicCamera

OrthographicCamera正交投影相机,会将空间中的所有物体平行投影到投影面上,所以不会呈现近大远小的效果


1632492729(1).png

一般应用在像CAD这种需要精确测量物体尺寸的应用场景中


1632492749(1).png

比如用正交投影可以轻易的渲染出物体的三视图等等

正交相机的视锥(Frustum)是一个长方体,所以定义正交相机要先定义前后左右上下这6个面的位置

    const camera = new THREE.OrthographicCamera(
        -2,//left 
        2,//right 
        1.5,//top
        -1.5,//bottom
        1,//near
        10 //far
    );

一样使用position属性修改相机的位置

//三种修改position的方法
camera.position.set(0,1,5)
camera.position.y += 2
camera.translateZ(2)

camera.updateMatrix()
//更新相机的变换矩阵

参考资料
1.奇乐编程
2.http://www.yanhuangxueyuan.com/threejs/docs/index.html#manual/zh/introduction/Creating-a-scene

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • What is Three.js 什么是threejs,很简单,你将它理解成three + js就可以了。thre...
    依依玖玥阅读 1,613评论 0 2
  • Threejs 为什么? webGL太难用,太复杂! 但是现代浏览器都支持 WebGL 这样我们就不必使用 Fla...
    强某某阅读 6,276评论 1 21
  • Three.js 1.Three.js 介绍 OpenGL(英语:Open Graphics Library,译名...
    GuitarHusky阅读 2,610评论 0 1
  • three之前的准备 three.js是webGL的一个高级工具集,webGL则是从openGL ES 发展而来的...
    琙灵阅读 1,711评论 0 2
  • Threejs中文文档 郭隆邦技术博客 2018-09-21 20:40:17 关注 Three.js中文文档 今...
    情人波阅读 14,204评论 0 7