WebGL学习----Three.js学习笔记(5)

点击查看demo演示

Demo地址:https://nsytsqdtn.github.io/demo/360/360

简单网格材质 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.php?page=Textures

本例子的完整代码如下:

<!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度全景天空盒的方法的更多相关文章

  1. WebGL three.js学习笔记 6种类型的纹理介绍及应用

    WebGL three.js学习笔记 6种类型的纹理介绍及应用 本文所使用到的demo演示: 高光贴图Demo演示 反光效果Demo演示(因为是加载的模型,所以速度会慢) (一)普通纹理 计算机图形学 ...

  2. WebGL three.js学习笔记 使用粒子系统模拟时空隧道(虫洞)

    WebGL three.js学习笔记 使用粒子系统模拟时空隧道 本例的运行结果如图: 时空隧道demo演示 Demo地址:https://nsytsqdtn.github.io/demo/sprite ...

  3. WebGL three.js学习笔记 加载外部模型以及Tween.js动画

    WebGL three.js学习笔记 加载外部模型以及Tween.js动画 本文的程序实现了加载外部stl格式的模型,以及学习了如何把加载的模型变为一个粒子系统,并使用Tween.js对该粒子系统进行 ...

  4. WebGL three.js学习笔记 创建three.js代码的基本框架

    WebGL学习----Three.js学习笔记(1) webgl介绍 WebGL是一种3D绘图协议,它把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的 ...

  5. WebGL three.js学习笔记 自定义顶点建立几何体

    自定义顶点建立几何体与克隆 Three.js本身已经有很多的网格模型,基本已经够我们的使用,但是如果我们还是想自己根据顶点坐标来建立几何模型的话,Three.js也是可以的. 基本效果如图: 点击查看 ...

  6. WebGL three.js学习笔记 纹理贴图模拟太阳系运转

    纹理贴图的应用以及实现一个太阳系的自转公转 点击查看demo演示 demo地址:https://nsytsqdtn.github.io/demo/solar/solar three.js中的纹理 纹理 ...

  7. WebGL three.js学习笔记 阴影与实现物体的动画

    实现物体的旋转.跳动以及场景阴影的开启与优化 本程序将创建一个场景,并实现物体的动画效果 运行的结果如图: 完整代码如下: <!DOCTYPE html> <html lang=&q ...

  8. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  9. Vue.js学习笔记(2)vue-router

    vue中vue-router的使用:

随机推荐

  1. Oracle入门《Oracle介绍》第一章1-3 Oracle 逻辑组件

    一.数据库的逻辑结构是从逻辑的角度分析数据库的组成.Oracle 的逻辑组件包括: 1.表空间 表空间是数据库中最大的逻辑单位,一个 Oracle 数据库至少包含一个表空间,就是名为SYSTEM的系统 ...

  2. 基于DP的LCS(最长公共子序列)问题

    最长公共子序列,即给出两个序列,给出最长的公共序列,例如: 序列1 understand 序列2 underground 最长公共序列undernd,长度为7 一般这类问题很适合使用动态规划,其动态规 ...

  3. c语言,数据结构,链表的一些操作总结

    下面是自己的一些学习操作以及总结,能用我会很开心,有不足之处,欢迎大家提出宝贵的意见! c语言链表是一种基本的数据结构,与顺序表一样属于线性表,但是顺序表在内存中的存储单元是连续的,这样就对内存的要求 ...

  4. Struts标签库详解【3】

    struts2标签库详解 要在jsp中使用Struts2的标志,先要指明标志的引入.通过jsp的代码的顶部加入以下的代码: <%@taglib prefix="s" uri= ...

  5. eclipse换了高版本的maven插件后报错:org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.project

    在给eclipse换了高版本的maven插件后,引入jar包报如下的错误:  org.apache.maven.archiver.MavenArchiver.getManifest(org.apach ...

  6. (一)linux定时任务的设置 crontab 基础实践

    为当前用户创建cron服务 1.  键入 crontab  -e 编辑crontab服务文件 例如 文件内容如下: */2 * * * * /bin/sh /home/admin/jiaoben/bu ...

  7. shell 中各种括号的作用()、(())、[]、[[]]、{}

    一.小括号,圆括号 () 1.单小括号 () 命令组.括号中的命令将会新开一个子shell顺序执行,所以括号中的变量不能够被脚本余下的部分使用.括号中多个命令之间用分号隔开,最后一个命令可以没有分号, ...

  8. 'version' contains an expression but should be a constant

    [WARNING] Some problems were encountered while building the effective model for com.app:cache:jar:4. ...

  9. Oauth2.0 用Spring-security-oauth2

    客户端通过appId,redirectUrl,在open platform打开的页面上填写正确的用户名和密码后,open platform验证通过后,会跳转到redirectUrl,此时的redire ...

  10. 优雅地实现CSS Animation delay心得

    话不多说直接开讲: 1.需求: 等待元素A的动画加载完,再加载B元素的动画(下图中A为大熊猫,B为下方卡片) 先来看下最后的效果啦: 2.初始思路: 在B元素的动画属性上加上delay(延迟,使得这个 ...