WebGL three.js学习笔记 法向量网格材质MeshNormalMaterial的介绍和创建360度全景天空盒的方法
栏目: JavaScript · 发布时间: 5年前
内容简介:MeshNormalMaterial是一种不受渲染时使用的颜色影响的材质,它只与自己每一个面从内到外的法向量有关。法向量在webgl中用处十分广泛,光的反射,以及三维图形的纹理映射都与这个有关。从图中可以看到,网格的每一面渲染的颜色都是不一样的,如果我们想要在物体表面添加法向量,我们可以使用的THREE.ArrowHelper去表示每一个法向量,它的参数为
WebGL学习----Three.js学习笔记(5)
点击查看demo演示
Demo地址: https://nsytsqdtn.github.io/d...
简单网格材质 MeshNormalMaterial
MeshNormalMaterial是一种不受渲染时使用的颜色影响的材质,它只与自己每一个面从内到外的法向量有关。法向量在webgl中用处十分广泛,光的反射,以及三维图形的纹理映射都与这个有关。
从图中可以看到,网格的每一面渲染的颜色都是不一样的,如果我们想要在物体表面添加法向量,我们可以使用的THREE.ArrowHelper去表示每一个法向量,它的参数为
THREE.ArrowHelper(dir, origin, length, color, headLength, headWidth)
**其中参数的意义为:
dir:方向,默认是法向量
origin:开始的坐标位置
length:辅助线的长度
color:辅助线的颜色
headLength:头部的长度
headWidth:头部的宽度**
对于一个球体,要描述它每一个面的法向量,首先需要对它的每一个面进行遍历,取出这个面上的三个顶点(因为webgl的面都是三角形,所以是三个顶点),通过divideScalar(3)这个函数计算它的中心位置,我们就可以在这个中心位置点上,从内向外引出一个ArrowHelper,来模拟法向量。
for(let i=0;i<sphereGeometry.faces.length;i++){//在每一个面上面循环 let face = sphereGeometry.faces[i];//得到每个面的对象 let centroid = new THREE.Vector3(); //先创建一个vector3对象,要使用这个对象找到每个面的中心 centroid.add(sphereGeometry.vertices[face.a]); // 将这该面的三个顶点的索引传给sphereGeometry.vertices找到其顶点的坐标 //再添加进centroid centroid.add(sphereGeometry.vertices[face.b]); centroid.add(sphereGeometry.vertices[face.c]); centroid.divideScalar(3);//三角形的中心点坐标 let arrow = new THREE.ArrowHelper( face.normal,//face这个面的法向量 centroid, 2, 0xffcc55, 0.5, 0.5);//箭头辅助线,相当于把法向量用箭头表示出来 sphere.add(arrow); }
其中,centroid.add(sphereGeometry.vertices[face.a])这段代码中的sphereGeometry.vertices存有几何体的所有顶点信息,通过[ ]索引可以取得其中的某一个顶点。face.a还有下面的face.b和c都是该面的顶点索引号,表示这个面是由顶点编号为face.a,face.b,face.c的三个顶点所构成的一个三角形(webgl的面都是三角形),然后我们再计算这三个顶点的中心点。
菜单面板的设置
在菜单面板中设置一些MeshNormalmaterial的一些属性,便于去测试这种材质的一些特质
其中:
**this.visible = meshMaterial.visible;//是否可见
this.wireframe = meshMaterial.wireframe;//是否以线框的方式渲染物体 this.wireframeWidth = meshMaterial.wireframeLinewidth;//线框的宽度 this.transparent = meshMaterial.transparent;//是否透明 this.opacity = meshMaterial.opacity;//透明度,需要transparent为true才有效果 this.side = "front";//边的渲染方式,有三种,前面,后面,还有双面 this.selectMesh = "sphere";//当前选择的几何体 this.shading = "smooth";//着色方式,有平面着色和平滑着色,对一个面很平的几何体几乎看不出区别,如正方体**
function initDatGUI() { //设置菜单中需要的参数 controls = new function () { this.rotationSpeed = 0.02; this.visible = meshMaterial.visible;//是否可见 this.wireframe = meshMaterial.wireframe;//是否以线框的方式渲染物体 this.wireframeWidth = meshMaterial.wireframeLinewidth;//线框的宽度 this.transparent = meshMaterial.transparent;//是否透明 this.opacity = meshMaterial.opacity;//透明度,需要transparent为true才有效果 this.side = "front";//边的渲染方式,有三种,前面,后面,还有双面 this.selectMesh = "sphere";//当前选择的几何体 this.shading = "smooth";//着色方式,有平面着色和平滑着色,对一个面很平的几何体几乎看不出区别,如正方体 }; let gui = new dat.GUI(); //将刚刚设置的参数添加到菜单中 let F1 = gui.addFolder("Mesh"); F1.add(controls, "rotationSpeed", 0, 0.1); F1.add(controls, "visible").onChange(function (e) { meshMaterial.visible = e; }); F1.add(controls, "wireframe").onChange(function (e) { meshMaterial.wireframe = e; }); F1.add(controls, "wireframeWidth",0,10).onChange(function (e) { meshMaterial.wireframeWidth = e; }); F1.add(controls, "transparent").onChange(function (e) { meshMaterial.transparent = e; }); F1.add(controls, "opacity",0,1).onChange(function (e) { meshMaterial.opacity = e; }); F1.add(controls, "side",["front","back","double"]).onChange(function (e) { switch (e) { case "front": meshMaterial.side = THREE.FrontSide; break; case "back": meshMaterial.side = THREE.BackSide; break; case "double": meshMaterial.side = THREE.DoubleSide; break; } meshMaterial.needsUpdate = true;//要在程序中让材质更新需要添加这一句话 }); F1.add(controls, "selectMesh",["sphere","cube","plane"]).onChange(function (e) { //先把场景的物体清除,再来添加 scene.remove(cube); scene.remove(sphere); scene.remove(plane); switch (e) { case "sphere": scene.add(sphere); break; case "cube": scene.add(cube); break; case "plane": scene.add(plane); break; } }); F1.add(controls, "shading",["flat","smooth"]).onChange(function (e) { switch (e) { case "flat": meshMaterial.shading = THREE.FlatShading; break; case "smooth": meshMaterial.shading = THREE.SmoothShading; break; } meshMaterial.needsUpdate = true;//要在程序中让材质更新需要添加这一句话 }); }
**注意在程序运行过程中想要改变材质的属性,需要在改完以后,添加一句
meshMaterial.needsUpdate = true,这样才能更新成功。**
360度全景背景
360度全景背景能够让人有身临其境的感觉,所有这里的背景使用了全景背景
如果想要使用全景的背景,就需要6张6个方向的图片来合成一个完整的背景(也可以使用1张6方向的图片),然后把这些贴图赋值给 scene.background
let urls =[ 'image/posx.jpg', 'image/negx.jpg', 'image/posy.jpg', 'image/negy.jpg', 'image/posz.jpg', 'image/negz.jpg' ];//引入6个方向的贴图 let cubeMap = THREE.ImageUtils.loadTextureCube( urls ); scene = new THREE.Scene(); scene.background = cubeMap;
这些图片的需要按照顺序摆放,右左上下后前,否则背景会错乱。
这里给一个全景图片的网站,里面有很多的360度风景图,都是6张类型的,下载下来解压后就可以直接引入
http://www.humus.name/index.p...本例子的完整代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Depth Material Test</title> <script src="../../import/three.js"></script> <script src="../../import/stats.js"></script> <script src="../../import/Setting.js"></script> <script src="../../import/OrbitControls.js"></script> <script src="../../import/dat.gui.min.js"></script> <script src="../../import/SceneUtils.js"></script> <style type="text/css"> div#WebGL-output { border: none; cursor: pointer; width: 100%; height: 850px; background-color: #333333; } </style> </head> <body onload="Start()"> <div id="WebGL-output"></div> <script> let camera, renderer, scene, light; let controller; let controls; let cube, sphere, plane, meshMaterial; function initThree() { //渲染器初始化 renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0x333333); document.getElementById("WebGL-output").appendChild(renderer.domElement);//将渲染添加到div中 //初始化摄像机,这里使用透视投影摄像机 camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 10, 100); camera.position.set(0, 40, 60); camera.up.x = 0;//设置摄像机的上方向为哪个方向,这里定义摄像的上方为Y轴正方向 camera.up.y = 1; camera.up.z = 0; camera.lookAt(0, 0, 0); //初始化场景 let urls =[ 'image/posx.jpg', 'image/negx.jpg', 'image/posy.jpg', 'image/negy.jpg', 'image/posz.jpg', 'image/negz.jpg' ];//引入6个方向的贴图 let cubeMap = THREE.ImageUtils.loadTextureCube( urls ); scene = new THREE.Scene(); scene.background = cubeMap; //相机的移动 controller = new THREE.OrbitControls(camera, renderer.domElement); controller.target = new THREE.Vector3(0, 0, 0); light = new THREE.AmbientLight(0x0c0c0c); scene.add(light); // add spotlight for the shadows light = new THREE.SpotLight(0xffffff); light.position.set(0, 30, 30); scene.add(light); } //初始化菜单面板 function initDatGUI() { //设置菜单中需要的参数 controls = new function () { this.rotationSpeed = 0.02; this.visible = meshMaterial.visible;//是否可见 this.wireframe = meshMaterial.wireframe;//是否以线框的方式渲染物体 this.wireframeWidth = meshMaterial.wireframeLinewidth;//线框的宽度 this.transparent = meshMaterial.transparent;//是否透明 this.opacity = meshMaterial.opacity;//透明度,需要transparent为true才有效果 this.side = "front";//边的渲染方式,有三种,前面,后面,还有双面 this.selectMesh = "sphere";//当前选择的几何体 this.shading = "smooth";//着色方式,有平面着色和平滑着色,对一个面很平的几何体几乎看不出区别,如正方体 }; let gui = new dat.GUI(); //将刚刚设置的参数添加到菜单中 let F1 = gui.addFolder("Mesh"); F1.add(controls, "rotationSpeed", 0, 0.1); F1.add(controls, "visible").onChange(function (e) { meshMaterial.visible = e; }); F1.add(controls, "wireframe").onChange(function (e) { meshMaterial.wireframe = e; }); F1.add(controls, "wireframeWidth",0,10).onChange(function (e) { meshMaterial.wireframeWidth = e; }); F1.add(controls, "transparent").onChange(function (e) { meshMaterial.transparent = e; }); F1.add(controls, "opacity",0,1).onChange(function (e) { meshMaterial.opacity = e; }); F1.add(controls, "side",["front","back","double"]).onChange(function (e) { switch (e) { case "front": meshMaterial.side = THREE.FrontSide; break; case "back": meshMaterial.side = THREE.BackSide; break; case "double": meshMaterial.side = THREE.DoubleSide; break; } meshMaterial.needsUpdate = true;//要在程序中让材质更新需要添加这一句话 }); F1.add(controls, "selectMesh",["sphere","cube","plane"]).onChange(function (e) { //先把场景的物体清除,再来添加 scene.remove(cube); scene.remove(sphere); scene.remove(plane); switch (e) { case "sphere": scene.add(sphere); break; case "cube": scene.add(cube); break; case "plane": scene.add(plane); break; } }); F1.add(controls, "shading",["flat","smooth"]).onChange(function (e) { switch (e) { case "flat": meshMaterial.shading = THREE.FlatShading; break; case "smooth": meshMaterial.shading = THREE.SmoothShading; break; } meshMaterial.needsUpdate = true;//要在程序中让材质更新需要添加这一句话 }); } function initObject() { //创建正方体,球和地面的几何体 let cubeGeometry = new THREE.BoxGeometry(10, 10, 10); let sphereGeometry = new THREE.SphereGeometry(10, 20, 20); let planeGeometry = new THREE.PlaneGeometry(10, 10, 1, 1); //创建一个法向量材质 meshMaterial = new THREE.MeshNormalMaterial(); cube = new THREE.Mesh(cubeGeometry, meshMaterial); sphere = new THREE.Mesh(sphereGeometry, meshMaterial); plane = new THREE.Mesh(planeGeometry, meshMaterial); //把三者的位置统一 cube.position.set(0,0,0); sphere.position = cube.position; plane.position = cube.position; //在球的每一个面上显示一个法向量,方便观测这种法向量材质的渲染方式 for(let i=0;i<sphereGeometry.faces.length;i++){//在每一个面上面循环 let face = sphereGeometry.faces[i];//得到每个面的对象 let centroid = new THREE.Vector3();//先创建一个vector3对象,要使用这个对象找到每个面的中心, centroid.add(sphereGeometry.vertices[face.a]); // 将这该面的三个顶点的索引传给sphereGeom.vertices找到其顶点的坐标,再添加进centroid centroid.add(sphereGeometry.vertices[face.b]); centroid.add(sphereGeometry.vertices[face.c]); centroid.divideScalar(3);//三角形的中心点坐标 let arrow = new THREE.ArrowHelper( face.normal, centroid, 2, 0xffcc55, 0.5, 0.5);//箭头辅助线,相当于把法向量用箭头表示出来 sphere.add(arrow); } scene.add(sphere); } function rotation() { scene.traverse(function (e) { if (e instanceof THREE.Mesh) { e.rotation.y += controls.rotationSpeed; } }) } //渲染函数 function render() { rotation(); stats.update(); renderer.clear(); requestAnimationFrame(render); renderer.render(scene, camera); } //功能函数 function setting() { loadFullScreen(); loadAutoScreen(camera, renderer); loadStats(); } //运行主函数,敲代码的时候老是敲错,所以改了一个名字,叫Start更方便 function Start() { initThree(); initObject(); initDatGUI(); setting(); render(); } </script> </body> </html>
以上所述就是小编给大家介绍的《WebGL three.js学习笔记 法向量网格材质MeshNormalMaterial的介绍和创建360度全景天空盒的方法》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 支持向量机(一):支持向量机的分类思想
- 算法工程师的数学基础:线性代数中的向量和向量空间
- [Grid 网格布局教程]显式网格和隐式网格之间的区别
- 支持向量机:LinearSVM
- 词向量
- PyTorch入门(一)向量
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。