threejs学习笔记-02

Posted weixin_43739821

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了threejs学习笔记-02相关的知识,希望对你有一定的参考价值。

6.threejs的透视投影摄像机与正交投影摄像机

<!DOCTYPE html>
<html>

<head>
    <title>threejs-008</title>
    <meta charset="UTF-8" />
    <!-- <script type="module" charset="UTF-8" src="../../libs/three.js/Three.js"></script> -->
    <style>
        body 
            margin: 0;
            overflow: hidden;
        
    </style>

</head>

<body>
    <!--我们将把threejs渲染的效果显示在这个div中-->
    <div id="webgl-output">

    </div>

    <div id="myStats"></div>

    <script type="module">
        import 
            Scene, PerspectiveCamera, OrthographicCamera, WebGLRenderer, BoxGeometry,
            MeshBasicMaterial, Mesh, PlaneGeometry, MeshLambertMaterial,
            AmbientLight, SpotLight, Vector2, AxesHelper, Color, Fog, FogExp2,
            TorusGeometry, CylinderGeometry, BufferGeometry, BufferAttribute,
            DoubleSide, WireframeGeometry, LineSegments
         from "../../libs/three.js/three.js"

        import  dat  from "../../libs/dat.gui/dat.gui.js"

        var scene = new Scene();
        //这节课了解一下threejs中的俩种相机,常用的相机是透视投影摄像机,这个相机的特点是能将场景中的物体进行近大远小效果的渲染,这种效果也更加真实,所以我们也常常使用该相机
        var camera = new PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000);
        //第一个参数表示这个摄像机中能够看到的那部分场景,可以理解为我们能看到的视角,越大则能够看到的范围越大;第二个参数表示渲染的长宽比,长宽比变小则场景变扁,变大则变高;
        //第三个参数表示距离摄像机多近的位置开始渲染,靠近摄像机的那部分不会被渲染;第四个部分表示相机从它所处位置能够看的多远,也就是场景渲染最远位置

        //下面OrthographicCamera是正交投影摄像机,其不具备将物体渲染成近大远小的效果.该相机共6个参数,第一个参数左边界,可以理解为渲染部分的左边界;第二个右边界,第三个上边界,第四个参数下边界,
        //第五个参数近端距离,可以理解为相机所处位置从改点开始渲染,调整该参数可以发现场景中靠近相机的部分场景未渲染;第六个参数远端距离,可以理解为相机所处的位置从该点停止渲染
        //var camera = new OrthographicCamera(window.innerWidth / -8, window.innerWidth / 8, window.innerHeight / 8, window.innerHeight / -8, 50, 100);

        var render = new WebGLRenderer();
        render.setClearColor(new Color(0x000000));
        render.setSize(window.innerWidth, window.innerHeight);
        render.shadowMap.enabled = true;

        document.getElementById("webgl-output").appendChild(render.domElement);

        var axes = new AxesHelper(50);
        scene.add(axes);


        var planeGeometry = new PlaneGeometry(100, 100);
        var planeMaterial = new MeshLambertMaterial( color: 0xAAAAAA );
        var plane = new Mesh(planeGeometry, planeMaterial);

        plane.rotation.x = -0.5 * Math.PI;
        plane.position.set(15, 0, 0);
        plane.receiveShadow = true;

        scene.add(plane);

        camera.position.x = -30;
        camera.position.y = 40;
        camera.position.z = 30;
        camera.lookAt(scene.position);

        var spotLight = new SpotLight(0xFFFFFF);
        spotLight.position.set(-60, 40, -65);
        spotLight.castShadow = true;
        spotLight.shadow.mapSize = new Vector2(1024, 1024);
        spotLight.shadow.camera.far = 130;
        spotLight.shadow.camera.near = 40;

        scene.add(camera);
        scene.add(spotLight);

        var ambienLight = new AmbientLight(0xcccccc);
        scene.add(ambienLight);

        //通过一个案例来观察特点,现在需要将地板plane铺上一层小方块,通过循环的方式进行,我们将这个地板分成一个个5*5的方格
        for (var i = 0; i < (planeGeometry.parameters.height / 5); i++) 
            for (var j = 0; j < (planeGeometry.parameters.width / 5); j++) 
                var cubeGeo = new BoxGeometry(4, 4, 4);//然后创建一个4*4*4的正方体
                var cubeMaterial = new MeshLambertMaterial();
                cubeMaterial.color = new Color(0, Math.random() * 0.25 + 0.5, 0);//对该材质的颜色进行随机
                var cube = new Mesh(cubeGeo, cubeMaterial);

                cube.position.x = -(planeGeometry.parameters.width / 2) + 15 + (i * 5);
                cube.position.y = 2;
                cube.position.z = -(planeGeometry.parameters.height / 2) + 5 + (j * 5);

                scene.add(cube);
            
        //正交投影摄像机看到的每个正方体都是一样大小的,而透视投影摄像机是近大远小                                     

        var ctrlObj = new function () //为了更加方便的查看俩种摄像机的表现效果,我们通过辅助库dat.GUI来进行
            this.showText = "透视投影摄像机";//我们先创建一个保存相机类型的属性
            this.changeCamera = function () //再封装一个切换相机的方法
                if (camera instanceof PerspectiveCamera)//我们先对摄像机的类型进行判断
                //若是透视投影摄像机,则我们将摄像机类型修改为正交投影摄像机
                    camera = new OrthographicCamera(window.innerWidth / -16, window.innerWidth / 16, window.innerHeight / 16, window.innerHeight / -16, -200, 500);
                    camera.position.x = -30;//对相机的位置和视角进行调整并修改相机类型文本
                    camera.position.y = 40;
                    camera.position.z = 30;
                    camera.lookAt(scene.position);
                    this.showText = "正交投影摄像机";
                
                else//否则我们将相机类型切换为透视投影摄像机
                
                    camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
                    camera.position.x = -30;//对相机的位置和视角进行调整并修改相机类型文本
                    camera.position.y = 40;
                    camera.position.z = 30;
                    camera.lookAt(scene.position);
                    this.showText = "透视投影摄像机";
                
            
        

        var ctrl = new dat.GUI();//然后通过辅助库将属性功能显示到浏览器中
        ctrl.add(ctrlObj, "showText").listen();//这里新的方法listen,该方法可以在我们修改文本后显示出对应的文本
        ctrl.add(ctrlObj, "changeCamera");
        //接下来看一下相机的lookAt方法,该方法表示摄像机所指向的位置,我们先创建一个想要指向的正方体
        var geometry = new BoxGeometry(8, 8, 8);
        var material = new MeshLambertMaterial( color: 0xff2288 );
        var cube = new Mesh(geometry, material);
        cube.position.x = 0;
        cube.position.y = 8;
        cube.position.z = 0;
        scene.add(cube);

        renderScene();

        var pos = 0;//接着我们声明一个位置对象,用于保存位置的变化量
        function renderScene() 
            pos += 0.01;//再修改变化量值
            cube.position.x = 10 + (100 * (Math.sin(pos)));//通过正弦函数使得该正方体能够在x轴方向上来回移动
            camera.lookAt(cube.position);//接着我们调用相机的lookAt方法使得相机能够指向该正反体
            requestAnimationFrame(renderScene);
            render.render(scene, camera);
        


        window.addEventListener('resize', onWindowResize, false);

        function onWindowResize() 
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            render.setSize(window.innerWidth, window.innerHeight);
        
    </script>

</body>

</html>

渲染效果图:

7.threejs的AmbientLight光源和SpotLight聚光灯光源

<!DOCTYPE html>
<html>

<head>
    <title>threejs-009</title>
    <meta charset="UTF-8" />
    <style>
        body 
            margin: 0;
            overflow: hidden;
        
    </style>

</head>

<body>
    <!--我们将把threejs渲染的效果显示在这个div中-->
    <div id="webgl-output">

    </div>

    <div id="myStats"></div>

    <script type="module">
        //拿出我们之前的案例,我们在场景中添加了俩个光源,光源是渲染场景中不可或缺的一部分,threejs中有许多不同类型的光源,每种光源都有不同行为和用法
        //本节课重点介绍之前用过的AmbientLight基本光源和SpotLight聚光灯光源
        //我们将聚光灯光源从场景中去除,发现基本光源会均匀的照亮场景中所有物体,同时原本带有阴影效果的正方体此时的阴影也没有了,说明基本光源不会生成阴影
        //通常我们不会将AmbientLight光源作为场景中唯一的光源,其通常用于柔话生硬的颜色和阴影,AmbientLight一共有俩个构造参数,第一个构造参数是光源的颜色,第二个构造参数是光照强度,默认是1

        //聚光灯光源是最常用的光源之一,是一种具有锥形效果的光源,和手电筒类似,可以配置它随着距离的增大而逐渐变弱,并且可以生成阴影,聚光灯源SpotLight有6个构造参数,第一个参数是光照颜色,第二个是光照强度,第三个
        //参数是光源发出光的最大距离,第四个是光线散射角度,第五个是聚光锥的半影衰减百分比,第六个是沿着光照距离的衰减量
        import 
            Scene, PerspectiveCamera, OrthographicCamera, WebGLRenderer, BoxGeometry,
            MeshBasicMaterial, Mesh, PlaneGeometry, MeshLambertMaterial,
            AmbientLight, SpotLight, Vector2, AxesHelper, Color, Fog, FogExp2,
            TorusGeometry, CylinderGeometry, BufferGeometry, BufferAttribute,
            DoubleSide, WireframeGeometry, LineSegments,
            SpotLightHelper, CameraHelper
         from "../../libs/three.js/three.js"

        import  dat  from "../../libs/dat.gui/dat.gui.js"

        var scene = new Scene();
        var camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

        var render = new WebGLRenderer();
        render.setClearColor(new Color(0x000000));
        render.setSize(window.innerWidth, window.innerHeight);
        render.shadowMap.enabled = true;

        document.getElementById("webgl-output").appendChild(render.domElement);

        var axes = new AxesHelper(50);
        scene.add(axes);


        var planeGeometry = new PlaneGeometry(100, 100);
        var planeMaterial = new MeshLambertMaterial( color: 0xAAAAAA );
        var plane = new Mesh(planeGeometry, planeMaterial);

        plane.rotation.x = -0.5 * Math.PI;
        plane.position.set(15, 0, 0);
        plane.receiveShadow = true;

        scene.add(plane);

        camera.position.x = -30;//为了更清晰显示效果,将相机位置修改
        camera.position.y = 140;
        camera.position.z = 30;
        camera.lookAt(scene.position);

        var spotLight = new SpotLight(0xFFFFFF);
        spotLight.position.set(-60, 30, -65);//再修改聚光灯位置
        spotLight.castShadow = true;
        spotLight.shadow.mapSize = new Vector2(1024, 1024);
        spotLight.shadow.camera.far = 130;
        spotLight.shadow.camera.near = 40;

        scene.add(camera);
        scene.add(spotLight);

        //为了能够对后面的属性有更加详细的理解,我们需要添加俩个辅助类
        var lightHelper = new SpotLightHelper(spotLight);//我们先通过聚光灯对象创建一个SpotLightHelper对象
        scene.add(lightHelper);//并添加到场景中

        var shadowCameraHelper = new CameraHelper(spotLight.shadow.camera);//再通过创建一个CameraHelper对象
        scene.add(shadowCameraHelper);//同样添加到场景中,别忘了import这俩个模块
        //同时为了能够在修改光源属性后这俩个辅助类型能够做出对应的变化,我们需要在renderScene中对这俩个对象进行刷新
        //刷新后我们可以清楚的看到辅助线,这个辅助线可以显示聚光灯的光效最大距离、光线散射角度等属性

        var ambienLight = new AmbientLight(0xcccccc);
        //scene.add(ambienLight); 

        //为了更加清晰的演示光源构造函数参数的效果,我们依然可以通过辅助库dat.GUI的方法进行属性的修改
        var ctrlObj = 
            //AmbientLight 
            ambienLightintensity: 1,//创建一个对象保存基本光源的光照强度,在下面的renderScene中对属性进行修改
            ambienLightColor: 0xcccccc,
            //SpotLight
            spotLightintensity: 1,//其他属性同理
            spotLightColor: 0xFFFFFF,
            spotLightDistance: 0,
            spotLightAngle: Math.PI / 3,
            spotPenumbra: 0,
            spotDecay: 0,
        

        var ctrl = new dat.GUI();
        //为了在dat.GUI控制模块中进行区分AmbienLight和SpotLight,我们可以通过调用addFolder方法,创建俩个基本光源分组,这样页面菜单里就有俩个下拉分组
        var ambienLightFolder = ctrl.addFolder("ambienLight");//创造第一个区域分组
        ambienLightFolder.add(ctrlObj, "ambienLightintensity", 0, 5);//将原先的俩个属性加入到分组
        //这里我们不在使用add方法而是addColor方法,该方法会在控制菜单模块添加一个选项,在这个选项中能够直接传入颜色变量,
        //通过onChange方法告诉控制菜单在每次颜色改变的时候调用传入的函数,所以颜色属性我们不用在renderScene中进行更新,用onChange触发修改就行,但是还是要有requestAnimationFrame(renderScene)来捕捉修改动画帧,这点切记
        ambienLightFolder.addColor(ctrlObj, "ambienLightColor").onChange(function (clr) 
            ambienLight.color = new Color(clr);//在此处我们需要修改的是ambienLight光源的颜色值
        );

        var spotLightFolder = ctrl.addFolder("spotLight");//创造第二个聚光灯光源折叠区域
        spotLightFolder.add(ctrlObj, "spotLightintensity", 0, 5);//同样的方法添加到dat.GUI中
        spotLightFolder.addColor(ctrlObj, "spotLightColor").onChange(function (clr) 
            spotLight.color = new Color(clr);
        );

        spotLightFolder.add(ctrlObj, "spotLightDistance", 0, 1000).onChange(function (dis) 
            spotLight.distance = dis;//下面的属性同理
        )以上是关于threejs学习笔记-02的主要内容,如果未能解决你的问题,请参考以下文章

threejs学习笔记-02

ThreeJS-聚光等衰减(二十一)

THREEJS案例(11)- 光照阴影

一大波ThreeJS学习笔记来啦

three.js学习:初学three.js,从立方体开始

threejs学习day3:几何形状