阅读 502

ThreeJs入门37-WebGL视图篇:类似3Dmax的多视图显示

我们上节讲解了多摄像机、多视图、多角度摄影,对于多视图我们还需要了解一些其他的东西。类似于3Dmax的多视图显示又应该如何做呢?我们一起来看下吧。

3Dmax的多视图

  • 如果你有用过3Dmax,那么你对于多视图是会比较熟悉的。看下图

aa18972bd40735faad72ed9e9f510fb30f240812.jpg

  • 在我们的3Dmax软件上显示一个物体,但是我们显示了4个窗口,分别显示了物体的正面、侧面、斜面、透视和实体效果。

  • 我们通过three.js也能实现类似的效果,下面我们就开始吧。

效果展示

  • 我们在场景中添加了3个20面体和对应的阴影。通过设置摄像机不同的位置,来达到类似于3Dmax的效果

image.png

  • 图1:正面看的效果

  • 图2:侧面看的效果

  • 图3:上面看的效果

  • 图4:斜面看的效果

  • 下面讲解的时候会以图1234来进行说明做的是哪一部分的内容

场景渲染方式

  • 我们的渲染方式其实有两种:

    • 这一节我们要讲述的渲染方式

    • 上一节讲述的就是这个渲染方式

    • 多个相机、多个渲染器、单个场景

    • 多个相机、多个渲染器、多个场景

  • 实现方式

    • 通过一个场景,放入3个20面体

    • 把场景添加到4个容器中,这个时候我们不设置摄像机或者设置一个摄像机,4个容器展示效果一样

    • 摆放4个不同位置的摄像机,就可以显示出不同的效果了

静态界面

  • 我们先把html界面布局好

  • 我们准备4个容器,用来布局我们的场景

<div id="container">   <div id="container1"></div>   <div id="container2"></div>   <div id="container3"></div>   <div id="container4"></div> </div> 复制代码

body { color: #808080; font-family: Monospace; font-size: 13px; text-align: center; background-color: #fff; margin: 0px; overflow: hidden; } #container { position: relative; } #container1, #container2, #container3, #container4 { position: absolute; border: 1px solid red; } #container1 { width: 500px; height: 250px; } #container2 { width: 500px; height: 250px; left: 520px; } #container3 { width: 500px; height: 250px; top: 270px; } #container4 { width: 500px; height: 250px; top: 270px; left: 520px; } 复制代码

初始化视图

  • 我们需要初始化4个画布,来放置我们场景中不同摄像机的位置

function initView() {     container1 = document.getElementById("container1");     container2 = document.getElementById("container2");     container3 = document.getElementById("container3");     container4 = document.getElementById("container4"); } 复制代码

初始化场景

  • 我们初始化一个场景,用来放我们的物体、摄像机、灯光等

function initScene() {     scene = new THREE.Scene(); } 复制代码

初始化灯光

  • 初始化一个环境光,添加到场景中

function initLight() {     light = new THREE.DirectionalLight(0xffffff);     light.position.set(0, 0, 1).normalize();     scene.add(light); } 复制代码

初始化摄像机

  • 我们使用的摄像机都是透视投影

  • 设置远近距离

const near = 1 const far = 10000 复制代码

图1摄像机

  • 图1中需要的摄像机,是正对屏幕往里看的效果

camera1 = new THREE.PerspectiveCamera(45, 500 / 250, near, far); camera1.setViewOffset(500, 250, 0, 0, 500, 250) camera1.position.z = 1800 // z轴看向原点,正对屏幕 复制代码

image.png

图2摄像机

  • 图2需要的摄像机,是从侧面看的效果

camera2 = new THREE.PerspectiveCamera(45, 500 / 250, near, far); camera2.setViewOffset(500, 250, 0, 0, 500, 250) camera2.position.x = 1800 // x轴看向原点,从球的侧面往左看 复制代码

  • 类似于在图1中摆放了从右往左看的摄像机

image.png

图3摄像机

  • 图3需要的摄像机,是从上往下看

    • 这里我们调整y的位置时,也需要调整快门的方向,保证快门和y轴平行

camera3 = new THREE.PerspectiveCamera(45, 500 / 250, near, far); camera3.setViewOffset(500, 250, 0, 0, 500, 250) camera3.position.y = 1800 // y轴看向原点,从球的上面往下看 camera3.up.set(0, 0, 1) // 默认为(0,1,0),调整快门的方向,和y轴平行 复制代码

  • 类似于在图1中摆放了一个向下看的摄像机

image.png

图4摄像机

  • 图3需要的摄像机,是从右下角往左上角看

camera4 = new THREE.PerspectiveCamera(45, 500 / 250, near, far); camera4.setViewOffset(500, 250, 0, 0, 500, 250) // 斜着看物体 camera4.position.x = 300 camera4.position.z = 800 复制代码

  • 类似于在图1中摆放了一个向下看的摄像机

image.png

初始化20面几何体

  • 上一节课我们已经实现过了,这一节不做过多介绍,直接看代码

var shadowMaterial; function createShadowByCanvas() {     // 创建画布     var canvas = document.createElement("canvas");     // 设置画布大小宽128,高128     canvas.width = 128;     canvas.height = 128;     // 得到画布的可画类context     var context = canvas.getContext("2d");     // 创建一个放射性渐变,渐变从画布的中心开始,到以canvas.width/2为半径的圆结束。如果不明白可以参考:http://www.w3school.com.cn/htmldom/met_canvasrenderingcontext2d_createradialgradient.asp     var gradient = context.createRadialGradient(         canvas.width / 2,         canvas.height / 2,         0,         canvas.width / 2,         canvas.height / 2,         canvas.width / 2     );     // 在离画布中心canvas.width*0.1的位置添加一种颜色,     gradient.addColorStop(0.1, "rgba(210,210,210,1)");     // 在画布渐变的最后位置添加一种颜色,     gradient.addColorStop(1, "rgba(255,255,255,1)");     // 填充方式就是刚才创建的渐变填充     context.fillStyle = gradient;     // 实际的在画布上绘制渐变。     context.fillRect(0, 0, canvas.width, canvas.height);     // 将画布转为纹理     var shadowTexture = new THREE.CanvasTexture(canvas);     shadowTexture.needsUpdate = true;     // 将纹理添加到材质中     shadowMaterial = new THREE.MeshBasicMaterial({ map: shadowTexture }); } function initShadowPlane() {     // 定义一个宽和高都是300的平面,平面内部没有出现多个网格。     var shadowGeo = new THREE.PlaneGeometry(300, 300, 1, 1);     // 构建一个Mesh网格,位置在(0,-250,0),即y轴下面250的距离。     mesh = new THREE.Mesh(shadowGeo, shadowMaterial);     mesh.position.y = -250;     // 围绕x轴旋转-90度,这样竖着的平面就横着了。阴影是需要横着的。     mesh.rotation.x = -Math.PI / 2;     scene.add(mesh);     // 第二个平面阴影     mesh = new THREE.Mesh(shadowGeo, shadowMaterial);     mesh.position.x = -400;     mesh.position.y = -250;     mesh.rotation.x = -Math.PI / 2;     scene.add(mesh);     // 第三个平面阴影     mesh = new THREE.Mesh(shadowGeo, shadowMaterial);     mesh.position.x = 400;     mesh.position.y = -250;     mesh.rotation.x = -Math.PI / 2;     scene.add(mesh); } // 初始化物体 function initObject() {     // 20面体的半径是200单位     var radius = 200;     // 生成3个20面体     var geometry1 = new THREE.IcosahedronGeometry(radius, 1);     // 由于场景中有3个20面体,所以这里通过clone函数复制3个。clone函数将生产一模一样的一个几何体。     var geometry2 = geometry1.clone();     var geometry3 = geometry1.clone();     var faceIndices = ['a', 'b', 'c', 'd'];     var color, f1, f2, f3, p, n, vertexIndex;       for (var i = 0; i < geometry1.faces.length; i++) {         f1 = geometry1.faces[i];         f2 = geometry2.faces[i];         f3 = geometry3.faces[i];         n = (f1 instanceof THREE.Face3) ? 3 : 4;         for (var j = 0; j < n; j++) {             vertexIndex = f1[faceIndices[j]];             p = geometry1.vertices[vertexIndex];             color = new THREE.Color(0xffffff);             color.setHSL((p.y / radius + 1) / 2, 1.0, 1.0);             f1.vertexColors[j] = color;             color = new THREE.Color(0xffffff);             color.setHSL(0.0, (p.y / radius + 1) / 2, 1.0);             f2.vertexColors[j] = color;             color = new THREE.Color(0xffffff);             color.setHSL(0.125 * vertexIndex / geometry1.vertices.length, 1.0, 1.0);             f3.vertexColors[j] = color;         }     }     var materials = [         new THREE.MeshLambertMaterial({ color: 0xffffff, shading: THREE.FlatShading, vertexColors: THREE.VertexColors }),         new THREE.MeshBasicMaterial({ color: 0x000000, shading: THREE.FlatShading, wireframe: true, transparent: true })     ];     /* --几何体1-- */     group1 = THREE.SceneUtils.createMultiMaterialObject( geometry1, materials );     group1.position.x = -400;     group1.rotation.x = -1.87;     scene.add( group1 );     /* --几何体2-- */     group2 = THREE.SceneUtils.createMultiMaterialObject( geometry2, materials );     group2.position.x = 400;     group2.rotation.x = 0;     scene.add( group2 );     /* --几何体3-- */     group3 = THREE.SceneUtils.createMultiMaterialObject( geometry3, materials );     group3.position.x = 0;     group3.rotation.x = 0;     scene.add( group3 ); } 复制代码

  • 我们上一节是使用r93版本实现的20面几何体,这一节我们使用r73版本实现的几何体,由于r73版本没有IcosahedronBufferGeometry这个方法,所以我们通过IcosahedronGeometry方法来实现。

  • 这里也用到了THREE.SceneUtils.createMultiMaterialObject方法,这个方法可以把多种材质的数组,添加到一个几何体中

初始化渲染器

  • 我们需要4个渲染器,添加到4个容器中

renderer1 = new THREE.WebGLRenderer({ antialias: true }); renderer1.setSize(500, 250); renderer2 = new THREE.WebGLRenderer({ antialias: true }); renderer2.setSize(500, 250); renderer3 = new THREE.WebGLRenderer({ antialias: true }); renderer3.setSize(500, 250); renderer4 = new THREE.WebGLRenderer({ antialias: true }); renderer4.setSize(500, 250); container1.appendChild(renderer1.domElement); container2.appendChild(renderer2.domElement); container3.appendChild(renderer3.domElement); container4.appendChild(renderer4.domElement); 复制代码

  • 如果只使用一个渲染器,四个容器中添加这个渲染器,那么会造成只有最后一个容器添加了这个渲染器,也就是如下效果

image.png

渲染函数

  • 我们需要让4个摄像机都看向场景,不然的话可能摄像机就看不到我们的物体了。

function animation() {     render()     requestAnimationFrame(animation); } function render() {     camera1.lookAt(scene.position)     camera2.lookAt(scene.position)     camera3.lookAt(scene.position)     camera4.lookAt(scene.position)     renderer1.render(scene, camera1)     renderer2.render(scene, camera2)     renderer3.render(scene, camera3)     renderer4.render(scene, camera4) }


作者:张雨凡
链接:https://juejin.cn/post/7069173560073256996


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐