• Three.js开发指南---使用three.js的材质(第四章)


    材质就像物体的皮肤,决定了几何体的外表,例如是否像草地/金属,是否透明,是否显示线框等

    一 材质

      THREE.js的材质分为多种,Three.js提供了一个材质基类THREE.Material,

      该基类拥有three.js所有材质的公有属性,分为三类:基础属性,融合属性,高级属性

      基础属性:ID,name,透明度,是否可见,是否需要刷新等

      融合属性:决定了物体如何与背景融合

      高级属性:可以控制WEBGL上下文渲染物体的方法,大多数情况下,是不会用这些属性,我们这里不再讨论

       1.1 基础属性

    属性 描述
    ID(描述符) 用来标识材质,在创建时赋值
    name(名称) 通过该属性克赋予该材质名称
    opacity(透明度) 定义物体有多透明,与transparent属性一起使用
    transparent(是否透明) 设置为true时,会根据opacity的值来设置透明度,设置为false时,则只着色
    overdraw(过度描绘) 当使用THREE.CanvasRenderer画布渲染器绘制对象的时候,物体之间可能会有空隙,这时设置该值为true,多边形会被渲染的稍微大一点,
    visible(是否可见) 定义该材质是否可见
    side(侧面)

    决定了几何体的哪一面应用该材质,

    THREE.FrontSide应用到几何体的前(外)面;

    THREE.BackSide应用到几何体的后(内)面;

    THREE.DoubleSide应用到几何体的内外两侧

    needUpdate(是否刷新) 设置该值为true后,如果材质发生改变,就会使用新的材质刷新它的缓存

      

      1.2 融合属性

    属性 描述  
    blending(融合) 决定物体上的材质如何跟背景融合,一般是NormalBlending,这种模式一般只显示材质的上层  
    blendsrc(融合源)

    通过指定融合源,融合目标来指定源如何跟目标融合以及融合时如何使用目标,以达到创建自定义的融合模式

    融合源的默认值SrcAlphaFactor:使用alpha透明度通道进行融合

    融合目标的默认值OneMinusSrcAlphaFactor:融合目标也使用融合源的alpha通道进行融合

    blendingequation只读blendsrc和blenddst的值的叠加方式创建自定义的融合方式

     
    blenddst(融合目标)  
    blendingequation(融合公式)  

      1.3 基础材质(MeshBasicMaterial)

         MeshBasicMaterial是一种简单的材质,这种材质不考虑光照的影响。

        使用这种材质的网格会被渲染成一些简单的平面多边形,而且可以通过设置wireframe的值会显示几何体的线框

    属性 描述
    color 设置材质的颜色
    wireframe 是否将材质渲染成线框
    wireframeLinewidth 如果设置了wireframe的值,则该属性则设置了线框的宽度,即线框的宽度
    wireframeLinecap(线框的端点)

    该属性定义了线框模式下端点的显示方式,有butt平,round圆,square方,

    但是在实际的应用中,该值很难看出效果,而且webglrenderer不支持该属性

    wireframeLinejoin(线框线段连接点)  定义线段的连接点如何显示,webglrenderer不支持该属性
     shading(着色方式)

     THREE.SmoothShading平滑着色,和THREE.FlatShading平面着色,

    平面着色的话,每个面是什么颜色就会被渲染成什么颜色,

    而平滑着色的话可以使物体的表面看起来变的更光滑一些

     vertexColors(顶点颜色) 可以通过该属性为每一个顶点定义不同的颜色,但是canvasRenderer不支持
     fog(雾化) 当前材质是否会受全局雾化效果的影响
    side(面)

    该属性可以指定几何体的哪个面应用了材质,

    由于材质多应用于物体前面的面上,

    所以当旋转的时候,会有一部分时间是不可见的(其实是物体背面没有应用材质)

    side属性的值有front(只有物体的前面应用材质)和double(前后都应用材质)

     

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>1</title>
        <script type="text/javascript" src="three.js"></script>
        <script type="text/javascript" src="dat.gui.js"></script>
        <script type="text/javascript" src="CanvasRenderer.js"></script>
        <script type="text/javascript" src="Projector.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    //var scene
        function init() {
            //生成一个场景
            var scene=new THREE.Scene();
            
            
            //生成一个相机
            //参数:视场,长宽比,近面,远面
            var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);
            camera.position.x=-20;
            camera.position.y=40;
            camera.position.z=30;
            camera.lookAt(scene.position);
            scene.add(camera);
            
            var render;
            
            //生成一个webgl的渲染器
            var webGLrender=new THREE.WebGLRenderer();
            webGLrender.setClearColor(0xEEEEEE);
            webGLrender.setSize(window.innerWidth,window.innerHeight);
            webGLrender.shadowMapEnabled=true;
            //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影        
            render=webGLrender;
            
            //生成一个canvas的渲染器,渲染器有什么不同?
            var canvasRender=new THREE.CanvasRenderer();
            canvasRender.setSize(window.innerWidth,window.innerHeight);
            //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影        
            //scene.add(canvasRender);
            
            
            //生成基本材质,并将该材质应用于下面中的球体,方块或者平面
            var material=new THREE.MeshBasicMaterial({color: 0x77777ff});
            
            material.needsUpdate=true;
            
            //生成一个地面平面,并添加到场景中
            //参数:长,宽,长分为多少份,宽分为多少份
            var groundGeometry = new THREE.PlaneGeometry(100, 200, 20, 20);
            var groundMaterial = new THREE.MeshBasicMaterial({color: 0x777777});
            var ground = new THREE.Mesh(groundGeometry, groundMaterial);
            ground.receiveShadow = true;
            ground.rotation.x = -0.5 * Math.PI;
            scene.add(ground);
            
            //生成一个方块,并添加到场景中
            var cubeGeometry=new THREE.BoxGeometry(10,10,10);
            var cube=new THREE.Mesh(cubeGeometry,material);
            cube.castShadow=true;
            cube.position.set(0,3,2);
            scene.add(cube);
            
            //生成一个圆球,暂时不添加到场景,使用图形界面选择物体        
            var sphereGeometry=new THREE.SphereGeometry(10,10,10);
            var sphere=new THREE.Mesh(sphereGeometry,material);
            sphere.castShadow=true;
            sphere.position.set(0,3,2);
            //scene.add(sphere);
            //生成一个平面,暂时不添加到场景,使用图形界面选择物体        
            var planeGeometry=new THREE.PlaneGeometry(10,10,10);
            var plane=new THREE.Mesh(planeGeometry,material);
            plane.position.set(0,3,2);
            
            //生成环境光,弱化阴影
            var ambientLight = new THREE.AmbientLight(0x0c0c0c);
            scene.add(ambientLight);
            
            
            //生成聚光灯
            var spotLight0 = new THREE.SpotLight(0xffffff);
            spotLight0.position.set(-40, 60, -10);
            spotLight0.castShadow=true;
            scene.add(spotLight0);
            
            //增加图形控制界面
            var controls=new function(){
                this.rotationSpeed=0.02;
                this.opacity=material.opacity;//透明度
                this.transparent=material.transparent;
                this.visible=material.visible;
                
                this.wireframe=material.wireframe;
                this.shading=material.shading;
                this.wireframeLineWidth=material.wireframeLineWidth;
                this.selectedMesh = "矩形";
                this.switchRender=function(){
                    if(render instanceof THREE.WebGLRenderer){
                        render=canvasRender;
                    }else{
                        render=webGLrender;
                    }
                    document.getElementById("WebGL-output").innerHTML='';
                    document.getElementById("WebGL-output").appendChild(render.domElement);
                }
                this.color=material.color.getStyle();
            };
            
            var gui=new dat.GUI();
            //上面controls里面的opacity必须与下面的一致
            var childGui=gui.addFolder("材质的共有属性");
            childGui.add(controls,"opacity",0,1).onChange(function(e){
                material.opacity=e;
            });
            //注意,当opacity设置的值不为1时,以opacity为主
            childGui.add(controls,"transparent").onChange(function(e){
                material.transparent=e;
            });
            childGui.add(controls,"wireframe").onChange(function(e){
                material.wireframe=e;
            });
            //如果visible的值为false,即不可见,不管opacity的值为多少,物体都是不可见的
            childGui.add(controls,"visible").onChange(function(e){
                material.visible=e;
            });
            //addColor注意,增加颜色的图形控制,需要使用addColor方法
            childGui.addColor(controls,"color").onChange(function(e){
                
                material.color.setStyle(e);
            });
            childGui.add(controls,"selectedMesh",["cube","sphere","plane"]).onChange(function(e){
                scene.remove(plane);
                scene.remove(cube);
                scene.remove(sphere);
                switch(e){
                    case 'cube':
                        scene.add(cube);
                    break;
                    case 'sphere':
                        scene.add(sphere);
                    break;
                    case 'plane':
                        scene.add(plane);
                    break;
                }
            });
            
            //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数
            //即controls的this.switchRender必须与下面的属性一致,即上面代码的switchRender必须与下面语句的switchRender保持一致
            gui.add(controls, 'switchRender');
            document.getElementById("WebGL-output").append(render.domElement);
            
            function renderScene(){
                
                requestAnimationFrame(renderScene);
                render.render(scene, camera);
            }
            //scene.fog=new THREE.Fog(0xffffff,0.015,100);
            renderScene();
        }
        
        window.onload = init;
    
    </script>
    </body>
    </html>

      1.4 基于深度着色的材质------MeshDepthMaterial

        该种材质的外观不是由光照或者材质属性visible决定的,而是物体和相机的距离决定,

        因此使用这种材质很容易创建出逐渐消失的效果

        注意这个demo使用了场景的overrideMaterial属性

     

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>1</title>
        <script type="text/javascript" src="three.js"></script>
        <script type="text/javascript" src="dat.gui.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    //var scene
        function init() {
            //生成一个场景
            var scene=new THREE.Scene();
            
            //这里我们使用场景的overrideMaterial属性,即场景中的所有物体都应用这一种材质
            scene.overrideMaterial = new THREE.MeshDepthMaterial();
    
            
            //生成一个相机
            //参数:视场,长宽比,近面,远面
            var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100);
            camera.position.x=-50;
            camera.position.y=40;
            camera.position.z=50;
            camera.lookAt(scene.position);
            scene.add(camera);
            
            var render;
            
            //生成一个webgl的渲染器
            var webGLrender=new THREE.WebGLRenderer();
            webGLrender.setClearColor(0xEEEEEE);
            webGLrender.setSize(window.innerWidth,window.innerHeight);
            webGLrender.shadowMapEnabled=true;
            //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影        
            render=webGLrender;
            
            
        
            //生成一个方块,并添加到场景中
            var cubeGeometry=new THREE.BoxGeometry(10,10,10);
            var cube=new THREE.Mesh(cubeGeometry,new THREE.MeshLambertMaterial({"color":0xeeeeee}));
            cube.castShadow=true;
            cube.position.set(0,3,2);
            scene.add(cube);
            
            
            
            //增加图形控制界面
            var controls=new function(){
                this.cameraNear=camera.near;
                this.cameraFar=camera.far;
                this.rotationSpeed=0.02;
                this.addCube=function(){
                    var size=Math.random()*3+3;
                    var cubeGeo=new THREE.BoxGeometry(4,4,10,10);
                    var cube=new THREE.Mesh(cubeGeo,new THREE.MeshLambertMaterial({color:Math.random()*0xffffff}));
                    cube.castShadow=true;
                    cube.position.x = -60 + Math.round((Math.random() * 100));
                    cube.position.y = Math.round((Math.random() * 10));
                    cube.position.z = -100 + Math.round((Math.random() * 150));
                    scene.add(cube);
                }
                
            };
            
            var gui=new dat.GUI();
            gui.add(controls,"cameraNear",0,50).onChange(function(e){
                camera.near=e;
            });
            gui.add(controls,"cameraFar",0,50).onChange(function(e){
                camera.far=e;
            });
            gui.add(controls,"rotationSpeed",0,0.3);
            gui.add(controls, 'addCube');
            
            for(var i=0;i<10;i++){
                controls.addCube();
            }
            
            //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数
            //即controls的this.switchRender必须与下面的属性一致
            
            document.getElementById("WebGL-output").append(render.domElement);
            
            
            
            
            function renderScene(){
                scene.traverse(function(e){
                    if(e instanceof THREE.Mesh){
                        e.rotation.x+=controls.rotationSpeed;
                        e.rotation.y+=controls.rotationSpeed;
                        e.rotation.z+=controls.rotationSpeed;
                    }
                });
                requestAnimationFrame(renderScene);
                render.render(scene, camera);
            }
            //scene.fog=new THREE.Fog(0xffffff,0.015,100);
            renderScene();
        }
        
        window.onload = init;
    
    </script>
    </body>
    </html>

      1.5 联合材质

        当一个几何体应用多种材质的时候,使用的就不是THREE.Mesh来创建网格了,

        而是THREE.SceneUtil.createMultiMaterialObject方法

        另外需要注意的细节,我们需要把MeshBasicMaterial材质的transparent值设置为true,

        只有材质的transparent的值为true,three.js才会检查该材质的blending属性,进行融合操作

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>1</title>
        <script type="text/javascript" src="three.js"></script>
        <script type="text/javascript" src="dat.gui.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    //var scene
        function init() {
            //生成一个场景
            var scene=new THREE.Scene();
            
            //生成一个相机
            //参数:视场,长宽比,近面,远面
            var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100);
            camera.position.x=-50;
            camera.position.y=40;
            camera.position.z=50;
            camera.lookAt(scene.position);
            scene.add(camera);
            
            var render;
            
            //生成一个webgl的渲染器
            var webGLrender=new THREE.WebGLRenderer();
            webGLrender.setClearColor(0xEEEEEE);
            webGLrender.setSize(window.innerWidth,window.innerHeight);
            webGLrender.shadowMapEnabled=true;
            //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影        
            render=webGLrender;
            
            
            //增加图形控制界面
            var controls=new function(){
                this.cameraNear=camera.near;
                this.cameraFar=camera.far;
                this.rotationSpeed=0.02;
                this.addCube=function(){
                    var size=Math.random()*3+3;
                    var cubeGeo=new THREE.BoxGeometry(4,4,10,10);
                    var basicMaterial=new THREE.MeshBasicMaterial({
                        color: 0x00ff00,
                        transparent: true,//注意这里一定要设置基础材质的透明度为true
                        blending: THREE.MultiplyBlending
                        //这里的融合方式选择的是MultiplyBlending
                        //即最终展示的颜色是前景颜色和背景的颜色相乘后得到的
                    });
                    var depthMaterial=new THREE.MeshDepthMaterial();
                    var cube=new THREE.SceneUtils.createMultiMaterialObject(cubeGeo,[basicMaterial,depthMaterial]);
                    
                    //cube.children[1].scale.set(0.99,0.99,0.99);
                    cube.castShadow=true;
                    cube.position.x = -60 + Math.round((Math.random() * 100));
                    cube.position.y = Math.round((Math.random() * 10));
                    cube.position.z = -100 + Math.round((Math.random() * 150));
                    scene.add(cube);
                }
                
            };
            
            var gui=new dat.GUI();
            gui.add(controls,"cameraNear",0,50).onChange(function(e){
                camera.near=e;
            });
            gui.add(controls,"cameraFar",0,50).onChange(function(e){
                camera.far=e;
            });
            gui.add(controls,"rotationSpeed",0,0.3);
            gui.add(controls, 'addCube');
            
            for(var i=0;i<10;i++){
                controls.addCube();
            }
            
          
            document.getElementById("WebGL-output").append(render.domElement);
            
            
            
            
            function renderScene(){
                scene.traverse(function(e){
                    if(e instanceof THREE.Mesh){
                        e.rotation.x+=controls.rotationSpeed;
                        e.rotation.y+=controls.rotationSpeed;
                        e.rotation.z+=controls.rotationSpeed;
                    }
                });
                requestAnimationFrame(renderScene);
                render.render(scene, camera);
            }
            //scene.fog=new THREE.Fog(0xffffff,0.015,100);
            renderScene();
        }
        
        window.onload = init;
    
    </script>
    </body>
    </html>

      1.6 计算法向量颜色的材质------MeshNormalMaterial

        将该材质应用到几何体对象的时候,几何体对象的每一面的颜色都是从该面向外的法向量计算得到的

        法向量决定了光反射的方向,在三维物体上映射材质时起辅助作用,还可以在计算光照,阴影时提供信息,为物体表面的像素上色

        法向量所指的方向决定每个面从MeshNormalMaterial材质获取的颜色

       //圆球每个面的法向量都不同我可以理解,但是法向量如何与颜色相联系在一起,没有搞明白

         下面的demo,设置transparent为true,opacity为0.5,我们不仅可以看到计算法向颜色的材质,还可以看到材质共有的属性side的值front,back,both的效果

     

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>1</title>
        <script type="text/javascript" src="three.js"></script>
        <script type="text/javascript" src="dat.gui.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    //var scene
        function init() {
            //生成一个场景
            var scene=new THREE.Scene();
            
            //生成一个相机
            //参数:视场,长宽比,近面,远面
            var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100);
            camera.position.x=-50;
            camera.position.y=40;
            camera.position.z=50;
            camera.lookAt(scene.position);
            scene.add(camera);
            
            var render;
            
            //生成一个webgl的渲染器
            var webGLrender=new THREE.WebGLRenderer();
            webGLrender.setClearColor(0xEEEEEE);
            webGLrender.setSize(window.innerWidth,window.innerHeight);
            webGLrender.shadowMapEnabled=true;
            //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影        
            render=webGLrender;
            
             var ambientLight = new THREE.AmbientLight(0x0c0c0c);
            scene.add(ambientLight);
    
            // add spotlight for the shadows
            var spotLight = new THREE.SpotLight(0xffffff);
            spotLight.position.set(-40, 60, -10);
            spotLight.castShadow = true;
            scene.add(spotLight);
            
            var sphereGeometry = new THREE.SphereGeometry(14, 20, 20);        
            var meshMaterial = new THREE.MeshNormalMaterial({color: 0x7777ff});
            var sphere = new THREE.Mesh(sphereGeometry, meshMaterial);
             sphere.position.x = 0;
            sphere.position.y = 3;
            sphere.position.z = 2;
            for (var f = 0, fl = sphere.geometry.faces.length; f < fl; f++) {
                var face = sphere.geometry.faces[f];
                f==0?console.log(face)&&console.log(sphere.geometry.vertices[face.a]):"";
                var centroid = new THREE.Vector3(0, 0, 0);
                centroid.add(sphere.geometry.vertices[face.a]);
                centroid.add(sphere.geometry.vertices[face.b]);
                centroid.add(sphere.geometry.vertices[face.c]);
                centroid.divideScalar(3);//这个函数没有看明白是做什么的
    
                var arrow = new THREE.ArrowHelper(
                        face.normal,//面的法向量
                        centroid,//该面的质心
                        2,
                        0x3333FF,//颜色
                        0.5,
                        0.5);
                sphere.add(arrow);
            }
            
            scene.add(sphere);
            
            
            //增加图形控制界面
            var controls=new function(){
                this.opacity=1;
                this.transparent=false;
                this.rotationSpeed=0.02;
                this.side="front";
                
            };
            
            var gui=new dat.GUI();
            gui.add(controls,"opacity",0,1).onChange(function(e){
                meshMaterial.opacity=e;
            });
            gui.add(controls,"transparent").onChange(function (e) {
                meshMaterial.transparent = e
            });
            gui.add(controls,"rotationSpeed",0,0.3);
            gui.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;
                }
                
            });
            
            //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数
            //即controls的this.switchRender必须与下面的属性一致
            
            document.getElementById("WebGL-output").append(render.domElement);
            
            
            
            
            function renderScene(){
                scene.traverse(function(e){
                    if(e instanceof THREE.Mesh){
                        e.rotation.x+=controls.rotationSpeed;
                        e.rotation.y+=controls.rotationSpeed;
                        e.rotation.z+=controls.rotationSpeed;
                    }
                });
                requestAnimationFrame(renderScene);
                render.render(scene, camera);
            }
            //scene.fog=new THREE.Fog(0xffffff,0.015,100);
            renderScene();
        }
        
        window.onload = init;
    
    </script>
    </body>
    </html>

      1.7 为几何体的每一面都指定材质的材质----MeshFaceMaterial

        这种并不是真正的材质,而更像一种材质容器,通过MeshFaceMaterial可以为几何体的每一个面都指定不同的材质

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>1</title>
        <script type="text/javascript" src="three.js"></script>
        <script type="text/javascript" src="dat.gui.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    //var scene
        function init() {
            //生成一个场景
            var scene=new THREE.Scene();
            
            //生成一个相机
            //参数:视场,长宽比,近面,远面
            var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100);
            camera.position.x=-50;
            camera.position.y=40;
            camera.position.z=50;
            camera.lookAt(scene.position);
            scene.add(camera);
            
            var render;
            
            //生成一个webgl的渲染器
            var webGLrender=new THREE.WebGLRenderer();
            webGLrender.setClearColor(0xEEEEEE);
            webGLrender.setSize(window.innerWidth,window.innerHeight);
            webGLrender.shadowMapEnabled=true;
            //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影        
            render=webGLrender;
            
             var ambientLight = new THREE.AmbientLight(0x0c0c0c);
            scene.add(ambientLight);
    
            // add spotlight for the shadows
            var spotLight = new THREE.SpotLight(0xffffff);
            spotLight.position.set(-40, 60, -10);
            spotLight.castShadow = true;
            scene.add(spotLight);
            
            
            //生成一个有6个基础材质的数组
            var materials=[];
            materials.push(new THREE.MeshBasicMaterial({color:"red"}));
            materials.push(new THREE.MeshBasicMaterial({color:"blue"}));
            materials.push(new THREE.MeshBasicMaterial({color:"yellow"}));
            materials.push(new THREE.MeshBasicMaterial({color:"green"}));
            materials.push(new THREE.MeshBasicMaterial({color:"white"}));
            materials.push(new THREE.MeshBasicMaterial({color:"black"}));
            //这6个基础材质的数组作为参数传递给MeshFaceMaterial
            var faceMaterial=new THREE.MeshFaceMaterial(materials);
            
            //生成一个方块应用faceMaterial,即为每个面指定一种材质
            var cubeGeom=new THREE.CubeGeometry(6,6,6);
            var cube=new THREE.Mesh(cubeGeom,faceMaterial);
            scene.add(cube);
            
            
            //增加图形控制界面
            var controls=new function(){
                
                this.rotationSpeed=0.02;
                
            };
            
            var gui=new dat.GUI();
            
            gui.add(controls,"rotationSpeed",0,0.3);
            
            
            //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数
            //即controls的this.switchRender必须与下面的属性一致
            
            document.getElementById("WebGL-output").append(render.domElement);
            
            
            
            
            function renderScene(){
                scene.traverse(function(e){
                    if(e instanceof THREE.Mesh){
                        e.rotation.x+=controls.rotationSpeed;
                        e.rotation.y+=controls.rotationSpeed;
                        e.rotation.z+=controls.rotationSpeed;
                    }
                });
                requestAnimationFrame(renderScene);
                render.render(scene, camera);
            }
            //scene.fog=new THREE.Fog(0xffffff,0.015,100);
            renderScene();
        }
        
        window.onload = init;
    
    </script>
    </body>
    </html>

     这里的demo做了一个魔方

      1 一共需要生成27个方块

      2 每个方块的每个面都应用材质数组中材质,即每一个小方块的各个面颜色都不同

      3 方块的长宽要比10小一些,留个空隙

      4 注意一下每个方块的position

      5 这些方块追加到一个网格中,然后再将网格追加到场景中

      6 旋转的时候,是这个网格在旋转,而不是每个单独的旋转

      

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>1</title>
        <script type="text/javascript" src="three.js"></script>
        <script type="text/javascript" src="dat.gui.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    //var scene
        function init() {
            //生成一个场景
            var scene=new THREE.Scene();
            
            //生成一个相机
            //参数:视场,长宽比,近面,远面
            var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100);
            camera.position.x=-50;
            camera.position.y=40;
            camera.position.z=50;
            camera.lookAt(scene.position);
            scene.add(camera);
            
            var render;
            
            //生成一个webgl的渲染器
            var webGLrender=new THREE.WebGLRenderer();
            webGLrender.setClearColor(0xEEEEEE);
            webGLrender.setSize(window.innerWidth,window.innerHeight);
            webGLrender.shadowMapEnabled=true;
            //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影        
            render=webGLrender;
            
             var ambientLight = new THREE.AmbientLight(0x0c0c0c);
            scene.add(ambientLight);
    
            // add spotlight for the shadows
            var spotLight = new THREE.SpotLight(0xffffff);
            spotLight.position.set(-40, 60, -10);
            spotLight.castShadow = true;
            scene.add(spotLight);
            
            
            //生成一个有6个基础材质的数组
            var materials=[],group=new THREE.Mesh();
            materials.push(new THREE.MeshBasicMaterial({color:"red"}));
            materials.push(new THREE.MeshBasicMaterial({color:"blue"}));
            materials.push(new THREE.MeshBasicMaterial({color:"yellow"}));
            materials.push(new THREE.MeshBasicMaterial({color:"green"}));
            materials.push(new THREE.MeshBasicMaterial({color:"white"}));
            materials.push(new THREE.MeshBasicMaterial({color:"black"}));
            //这6个基础材质的数组作为参数传递给MeshFaceMaterial
            var faceMaterial=new THREE.MeshFaceMaterial(materials);
            
            //生成27个方块,每三个应用一种材质,即为每个面指定一种材质
            for(var x=0;x<3;x++){
                for(var y=0;y<3;y++){
                    for(var z=0;z<3;z++){
                        var cubeGeom=new THREE.BoxGeometry(9,9,9,9);
                        var cube=new THREE.Mesh(cubeGeom,faceMaterial);
                        cube.position.set(x*10-10,y*10,z*10-10);
                        group.add(cube);
                    }
                }
            }
            scene.add(group);
            
            
            //增加图形控制界面
            var controls=new function(){
                
                this.rotationSpeed=0.02;
                
            };
            
            var gui=new dat.GUI();
            
            gui.add(controls,"rotationSpeed",0,0.3);
            
            
            //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数
            //即controls的this.switchRender必须与下面的属性一致
            
            document.getElementById("WebGL-output").append(render.domElement);
            
            
            
            
            function renderScene(){
                group.rotation.x+=controls.rotationSpeed;
                group.rotation.y+=controls.rotationSpeed;
                group.rotation.z+=controls.rotationSpeed;
                requestAnimationFrame(renderScene);
                render.render(scene, camera);
            }
            //scene.fog=new THREE.Fog(0xffffff,0.015,100);
            renderScene();
        }
        
        window.onload = init;
    
    </script>
    </body>
    </html>

     1.8 高级材质

        1 MeshLambertMaterial:会对光源做出反应,可以用来创建暗淡的材质

          MeshLambertMaterial材质的ambient(环境色)属性:该材质的环境色,跟AmbientLight光源一起使用,这个颜色会与AmbientLight光源的颜色相乘,该属性的默认值是白色

          MeshLambertMaterial材质的emissive(发射色)属性:该材质发射的颜色,它其实并不是光源,而是一种纯粹的,不受其他光照影响的颜色,该属性的默认值是黑色

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>1</title>
        <script type="text/javascript" src="three.js"></script>
        <script type="text/javascript" src="dat.gui.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    //var scene
        function init() {
            //生成一个场景
            var scene=new THREE.Scene();
            
            //生成一个相机
            //参数:视场,长宽比,近面,远面
            var camera=new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,10,100);
            camera.position.x=-20;
            camera.position.y=30;
            camera.position.z=40;
            camera.lookAt(scene.position);
            scene.add(camera);
            
            var render;
            
            //生成一个webgl的渲染器
            var webGLrender=new THREE.WebGLRenderer();
            webGLrender.setClearColor(0xEEEEEE);
            webGLrender.setSize(window.innerWidth,window.innerHeight);
            webGLrender.shadowMapEnabled=true;
            //允许阴影映射,渲染阴影需要大量的资源,因此我们需要告诉渲染器我们需要阴影        
            render=webGLrender;
            
             var ambientLight = new THREE.AmbientLight(0x0c0c0c);
            scene.add(ambientLight);
    
            // add spotlight for the shadows
            var spotLight = new THREE.SpotLight(0xffffff);
            spotLight.position.set(-40, 60, -10);
            spotLight.castShadow = true;
            scene.add(spotLight);
            
            var planeGeometry = new THREE.PlaneGeometry(1000, 1000, 4, 4);
            var plane = new THREE.Mesh(planeGeometry, new THREE.MeshBasicMaterial({color: 0x555555}));
            plane.rotation.x=-Math.PI/2;
            plane.position.y=0;
            scene.add(plane);
            
            //生成一个有6个基础材质的数组
            var cubeGeom=new THREE.BoxGeometry(10,10,10);
            var material=new THREE.MeshLambertMaterial({
                color:0x7777ff
            });
            var cube=new THREE.Mesh(cubeGeom,material);
            cube.position.x=0;
            cube.position.y=13;
            cube.position.z=2;
            scene.add(cube);
            
            //增加图形控制界面
            var controls=new function(){
                this.ambient=material.ambient.getHex();
                this.emissive=material.emissive.getHex();
                this.rotationSpeed=0.02;
                this.opacity=material.opacity;
                this.transparent=material.transparent;
                this.side="front";
                
            };
            
            var gui=new dat.GUI();
            
            gui.add(controls,"rotationSpeed",0,0.3);
            gui.add(controls,"opacity",0,1).onChange(function(e){
                material.opacity=e;
            });
            gui.add(controls,"transparent").onChange(function(e){
                material.transparent=e;
            });
            gui.add(controls,"side",["front","back","double"]).onChange(function(e){
                
                switch(e){
                    case "front":
                        material.side=THREE.FrontSide;
                    break;
                    case "back":
                        material.side=THREE.BackSide;
                    break;
                    case "double":
                        material.side=THREE.DoubleSide;
                    break;
                }
                material.needsUpdate=true;
            });
            //使用addColor方法,添加gui颜色选择器
            gui.addColor(controls,"ambient").onChange(function(e){
                //颜色选择器获取到的是gbs,需要转化THREE的color格式
                material.ambient=new THREE.Color(e);
            });
            gui.addColor(controls,"emissive").onChange(function(e){
                material.emissive=new THREE.Color(e);
            });
            
            //gui的一个参数是一个对象,该对象控制的属性是add的函数的第二个参数
            //即controls的this.switchRender必须与下面的属性一致
            
            document.getElementById("WebGL-output").append(render.domElement);
            
            
            
            
            function renderScene(){
                cube.rotation.x+=controls.rotationSpeed;
                cube.rotation.y+=controls.rotationSpeed;
                cube.rotation.z+=controls.rotationSpeed;
                requestAnimationFrame(renderScene);
                render.render(scene, camera);
            }
            //scene.fog=new THREE.Fog(0xffffff,0.015,100);
            renderScene();
        }
        
        window.onload = init;
    
    </script>
    </body>
    </html>

        2 MeshPhongMaterial:会对光源做出反应,可以用来创建光亮的材质

    名称 描述
    specular(镜面)

    该属性指定该材质的光亮程度及其高光部分的颜色,

    如果将它设置跟color的颜色相同,就会得到一种类似于金属的材质

    如果设置成灰色,材质就会显得更像塑料

    shininess 该属性指定高光部分的亮度,默认值是30

        

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>Example 04.06 - Mesh Lambert material</title>
        <script type="text/javascript" src="../libs/three.js"></script>
    
        <script type="text/javascript" src="../libs/stats.js"></script>
        <script type="text/javascript" src="../libs/dat.gui.js"></script>
        <script type="text/javascript" src="../libs/CanvasRenderer.js"></script>
        <script type="text/javascript" src="../libs/Projector.js"></script>
    
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <div id="Stats-output">
    </div>
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    
        // once everything is loaded, we run our Three.js stuff.
        function init() {
    
            var stats = initStats();
    
            // create a scene, that will hold all our elements such as objects, cameras and lights.
            var scene = new THREE.Scene();
    
            // create a camera, which defines where we're looking at.
            var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
    
            // create a render and set the size
            var renderer;
            var webGLRenderer = new THREE.WebGLRenderer();
            webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE, 1.0));
            webGLRenderer.setSize(window.innerWidth, window.innerHeight);
            webGLRenderer.shadowMapEnabled = true;
    
            var canvasRenderer = new THREE.CanvasRenderer();
            canvasRenderer.setSize(window.innerWidth, window.innerHeight);
            renderer = webGLRenderer;
    
            var groundGeom = new THREE.PlaneGeometry(100, 100, 4, 4);
            var groundMesh = new THREE.Mesh(groundGeom, new THREE.MeshBasicMaterial({color: 0x555555}));
            groundMesh.rotation.x = -Math.PI / 2;
            groundMesh.position.y = -20;
            scene.add(groundMesh);
    
            var sphereGeometry = new THREE.SphereGeometry(14, 20, 20);
            var cubeGeometry = new THREE.BoxGeometry(15, 15, 15);
            var planeGeometry = new THREE.PlaneGeometry(14, 14, 4, 4);
    
    
            var meshMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
            var sphere = new THREE.Mesh(sphereGeometry, meshMaterial);
            var cube = new THREE.Mesh(cubeGeometry, meshMaterial);
            var plane = new THREE.Mesh(planeGeometry, meshMaterial);
    
            // position the sphere
            sphere.position.x = 0;
            sphere.position.y = 3;
            sphere.position.z = 2;
    
    
            cube.position = sphere.position;
            plane.position = sphere.position;
    
    
            // add the sphere to the scene
            scene.add(cube);
    
            // position and point the camera to the center of the scene
            camera.position.x = -20;
            camera.position.y = 30;
            camera.position.z = 40;
            camera.lookAt(new THREE.Vector3(10, 0, 0));
    
            // add subtle ambient lighting
            var ambientLight = new THREE.AmbientLight(0x0c0c0c);
            scene.add(ambientLight);
    
            // add spotlight for the shadows
            var spotLight = new THREE.SpotLight(0xffffff);
            spotLight.position.set(-30, 60, 60);
            spotLight.castShadow = true;
            scene.add(spotLight);
    
            // add the output of the renderer to the html element
            document.getElementById("WebGL-output").appendChild(renderer.domElement);
    
            // call the render function
            var step = 0;
    
            var controls = new function () {
                this.rotationSpeed = 0.02;
                this.bouncingSpeed = 0.03;
    
                this.opacity = meshMaterial.opacity;
                this.transparent = meshMaterial.transparent;
                this.overdraw = meshMaterial.overdraw;
                this.visible = meshMaterial.visible;
                this.emissive = meshMaterial.emissive.getHex();
                this.ambient = meshMaterial.ambient.getHex();
                this.side = "front";
    
                this.color = meshMaterial.color.getStyle();
                this.wrapAround = false;
                this.wrapR = 1;
                this.wrapG = 1;
                this.wrapB = 1;
    
                this.selectedMesh = "cube";
    
            };
    
            var gui = new dat.GUI();
    
    
            var spGui = gui.addFolder("Mesh");
            spGui.add(controls, 'opacity', 0, 1).onChange(function (e) {
                meshMaterial.opacity = e
            });
            spGui.add(controls, 'transparent').onChange(function (e) {
                meshMaterial.transparent = e
            });
            spGui.add(controls, 'visible').onChange(function (e) {
                meshMaterial.visible = e
            });
            spGui.addColor(controls, 'ambient').onChange(function (e) {
                meshMaterial.ambient = new THREE.Color(e)
            });
            spGui.addColor(controls, 'emissive').onChange(function (e) {
                meshMaterial.emissive = new THREE.Color(e)
            });
            spGui.add(controls, 'side', ["front", "back", "double"]).onChange(function (e) {
                console.log(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;
    
            });
            spGui.addColor(controls, 'color').onChange(function (e) {
                meshMaterial.color.setStyle(e)
            });
            spGui.add(controls, 'selectedMesh', ["cube", "sphere", "plane"]).onChange(function (e) {
    
                scene.remove(plane);
                scene.remove(cube);
                scene.remove(sphere);
    
                switch (e) {
                    case "cube":
                        scene.add(cube);
                        break;
                    case "sphere":
                        scene.add(sphere);
                        break;
                    case "plane":
                        scene.add(plane);
                        break;
    
                }
    
    
                scene.add(e);
            });
    
            spGui.add(controls, 'wrapAround').onChange(function (e) {
    
                meshMaterial.wrapAround = e;
                meshMaterial.needsUpdate = true;
            });
    
            spGui.add(controls, 'wrapR', 0, 1).step(0.01).onChange(function (e) {
                meshMaterial.wrapRGB.x = e;
            });
    
            spGui.add(controls, 'wrapG', 0, 1).step(0.01).onChange(function (e) {
                meshMaterial.wrapRGB.y = e;
            });
    
            spGui.add(controls, 'wrapB', 0, 1).step(0.01).onChange(function (e) {
                meshMaterial.wrapRGB.z = e;
    
            });
    
            render();
    
            function render() {
                stats.update();
    
                cube.rotation.y = step += 0.01;
                plane.rotation.y = step;
                sphere.rotation.y = step;
    
                // render using requestAnimationFrame
                requestAnimationFrame(render);
                renderer.render(scene, camera);
            }
    
            function initStats() {
    
                var stats = new Stats();
    
                stats.setMode(0); // 0: fps, 1: ms
    
    
                // Align top-left
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.left = '0px';
                stats.domElement.style.top = '0px';
    
                document.getElementById("Stats-output").appendChild(stats.domElement);
    
                return stats;
            }
        }
        window.onload = init;
    </script>
    </body>
    </html>

        3 ShaderMaterial:最通用也是最难用的材质,通过ShaderMaterial可以创建自己的着色程序,直接在webgl环境中运行,

        着色器可以将three.js中的js对象转化为屏幕上的像素,

        注意着色器不是js编写的,而是类似于c的GLSL语言,所以下面这个demo只是一个例子,并不做过多的解释

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>Example 04.08 - Shader material - http://glsl.heroku.com/</title>
        <script type="text/javascript" src="../libs/three.js"></script>
    
        <script type="text/javascript" src="../libs/stats.js"></script>
        <script type="text/javascript" src="../libs/dat.gui.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <script id="vertex-shader" type="x-shader/x-vertex">
        uniform float time;
        varying vec2 vUv;
    
    
        void main()
        {
        vec3 posChanged = position;
        posChanged.x = posChanged.x*(abs(sin(time*1.0)));
        posChanged.y = posChanged.y*(abs(cos(time*1.0)));
        posChanged.z = posChanged.z*(abs(sin(time*1.0)));
        //gl_Position = projectionMatrix * modelViewMatrix * vec4(position*(abs(sin(time)/2.0)+0.5),1.0);
        gl_Position = projectionMatrix * modelViewMatrix * vec4(posChanged,1.0);
        }
    
    </script>
    
    <script id="fragment-shader-1" type="x-shader/x-fragment">
        precision highp float;
        uniform float time;
        uniform float alpha;
        uniform vec2 resolution;
        varying vec2 vUv;
    
        void main2(void)
        {
        vec2 position = vUv;
        float red = 1.0;
        float green = 0.25 + sin(time) * 0.25;
        float blue = 0.0;
        vec3 rgb = vec3(red, green, blue);
        vec4 color = vec4(rgb, alpha);
        gl_FragColor = color;
        }
    
        #define PI 3.14159
        #define TWO_PI (PI*2.0)
        #define N 68.5
    
        void main(void)
        {
        vec2 center = (gl_FragCoord.xy);
        center.x=-10.12*sin(time/200.0);
        center.y=-10.12*cos(time/200.0);
    
        vec2 v = (gl_FragCoord.xy - resolution/20.0) / min(resolution.y,resolution.x) * 15.0;
        v.x=v.x-10.0;
        v.y=v.y-200.0;
        float col = 0.0;
    
        for(float i = 0.0; i < N; i++)
        {
        float a = i * (TWO_PI/N) * 61.95;
        col += cos(TWO_PI*(v.y * cos(a) + v.x * sin(a) + sin(time*0.004)*100.0 ));
        }
    
        col /= 5.0;
    
        gl_FragColor = vec4(col*1.0, -col*1.0,-col*4.0, 1.0);
        }
    
    
    </script>
    
    <script id="fragment-shader-2" type="x-shader/x-fragment">
        // from http://glsl.heroku.com/e#7906.0
    
    
        uniform float time;
        uniform vec2 resolution;
    
        // 2013-03-30 by @hintz
    
        #define CGFloat float
        #define M_PI 3.14159265359
    
        vec3 hsvtorgb(float h, float s, float v)
        {
        float c = v * s;
        h = mod((h * 6.0), 6.0);
        float x = c * (1.0 - abs(mod(h, 2.0) - 1.0));
        vec3 color;
    
        if (0.0 <= h && h < 1.0)
        {
        color = vec3(c, x, 0.0);
        }
        else if (1.0 <= h && h < 2.0)
        {
        color = vec3(x, c, 0.0);
        }
        else if (2.0 <= h && h < 3.0)
        {
        color = vec3(0.0, c, x);
        }
        else if (3.0 <= h && h < 4.0)
        {
        color = vec3(0.0, x, c);
        }
        else if (4.0 <= h && h < 5.0)
        {
        color = vec3(x, 0.0, c);
        }
        else if (5.0 <= h && h < 6.0)
        {
        color = vec3(c, 0.0, x);
        }
        else
        {
        color = vec3(0.0);
        }
    
        color += v - c;
    
        return color;
        }
    
        void main(void)
        {
    
        vec2 position = (gl_FragCoord.xy - 0.5 * resolution) / resolution.y;
        float x = position.x;
        float y = position.y;
    
        CGFloat a = atan(x, y);
    
        CGFloat d = sqrt(x*x+y*y);
        CGFloat d0 = 0.5*(sin(d-time)+1.5)*d;
        CGFloat d1 = 5.0;
    
        CGFloat u = mod(a*d1+sin(d*10.0+time), M_PI*2.0)/M_PI*0.5 - 0.5;
        CGFloat v = mod(pow(d0*4.0, 0.75),1.0) - 0.5;
    
        CGFloat dd = sqrt(u*u+v*v);
    
        CGFloat aa = atan(u, v);
    
        CGFloat uu = mod(aa*3.0+3.0*cos(dd*30.0-time), M_PI*2.0)/M_PI*0.5 - 0.5;
        // CGFloat vv = mod(dd*4.0,1.0) - 0.5;
    
        CGFloat d2 = sqrt(uu*uu+v*v)*1.5;
    
        gl_FragColor = vec4( hsvtorgb(dd+time*0.5/d1, sin(dd*time), d2), 1.0 );
        }
    
    </script>
    
    <script id="fragment-shader-3" type="x-shader/x-fragment">
        uniform vec2 resolution;
        uniform float time;
    
        vec2 rand(vec2 pos)
        {
        return fract( 0.00005 * (pow(pos+2.0, pos.yx + 1.0) * 22222.0));
        }
        vec2 rand2(vec2 pos)
        {
        return rand(rand(pos));
        }
    
        float softnoise(vec2 pos, float scale)
        {
        vec2 smplpos = pos * scale;
        float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x;
        float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x;
        float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x;
        float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x;
    
        vec2 a = fract(smplpos);
        return mix(
        mix(c0, c1, smoothstep(0.0, 1.0, a.x)),
        mix(c2, c3, smoothstep(0.0, 1.0, a.x)),
        smoothstep(0.0, 1.0, a.y));
        }
    
        void main(void)
        {
        vec2 pos = gl_FragCoord.xy / resolution.y;
        pos.x += time * 0.1;
        float color = 0.0;
        float s = 1.0;
        for(int i = 0; i < 8; i++)
        {
        color += softnoise(pos+vec2(i)*0.02, s * 4.0) / s / 2.0;
        s *= 2.0;
        }
        gl_FragColor = vec4(color);
        }
    
    </script>
    
    <script id="fragment-shader-4" type="x-shader/x-fragment">
    
    
        uniform float time;
        uniform vec2 resolution;
    
        vec2 rand(vec2 pos)
        {
        return
        fract(
        (
        pow(
        pos+2.0,
        pos.yx+2.0
        )*555555.0
        )
        );
        }
    
        vec2 rand2(vec2 pos)
        {
        return rand(rand(pos));
        }
    
        float softnoise(vec2 pos, float scale) {
        vec2 smplpos = pos * scale;
        float c0 = rand2((floor(smplpos) + vec2(0.0, 0.0)) / scale).x;
        float c1 = rand2((floor(smplpos) + vec2(1.0, 0.0)) / scale).x;
        float c2 = rand2((floor(smplpos) + vec2(0.0, 1.0)) / scale).x;
        float c3 = rand2((floor(smplpos) + vec2(1.0, 1.0)) / scale).x;
    
        vec2 a = fract(smplpos);
        return mix(mix(c0, c1, smoothstep(0.0, 1.0, a.x)),
        mix(c2, c3, smoothstep(0.0, 1.0, a.x)),
        smoothstep(0.0, 1.0, a.x));
        }
    
        void main( void ) {
        vec2 pos = gl_FragCoord.xy / resolution.y - time * 0.4;
    
        float color = 0.0;
        float s = 1.0;
        for (int i = 0; i < 6; ++i) {
        color += softnoise(pos + vec2(0.01 * float(i)), s * 4.0) / s / 2.0;
        s *= 2.0;
        }
        gl_FragColor = vec4(color,mix(color,cos(color),sin(color)),color,1);
        }
    
    </script>
    
    <script id="fragment-shader-5" type="x-shader/x-fragment">
    
        uniform float time;
        uniform vec2 resolution;
    
        // tie nd die by Snoep Games.
    
        void main( void ) {
    
        vec3 color = vec3(1.0, 0., 0.);
        vec2 pos = (( 1.4 * gl_FragCoord.xy - resolution.xy) / resolution.xx)*1.5;
        float r=sqrt(pos.x*pos.x+pos.y*pos.y)/15.0;
        float size1=2.0*cos(time/60.0);
        float size2=2.5*sin(time/12.1);
    
        float rot1=13.00; //82.0+16.0*sin(time/4.0);
        float rot2=-50.00; //82.0+16.0*sin(time/8.0);
        float t=sin(time);
        float a = (60.0)*sin(rot1*atan(pos.x-size1*pos.y/r,pos.y+size1*pos.x/r)+time);
        a += 200.0*acos(pos.x*2.0+cos(time/2.0))+asin(pos.y*5.0+sin(time/2.0));
        a=a*(r/50.0);
        a=200.0*sin(a*5.0)*(r/30.0);
        if(a>5.0) a=a/200.0;
        if(a<0.5) a=a*22.5;
        gl_FragColor = vec4( cos(a/20.0),a*cos(a/200.0),sin(a/8.0), 1.0 );
        }
    
    
    </script>
    
    <script id="fragment-shader-6" type="x-shader/x-fragment">
    
    
        uniform float time;
        uniform vec2 resolution;
    
    
        void main( void )
        {
    
        vec2 uPos = ( gl_FragCoord.xy / resolution.xy );//normalize wrt y axis
        //suPos -= vec2((resolution.x/resolution.y)/2.0, 0.0);//shift origin to center
    
        uPos.x -= 1.0;
        uPos.y -= 0.5;
    
        vec3 color = vec3(0.0);
        float vertColor = 2.0;
        for( float i = 0.0; i < 15.0; ++i )
        {
        float t = time * (0.9);
    
        uPos.y += sin( uPos.x*i + t+i/2.0 ) * 0.1;
        float fTemp = abs(1.0 / uPos.y / 100.0);
        vertColor += fTemp;
        color += vec3( fTemp*(10.0-i)/10.0, fTemp*i/10.0, pow(fTemp,1.5)*1.5 );
        }
    
        vec4 color_final = vec4(color, 1.0);
        gl_FragColor = color_final;
        }
    
    </script>
    
    <div id="Stats-output">
    </div>
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    
        // once everything is loaded, we run our Three.js stuff.
        function init() {
    
            var stats = initStats();
    
            // create a scene, that will hold all our elements such as objects, cameras and lights.
            var scene = new THREE.Scene();
    
            // create a camera, which defines where we're looking at.
            var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
    
            // create a render and set the size
    
            var renderer = new THREE.WebGLRenderer();
            renderer.setClearColor(new THREE.Color(0x000000, 1.0));
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.shadowMapEnabled = true;
    
    
            var cubeGeometry = new THREE.BoxGeometry(20, 20, 20);
    
            var meshMaterial1 = createMaterial("vertex-shader", "fragment-shader-1");
            var meshMaterial2 = createMaterial("vertex-shader", "fragment-shader-2");
            var meshMaterial3 = createMaterial("vertex-shader", "fragment-shader-3");
            var meshMaterial4 = createMaterial("vertex-shader", "fragment-shader-4");
            var meshMaterial5 = createMaterial("vertex-shader", "fragment-shader-5");
            var meshMaterial6 = createMaterial("vertex-shader", "fragment-shader-6");
    
    
            var material = new THREE.MeshFaceMaterial(
                    [meshMaterial1,
                        meshMaterial2,
                        meshMaterial3,
                        meshMaterial4,
                        meshMaterial5,
                        meshMaterial6]);
    //        var material = new THREE.MeshFaceMaterial([meshMaterial2, meshMaterial2, meshMaterial1, meshMaterial1, meshMaterial1, meshMaterial1]);
    
            var cube = new THREE.Mesh(cubeGeometry, material);
    
    
            // add the sphere to the scene
            scene.add(cube);
    
            // position and point the camera to the center of the scene
            camera.position.x = 30;
            camera.position.y = 30;
            camera.position.z = 30;
            camera.lookAt(new THREE.Vector3(0, 0, 0));
    
            // add subtle ambient lighting
            var ambientLight = new THREE.AmbientLight(0x0c0c0c);
            scene.add(ambientLight);
    
            // add spotlight for the shadows
            var spotLight = new THREE.SpotLight(0xffffff);
            spotLight.position.set(-40, 60, -10);
            spotLight.castShadow = true;
            scene.add(spotLight);
    
            // add the output of the renderer to the html element
            document.getElementById("WebGL-output").appendChild(renderer.domElement);
    
            // call the render function
            var step = 0;
            var oldContext = null;
    
            var controls = new function () {
                this.rotationSpeed = 0.02;
                this.bouncingSpeed = 0.03;
    
                this.opacity = meshMaterial1.opacity;
                this.transparent = meshMaterial1.transparent;
    
                this.visible = meshMaterial1.visible;
                this.side = "front";
    
                this.wireframe = meshMaterial1.wireframe;
                this.wireframeLinewidth = meshMaterial1.wireframeLinewidth;
    
                this.selectedMesh = "cube";
    
                this.shadow = "flat";
    
            };
    
    
            render();
    
            function render() {
                stats.update();
    
                cube.rotation.y = step += 0.01;
                cube.rotation.x = step;
                cube.rotation.z = step;
    
    
                cube.material.materials.forEach(function (e) {
                    e.uniforms.time.value += 0.01;
                });
    
    
                // render using requestAnimationFrame
                requestAnimationFrame(render);
                renderer.render(scene, camera);
            }
    
            function initStats() {
    
                var stats = new Stats();
    
                stats.setMode(0); // 0: fps, 1: ms
    
    
                // Align top-left
                stats.domElement.style.position = 'absolute';
                stats.domElement.style.left = '0px';
                stats.domElement.style.top = '0px';
    
                document.getElementById("Stats-output").appendChild(stats.domElement);
    
                return stats;
            }
    
            function createMaterial(vertexShader, fragmentShader) {
                var vertShader = document.getElementById(vertexShader).innerHTML;
                var fragShader = document.getElementById(fragmentShader).innerHTML;
    
                var attributes = {};
                var uniforms = {
                    time: {type: 'f', value: 0.2},
                    scale: {type: 'f', value: 0.2},
                    alpha: {type: 'f', value: 0.6},
                    resolution: {type: "v2", value: new THREE.Vector2()}
                };
    
                uniforms.resolution.value.x = window.innerWidth;
                uniforms.resolution.value.y = window.innerHeight;
    
                var meshMaterial = new THREE.ShaderMaterial({
                    uniforms: uniforms,
                    attributes: attributes,
                    vertexShader: vertShader,
                    fragmentShader: fragShader,
                    transparent: true
    
                });
    
    
                return meshMaterial;
            }
    
    
        }
        window.onload = init;
    </script>
    </body>
    </html>

    1.9 线段几何体的材质

      下面这两种材质只能应用于特定的几何体:THREE.Line(线段)

      1.9.1 LineBaseMaterial:可以设置线段的颜色,宽度,端点,连接点等属性

      1.9.2 LineDashedMaterial:与上面的LineBaseMaterial属性一样,但是可以通过指定短划线和空格的长度,创造出来虚线的效果

      

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>Example 04.09 - Linematerial</title>
        <script type="text/javascript" src="../libs/three.js"></script>
    
        <script type="text/javascript" src="../libs/stats.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <div id="Stats-output">
    </div>
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    
        // once everything is loaded, we run our Three.js stuff.
        function init() {
    
            //var stats = initStats();
    
            // create a scene, that will hold all our elements such as objects, cameras and lights.
            var scene = new THREE.Scene();
    
            // create a camera, which defines where we're looking at.
            var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
    
            // create a render and set the size
            var renderer = new THREE.WebGLRenderer();
    
            renderer.setClearColor(new THREE.Color(0x000000, 1.0));
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.shadowMapEnabled = true;
    
    
            // position and point the camera to the center of the scene
            camera.position.x = -30;
            camera.position.y = 40;
            camera.position.z = 30;
            camera.lookAt(scene.position);
    
            // 环境光 没有特定的光源,该光源不会影响阴影的产生,使用该光源是为了弱化阴影或者添加一些颜色
            var ambientLight = new THREE.AmbientLight(0x0c0c0c);
            scene.add(ambientLight);
    
            //聚光灯光源,最常使用的光源,锥形效果
            var spotLight = new THREE.SpotLight(0xffffff);
            spotLight.position.set(-40, 60, -10);
            spotLight.castShadow = true;
            scene.add(spotLight);
            
            /*本处书中给出的例子是gosper曲线,涉及到数学曲线、,本人没有看懂,所以使用了随机生成的点,附带上Gosper函数,
            能看懂的朋友,可以留言给我,谢谢了!
            function gosper(a, b) {
    
                var turtle = [0, 0, 0];
                var points = [];
                var count = 0;
    
                rg(a, b, turtle);
    
    
                return points;
                
                //右走
                function rt(x) {
                    turtle[2] += x;
                }
                
                //左走
                function lt(x) {
                    turtle[2] -= x;
                }
    
                function fd(dist) {
    //                ctx.beginPath();
                    points.push({x: turtle[0], y: turtle[1], z: Math.sin(count) * 5});
    //                ctx.moveTo(turtle[0], turtle[1]);
    
                    var dir = turtle[2] * (Math.PI / 180);
                    turtle[0] += Math.cos(dir) * dist;
                    turtle[1] += Math.sin(dir) * dist;
    
                    points.push({x: turtle[0], y: turtle[1], z: Math.sin(count) * 5});
    //                ctx.lineTo(turtle[0], turtle[1]);
    //                ctx.stroke();
    
                }
    
                function rg(st, ln, turtle) {
    
                    st--;
                    ln = ln / 2.6457;
                    if (st > 0) {
    //                    ctx.strokeStyle = '#111';
                        rg(st, ln, turtle);
                        rt(60);
                        gl(st, ln, turtle);
                        rt(120);
                        gl(st, ln, turtle);
                        lt(60);
                        rg(st, ln, turtle);
                        lt(120);
                        rg(st, ln, turtle);
                        rg(st, ln, turtle);
                        lt(60);
                        gl(st, ln, turtle);
                        rt(60);
                    }
                    if (st == 0) {
                        fd(ln);
                        rt(60);
                        fd(ln);
                        rt(120);
                        fd(ln);
                        lt(60);
                        fd(ln);
                        lt(120);
                        fd(ln);
                        fd(ln);
                        lt(60);
                        fd(ln);
                        rt(60)
                    }
                }
    
                function gl(st, ln, turtle) {
                    st--;
                    ln = ln / 2.6457;
                    if (st > 0) {
    //                    ctx.strokeStyle = '#555';
                        lt(60);
                        rg(st, ln, turtle);
                        rt(60);
                        gl(st, ln, turtle);
                        gl(st, ln, turtle);
                        rt(120);
                        gl(st, ln, turtle);
                        rt(60);
                        rg(st, ln, turtle);
                        lt(120);
                        rg(st, ln, turtle);
                        lt(60);
                        gl(st, ln, turtle);
                    }
                    if (st == 0) {
                        lt(60);
                        fd(ln);
                        rt(60);
                        fd(ln);
                        fd(ln);
                        rt(120);
                        fd(ln);
                        rt(60);
                        fd(ln);
                        lt(120);
                        fd(ln);
                        lt(60);
                        fd(ln);
                    }
                }
            }
            
            
            */
            var points=[];
            function getPoints(){
                var rmd_x=Math.random()*50;
                var rmd_y=Math.random()*50;
                var rmd_z=Math.random()*50;
                points.push({x:rmd_x, y: rmd_y, z: rmd_z});
            }
            
            for(var j=0;j<100;j++){
                getPoints();
            }
    
            //生成一个几何体
            var lines = new THREE.Geometry();
            var colors = [];
            var i = 0;
            //该几何体的顶点由getPoint函数生成的点组成
            points.forEach(function (e) {
                lines.vertices.push(new THREE.Vector3(e.x, e.z, e.y));
                colors[i] = new THREE.Color(0xffffff);
                colors[i].setHSL(e.x / 100 + 0.5, (  e.y * 20 ) / 300, 0.8);
                //色调,饱和度,亮度
                i++;
            });
            
            //该几何体的颜色就是上面得到的颜色
            lines.colors = colors;
            /*这里有几个点不是很理解,linewidth是设置线段的宽度的,但是这里即使设置到50,也没有任何反应,不知道是哪里写错了
            有能找到问题的欢迎留言给我,另外透明度的opacity属性也不起作用            
            */
            
            
            var material = new THREE.LineBasicMaterial({
                opacity: 1.0,
                line 4,
                vertexColors: THREE.VertexColors
            });
    
            var line = new THREE.Line(lines, material);
            line.position.set(25, -30, -60);
            scene.add(line);
    
            // add the output of the renderer to the html element
            document.getElementById("WebGL-output").appendChild(renderer.domElement);
    
            // call the render function
            var step = 0;
            render();
    
            function render() {
                //stats.update();
                line.rotation.z = step += 0.01;
    
                requestAnimationFrame(render);
                renderer.render(scene, camera);
            }
        };
    
        window.onload = init;
    
    
    </script>
    </body>
    </html>

    LineDashedMaterial与LineBasicMaterial相似,多了几个属性,dashSize:短划线的长度,gapSize间隔的长度

    <!DOCTYPE html>
    
    <html>
    
    <head>
        <title>Example 04.09 - Linematerial</title>
        <script type="text/javascript" src="../libs/three.js"></script>
    
        <script type="text/javascript" src="../libs/stats.js"></script>
        <style>
            body {
                /* set margin to 0 and overflow to hidden, to go fullscreen */
                margin: 0;
                overflow: hidden;
            }
        </style>
    </head>
    <body>
    
    <div id="Stats-output">
    </div>
    <!-- Div which will hold the Output -->
    <div id="WebGL-output">
    </div>
    
    <!-- Javascript code that runs our Three.js examples -->
    <script type="text/javascript">
    
        // once everything is loaded, we run our Three.js stuff.
        function init() {
    
            //var stats = initStats();
    
            // create a scene, that will hold all our elements such as objects, cameras and lights.
            var scene = new THREE.Scene();
    
            // create a camera, which defines where we're looking at.
            var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
    
            // create a render and set the size
            var renderer = new THREE.WebGLRenderer();
    
            renderer.setClearColor(new THREE.Color(0x000000, 1.0));
            renderer.setSize(window.innerWidth, window.innerHeight);
            renderer.shadowMapEnabled = true;
    
    
            // position and point the camera to the center of the scene
            camera.position.x = -30;
            camera.position.y = 40;
            camera.position.z = 30;
            camera.lookAt(scene.position);
    
            // 环境光 没有特定的光源,该光源不会影响阴影的产生,使用该光源是为了弱化阴影或者添加一些颜色
            var ambientLight = new THREE.AmbientLight(0x0c0c0c);
            scene.add(ambientLight);
    
            //聚光灯光源,最常使用的光源,锥形效果
            var spotLight = new THREE.SpotLight(0xffffff);
            spotLight.position.set(-40, 60, -10);
            spotLight.castShadow = true;
            scene.add(spotLight);
            
           
            var points=[];
            function getPoints(){
                var rmd_x=Math.random()*50;
                var rmd_y=Math.random()*50;
                var rmd_z=Math.random()*50;
                points.push({x:rmd_x, y: rmd_y, z: rmd_z});
            }
            
            for(var j=0;j<100;j++){
                getPoints();
            }
    
            //生成一个几何体
            var lines = new THREE.Geometry();
            var colors = [];
            var i = 0;
            //该几何体的顶点由getPoint函数生成的点组成
            points.forEach(function (e) {
                lines.vertices.push(new THREE.Vector3(e.x, e.z, e.y));
                colors[i] = new THREE.Color(0xffffff);
                colors[i].setHSL(e.x / 100 + 0.5, (  e.y * 20 ) / 300, 0.8);
                //色调,饱和度,亮度
                i++;
            });
            
            //该几何体的颜色就是上面得到的颜色
            lines.colors = colors;
            
            //必须调用该方法,如果不调用,间隔就不能显示出来
            lines.computeLineDistances();
           var material = new THREE.LineDashedMaterial({
                dashSize:10,//短划线的长度
            gapSize:1,//间隔的长度
                scale: 0.4,//缩放的比例
                vertexColors:THREE.VertexColors//为每个顶点指定一个颜色
            });
    
            var line = new THREE.Line(lines, material);
            line.position.set(25, -30, -60);
            scene.add(line);
    
            // add the output of the renderer to the html element
            document.getElementById("WebGL-output").appendChild(renderer.domElement);
    
            // call the render function
            var step = 0;
            render();
    
            function render() {
                //stats.update();
                line.rotation.z = step += 0.01;
    
                requestAnimationFrame(render);
                renderer.render(scene, camera);
            }
        };
    
        window.onload = init;
    
    
    </script>
    </body>
    </html>
  • 相关阅读:
    tableView滑动时cell消失
    收集别人写的很好的关于多线程的文章
    scroll或是其子类被添加进view时,界面自动上移
    runtime之实现对象序列化
    runtime之方法的交换
    升级mac中的系统之后,给PHP安装扩展常出现问题
    ubuntu下搭建Scrapy框架简单办法
    CuDA的快速下载链接
    windows下Scrapy爬虫框架环境搭建
    windows下安装pywin32报错:close failed in file object destructor:sys.excepthook is missing lost sys.stderr
  • 原文地址:https://www.cnblogs.com/amy2011/p/6148736.html
Copyright © 2020-2023  润新知