博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

Posted on 2017-01-29 16:41  Amy-lover  阅读(20060)  评论(0编辑  收藏  举报

 

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

一 材质

  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,
            linewidth: 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>