【three.js学习笔记】02 物体材质 光 与 影

神说要有光,便有了光
神说光是好的,于是把光与暗分开了

在所有的3d游戏或者动画中,光与阴影都是非常重要的一部分,阴影可以影响到很多东西,一个游戏,阴影可以说是分辨一个游戏画面的好坏。
这一章中涉及到:

  1. 物体材质
  2. 添加光源
  3. 添加阴影
  4. 添加阴影的受体

在前面已经介绍过怎么样创建场景添加相机与物体,那么就直接贴创建场景的代码了

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--<script src="../three.min.js"></script>--><!--我发现我用的这个three.min.js本地版本没有辅助线-->
    <script src='https://threejs.org/build/three.js'></script>
    <title>场景</title>
    <style>
        body{
            margin:0;padding:0;
            overflow:hidden;
        }
    </style>
</head>
<body>
    <div id="WebGL-output"></div>
    <script>
        //初始化函数。在加载three之后调用,初始化所有的东西
        function init(){
            //创建场景。所有的物体对象都在场景上相当于是一个舞台
            var scene = new THREE.Scene();

            //创建透视相机
            var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
            //辅助线
            var axes = new THREE.AxesHelper(20);
            scene.add(axes);

            //渲染器
            var renderer = new THREE.WebGLRenderer();
            renderer.setClearColor(new THREE.Color(0xEEEEEE));

            renderer.setSize(window.innerWidth,window.innerHeight);
            //THREE.PCFSoftShadowMap  THREE.PCFShadowMap  BasicShadowMap
            //创建平面
            //材质种类:MeshLambertMaterial  MeshPhongMaterial MeshBasicMaterial
            var planeGeometry = new THREE.PlaneGeometry(60, 30);//框架
            var planeMaterial = new THREE.MeshBasicMaterial({color: 0xaaaaaa});//材质
            var planeMaterial1 = new THREE.MeshPhongMaterial( { color: 0xaaaaaa, dithering: true } );
            var plane = new THREE.Mesh(planeGeometry, planeMaterial);//填充


            //更改平面位置
            plane.rotation.x = -0.5 * Math.PI;
            plane.position.x = 15;
            plane.position.y = 0;
            plane.position.z = 0;

            scene.add(plane);

            //创建立方体
            var cubeGeometry = new THREE.BoxGeometry(4,4,4);
            var cubeMaterial = new THREE.MeshBasicMaterial({color: 0xdd4444,wireframe: true});
            //wireframe用于表现几何体的框架 默认为false
            var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);


            //立方体位置
            cube.position.x = -4;
            cube.position.y = 3;
            cube.position.z = 0;
            //将立方体添加进入场景
            scene.add(cube);
            //添加球体
            var sphereGeometry = new THREE.SphereGeometry(4, 20 ,20);
            var sphereMaterial = new THREE.MeshBasicMaterial({color:0xcc44cc});
            var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);


            //球体位置
            sphere.position.x = 18;
            sphere.position.y = 4;
            sphere.position.z = 2;
            //将球体加入到场景中
            scene.add(sphere);

            //柱体
            var cylinderGeometry = new THREE.CylinderGeometry( 4, 4, 5, 5);
            var material = new THREE.MeshBasicMaterial({color:0xcccc33});
            var cylinder = new THREE.Mesh(cylinderGeometry,material);

            //设定位置
            cylinder.position.x = 2;
            cylinder.position.y = 2.5;
            cylinder.position.z = 6;
            //添加柱体
            scene.add(cylinder);

            //变化相机位置以及方向
            camera.position.x = -30;
            camera.position.y = 40;
            camera.position.z = 30;
            camera.lookAt(scene.position);

            //创建canvas
            document.getElementById("WebGL-output").appendChild(renderer.domElement);
            //渲染
            renderer.render(scene,camera);
        }
        window.onload = init;
    </script>
</body>
</html>

相比起上一章的内容,我稍微变大了底部的plane 平台的面积,将柱体和球体的wireframe去掉了,这样就能看到基本材质的效果,效果如下:
three.js基本材质
emm这个材质看起来非常渣,勉强能认出是一个立体的东西,各个面的颜色都是一样的
THREE.MeshBasicMaterial 这种材质并不会对光源产生反应,所以我们要先修改材质
修改平面的材质以及所有物体对象的材质,将其都变成 THREE.MeshLambertMaterial(朗伯材质)
这种材质会对光有反应,它不包括任何镜面属性,对粗糙物体来说,是非常有用的,它不会反射出周围的环境

...
    var planeMaterial = new THREE.MeshLambertMaterial({color: 0xaaaaaa});//平面材质
...
    var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xdd4444});//立方体材质
...
    var sphereMaterial = new THREE.MeshLambertMaterial({color: 0xcc44cc});//球体材质
...
    var material = new THREE.MeshLambertMaterial({color:0xcccc33});//无棱柱材质

材质都更改完毕之后,我们再刷新一下页面:
three.js无光状态

发现一片漆黑–。从辅助线被遮掉的部分可以隐约看出有黑色的东西。那是因为没有光-。-
添加光源

            var spotLight = new THREE.SpotLight(0xffffff);//白色光线
            spotLight.position.set(-40,80,-10);//位置
            spotLight.castShadow = true;//会产生影子
            scene.add(spotLight);//添加光源进入场景

此处添加的是聚光灯光源,是从一个点出发按照一定角度散开的光源
光源有很多类型,比如环境光源AmbientLight 就是在场景中的物体都有的光源,这个光源在所有的物体表面都是随机分布的,
平行光 DirectionalLight 太阳光对于地球来说就类似于平行光
点光源 PointLight 类似于小灯泡那样四散开来的光源
除此之外还有很多,请自行寻找 光源
添加光源之后的样子:
three.js添加光源
嗯好像有那么点回事了,但是为啥还是没有影子?
原因是,虽然光源已经写了有产生影子的可能性,但是还需要三点:

  1. 哪些物体能产生影子(比如吸血鬼就没有影子哈那是因为他自己是吸血鬼,他本身自带的属性)
  2. 产生的影子放在哪(能接受影子的地方)
  3. 渲染器允许产生影子

为啥这么复杂呢,因为产生影子是一个非常消耗资源的工作,我们得知道在什么地方要产生影子,这个影子可以投到什么地方上面。
添加下面的代码:

    renderer.shadowMap.enabled = true;//渲染器将会渲染影子
    plane.receiveShadow = true;//让平面能够接受影子
    //让物体们能够有自己的影子
    cube.castShadow = true;
    sphere.castShadow = true;
    cylinder.castShadow = true;

完成后发现:
three.js影子马赛克

有影子了,但是这影子咋是马赛克影子-,-,虽然站远一点的确看不出来
但是我还是希望影子能够真实一点啊
其实是:在默认情况下为了避免影子渲染过多,设置里面就是有这样的马赛克。同时本来几何体的大小设置的就比较小=。=
所以导致这样的状况出现了。
添加代码

    spotLight.shadow.mapSize.width = 2000;  // 默认512
    spotLight.shadow.mapSize.height = 2000; // 默认512

影子在两个方向上的细致程度,越高表示越细致,到2000的时候感觉差不多可以用了
效果:
three.js添加阴影
我觉得还行。嗯 下一章应该讲到动画与 dat.GUI 组件库便于测试不同数值对表现产生的影响嗯,
(翻书。。。)

扫描二维码关注公众号,回复: 146192 查看本文章

猜你喜欢

转载自blog.csdn.net/towrabbit/article/details/80179515