欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Three.js使用第一视角控制器FirstPersonControls控制相机(代码教程)

程序员文章站 2022-04-25 17:29:16
简介 顾名思义,通过第一视角控制器你可以像第一视角射击游戏那样控制摄像机。鼠标用于控制视角,键盘用于控制移动角色。本人感觉最类似的效果就是cs游戏死亡后,能够随意漂浮的感觉。...

简介

顾名思义,通过第一视角控制器你可以像第一视角射击游戏那样控制摄像机。鼠标用于控制视角,键盘用于控制移动角色。本人感觉最类似的效果就是cs游戏死亡后,能够随意漂浮的感觉。

案例实现

Three.js使用第一视角控制器FirstPersonControls控制相机(代码教程)

首先,引入相关库文件,其中,我们额外引入了一个处理颜色的库叫chroma.js库。在这里,就不详细介绍这个库了,如果需要相关内容,请查看其官方文档:https://gka.github.io/chroma.js/#color-rgba

<script src="/lib/libs/chroma.js"></script> 
<script src="/lib/js/controls/firstpersoncontrols.js"></script>

其次,就是在实例化相机以后,通过camera实例化相关对象,然后进行相关配置:

controls = new three.firstpersoncontrols(camera);
controls.lookspeed = 0.2; //鼠标移动查看的速度
controls.movementspeed = 20; //相机移动速度
controls.nofly = true;
controls.constrainvertical = true; //约束垂直
controls.verticalmin = 1.0;
controls.verticalmax = 2.0;
controls.lon = -100; //进入初始视角x轴的角度
controls.lat = 0; //初始视角进入后y轴的角度

最后,需要在每次渲染里面更新控制器:

var clock = new three.clock();

function animate() {
    render();

    //更新性能插件
    stats.update();

    //更新控制器
    controls.update(clock.getdelta());

    requestanimationframe(animate);
}

该控件的相关控制方法:

操控 效果
移动鼠标 向四周看
上、下、左、右方向键 向上、下、左、右移动
w 向前移动
a 向左移动
s 向后移动
d 向右移动
r 向上移动
f 向下移动
q 停止移动

案例代码

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>title</title>
    <style type="text/css">
        html, body {
            margin: 0;
            height: 100%;
        }

        canvas {
            display: block;
        }

    </style>
</head>

<body onload="draw();">

</body>
<script src="/lib/three.js"></script>
<script src="/lib/js/loaders/objloader.js"></script>
<script src="/lib/js/loaders/mtlloader.js"></script>
<script src="/lib/libs/chroma.js"></script> <!--处理颜色的库-->
<script src="/lib/js/controls/firstpersoncontrols.js"></script>
<script src="/lib/js/libs/stats.min.js"></script>
<script src="/lib/js/libs/dat.gui.min.js"></script>
<script src="/lib/js/detector.js"></script>

<script>
    var renderer;
    function initrender() {
        renderer = new three.webglrenderer({antialias:true});
        renderer.setsize(window.innerwidth, window.innerheight);
        renderer.sortobjects = false;
        //告诉渲染器需要阴影效果
        document.body.appendchild(renderer.domelement);
    }

    var camera;
    function initcamera() {
        camera = new three.perspectivecamera(45, window.innerwidth/window.innerheight, 0.1, 10000);
        camera.position.set(0, 10, 50);
        camera.lookat(new three.vector3(0,0,0));
    }

    var scene;
    function initscene() {
        scene = new three.scene();
    }

    //初始化dat.gui简化试验流程
    var gui;
    function initgui() {
        //声明一个保存需求修改的相关数据的对象
        gui = {
        };
        var datgui = new dat.gui();
        //将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值)
    }

    var light;
    function initlight() {
        scene.add(new three.ambientlight(0x444444));

        light = new three.pointlight(0xffffff);
        light.position.set(0,50,0);

        //告诉平行光需要开启阴影投射
        light.castshadow = true;

        scene.add(light);
    }

    function initmodel() {

        //辅助工具
        var helper = new three.axeshelper(50);
        scene.add(helper);

        var mtlloader = new three.mtlloader();
        mtlloader.setpath('/lib/assets/models/');
        //加载mtl文件
        mtlloader.load('city.mtl', function (material) {
            var objloader = new three.objloader();
            //设置当前加载的纹理
            objloader.setmaterials(material);
            objloader.setpath('/lib/assets/models/');
            objloader.load('city.obj', function (object) {
                //设置颜色的取值范围
                var scale = chroma.scale(['yellow', '008ae5']);

                console.log(object);

                //重新设置纹理颜色
                setrandomcolors(object, scale);

                //将模型缩放并添加到场景当中
                scene.add(object);
            })
        });
    }

    //添加纹理的方法
    function setrandomcolors(object, scale) {
        //获取children数组
        var children = object.children;

        //如果当前模型有子元素,则遍历子元素
        if (children && children.length > 0) {
            children.foreach(function (e) {
                setrandomcolors(e, scale)
            });
        }
        else {
            if (object instanceof three.mesh) {
                //如果当前的模型是楼层,则设置固定的颜色,并且透明化
                if(array.isarray(object.material)){
                    for(var i = 0; i<object.material.length; i++){
                        var material = object.material[i];
                        var color = scale(math.random()).hex();
                        if (material.name.indexof("building") === 0) {
                            material.color = new three.color(color);
                            material.transparent = true;
                            material.opacity = 0.7;
                            material.depthwrite = false;
                        }
                    }
                }
                // 如果不是场景组,则给当前mesh添加纹理
                else{
                    //随机当前模型的颜色
                    object.material.color = new three.color(scale(math.random()).hex());
                }
            }
        }
    }

    //初始化性能插件
    var stats;
    function initstats() {
        stats = new stats();
        document.body.appendchild(stats.dom);
    }

    var controls;
    function initcontrols() {

        controls = new three.firstpersoncontrols(camera);
        controls.lookspeed = 0.2; //鼠标移动查看的速度
        controls.movementspeed = 20; //相机移动速度
        controls.nofly = true;
        controls.constrainvertical = true; //约束垂直
        controls.verticalmin = 1.0;
        controls.verticalmax = 2.0;
        controls.lon = -100; //进入初始视角x轴的角度
        controls.lat = 0; //初始视角进入后y轴的角度
    }

    function render() {

        renderer.clear();
        renderer.render( scene, camera );
    }

    //窗口变动触发的函数
    function onwindowresize() {

        camera.aspect = window.innerwidth / window.innerheight;
        camera.updateprojectionmatrix();
        render();
        renderer.setsize( window.innerwidth, window.innerheight );

    }

    var clock = new three.clock();

    function animate() {
        //更新控制器
        render();

        //更新性能插件
        stats.update();

        controls.update(clock.getdelta());

        requestanimationframe(animate);
    }

    function draw() {
        //兼容性判断
        if ( ! detector.webgl ) detector.addgetwebglmessage();

        initgui();
        initrender();
        initscene();
        initcamera();
        initlight();
        initmodel();
        initcontrols();
        initstats();

        animate();
        window.onresize = onwindowresize;
    }
</script>
</html>