THREE.js 第三部分 canvas_geometry_birds.html

WEB前端 waitig 425℃ 百度已收录 0评论

涉及到模拟鸟类飞行的状态,首先需要模拟鸟类的形态,代码如下:

var Bird = function () {

    var scope = this;

    THREE.Geometry.call(this);

    v(5, 0, 0);
    v(-5, -2, 1);
    v(-5, 0, 0);
    v(-5, -2, -1);

    v(0, 2, -6);
    v(0, 2, 6);
    v(2, 0, 0);
    v(-3, 0, 0);

    f3(0, 2, 1);
    f3(4, 7, 6);
    f3(5, 6, 7);

    this.computeFaceNormals();

    function v(x, y, z) {
        scope.vertices.push(new THREE.Vector3(x, y, z));
    }

    function f3(a, b, c) {
        scope.faces.push(new THREE.Face3(a, b, c));
    }

}

Bird.prototype = Object.create(THREE.Geometry.prototype);
Bird.prototype.constructor = Bird;

模拟出鸟类的样式。

同样需要模拟动态的鸟类飞行的状态,代码如下:

var Boid = function () {
            var vector = new THREE.Vector3();
            //加速
            var _acceleration;
            //宽度
            var _width = 500;
            //高度
            var _height = 500;
            //深度
            var _depth = 200;
            var _goal;
            //相邻之间的距离
            var _neighborhoodRedius = 100;
            //最大速度
            var _maxSpeed = 4;
            var _maxSteerForce = 0.1;
            //场景中是否有障碍
            var _avoidWalls = false;
            //位置
            this.position = new THREE.Vector3();
            //速率
            this.velocity = new THREE.Vector3();
            //加速
            _acceleration = new THREE.Vector3();

            //属性赋值
            this.setGoal = function (target) {
                _goal = target;
            };
            this.setAvoidWalls = function (value) {
                _avoidWalls = value;
            };
            this.setWorldSize = function (width, height, depth) {
                _width = width;
                _height = height;
                _depth = depth;
            };

            //运行
            this.run = function (boids) {
                if (_avoidWalls) {
                    vector.set(-_width, this.position.y, this.position.z);
                    vector = this.avoid(vector);
                    //vector中的xyz矩阵相乘倍数5 x=1 y=1 z=1 结果之后是 x=5 y=5 z=5
                    vector.multiplyScalar(5);
                    _acceleration.add(vector);

                    vector.set(_width, this.position.y, this.position.z);
                    vector = this.avoid(vector);
                    vector.multiplyScalar(5);
                    _acceleration.add(vector);

                    vector.set(this.position.x, -_height, this.position.z);
                    vector = this.avoid(vector);
                    vector.multiplyScalar(5);
                    _acceleration.add(vector);

                    vector.set(this.position.x, _height, this.position.z);
                    vector = this.avoid(vector);
                    vector.multiplyScalar(5);
                    _acceleration.add(vector);

                    vector.set(this.position.x, this.position.y, -_depth);
                    vector = this.avoid(vector);
                    vector.multiplyScalar(5);
                    _acceleration.add(vector);

                    vector.set(this.position.x, this.position.y, _depth);
                    vector = this.avoid(vector);
                    vector.multiplyScalar(5);
                    _acceleration.add(vector);

                } else {
                    this.checkBounds();
                }

                if (Math.random() > 0.5) {
                    this.flock(boids);
                }
                this.move();
            };

            this.flock = function (boids) {
                if (_goal) {
                    _acceleration.add(this.reach(_goal, 0.005));
                }
                _acceleration.add(this.alignment(boids));
                _acceleration.add(this.cohesion(boids));
                _acceleration.add(this.separation(boids));
            };

            this.move = function () {
                this.velocity.add(_acceleration);
                var l = this.velocity.length();
                if (l > _maxSpeed) {
                    this.velocity.divideScalar(l / _maxSpeed);
                }
                this.position.add(this.velocity);
                _acceleration.set(0, 0, 0);
            };

            //检测边框
            this.checkBounds = function () {
                if (this.position.x > _width)
                    this.position.x = -_width;
                if (this.position.x < -_width)
                    this.position.x = _width;
                if (this.position.y > _height)
                    this.position.y = -_height;
                if (this.position.y < -_height)
                    this.position.y = _height;
                if (this.position.z > _depth)
                    this.position.z = -_depth;
                if (this.position.z < -_depth)
                    this.position.z = _depth;
            };

            this.avoid = function (target) {
                var steer = new THREE.Vector3();
                //拷贝xyz矩阵
                steer.copy(this.position);
                //返回vector3() this.position.x - target.x this.position.y - target.y this.position.z - target.z
                steer.sub(target);
                //矩阵缩放 矩阵差的平方和 x^2 + y^2 + z^2
                steer.multiplyScalar(1 / this.position.distanceToSquared(target));
                return steer;
            };

            this.repulse = function (target) {
                //矩阵差的平方和的平方根
                var distance = this.position.distanceTo(target);
                if (distance < 150) {
                    var steer = new THREE.Vector3();
                    //返回vector3() a.x - b.x a.y - b.y a.z - b.z 两个矩阵相减
                    steer.subVectors(this.position, target);
                    steer.multiplyScalar(0,5 / distance);
                    _acceleration.add(steer);
                }
            };

            this.reach = function (target, amount) {
                var steer = new THREE.Vector3();
                steer.subVectors(target, this.position);
                steer.multiplyScalar(amount);
                return steer;
            };

            this.alignment = function (boids) {
                var count = 0;
                var velSum = new THREE.Vector3();
                for (var i = 0, il = boids.length; i < il; i++) {
                    if (Math.random() > 0.6)
                        continue;
                    var boid = boids[i];
                    var distance = boid.position.distanceTo(this.position);
                    if (distance > 0 && distance <= _neighborhoodRedius) {
                        velSum.add(boid.velocity);
                        count++;
                    }
                }
                if (count > 0) {
                    //this.multiplyScalar(1 / count)
                    velSum.divideScalar(count);
                    var l = velSum.length();
                    if (l > _maxSteerForce) {
                        velSum.divideScalar(l / _maxSteerForce);
                    }
                }
                return velSum;
            };

            this.cohesion = function (boids) {
                var count = 0;
                var posSum = new THREE.Vector3();
                var steer = new THREE.Vector3();
                for (var i = 0, il = boids.length; i < il; i++) {
                    if (Math.random() > 0.6)
                        continue;
                    var boid = boids[i];
                    var distance = boid.position.distanceTo(this.position);
                    if (distance > 0 && distance <= _neighborhoodRedius) {
                        posSum.add(boid.position);
                        count++;
                    }
                }
                if (count > 0) {
                    posSum.divideScalar(count);
                }
                steer.subVectors(posSum, this.position);
                var l = steer.length();
                if (l > _maxSteerForce) {
                    steer.divideScalar(l / _maxSteerForce);
                }
                return steer;
            };

            this.separation = function (boids) {
                var posSum = new THREE.Vector3();
                var repulse = new THREE.Vector3();
                for (var i = 0, il = boids.length; i < il; i++) {
                    if (Math.random() > 0.6)
                        continue;
                    var boid = boids[i];
                    var distance = boid.position.distanceTo(this.position);
                    if (distance > 0 && distance <= _neighborhoodRedius) {
                        repulse.subVectors(this.position, boid.position);
                        repulse.normalize();
                        repulse.divideScalar(distance);
                        posSum.add(repulse);
                    }
                }
                return posSum;
            };

        }

下面就是代码正文部分,涉及到初始化,动态效果,场景,渲染。

var stats;
        var container;
        var camera;
        var scene;
        var renderer;
        var bird;
        var birds;
        var boid;
        var boids;

        init();
        animate();

        function init() {

            var width = window.innerWidth || 0;
            var height = window.innerHeight || 0;

            container = document.createElement('div');
            document.body.appendChild(container);

            var info = document.createElement('div');
            info.style.position = 'absolute';
            info.style.top = '0px';
            info.style.width = '100%';
            info.style.padding = '5px';
            container.appendChild(info);

            //镜头设置
            var aspect = width / height;
            camera = new THREE.PerspectiveCamera(75, aspect, 1, 10000);
            camera.position.z = 450;

            //场景
            scene = new THREE.Scene();
            scene.background = new THREE.Color(0xffffff);

            birds = [];
            boids = [];

            for (var i = 0; i < 100; i++) {
                boid = boids[i] = new Boid();
                boid.position.x = Math.random() * 400 - 200;
                boid.position.y = Math.random() * 400 - 200;
                boid.position.z = Math.random() * 400 - 200;
                boid.velocity.x = Math.random() * 2 - 1;
                boid.velocity.y = Math.random() * 2 - 1;
                boid.velocity.z = Math.random() * 2 - 1;
                boid.setAvoidWalls(true);
                boid.setWorldSize(500, 500, 400);

                bird = birds[i] = new THREE.Mesh(new Bird(), new THREE.MeshBasicMaterial({color : Math.random() * 0xffffff, side : THREE.DoubleSide}));
                bird.phase = Math.floor(Math.random() * 62.83);
                scene.add(bird);
            }

            renderer = new THREE.CanvasRenderer();
            renderer.setPixelRatio(window.devicePixelRatio);
            renderer.setSize(width, height);

            document.addEventListener('mousemove', OnDocumentMouseMove, false);
            document.body.appendChild(renderer.domElement);

            //监控
            stats = new Stats();
            container.appendChild(stats.dom);

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

        }

        //窗口缩放event
        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }

        //鼠标移动event
        function OnDocumentMouseMove(event) {
            var vector = new THREE.Vector3(event.clientX - window.innerWidth / 2, - event.clientY + window.innerHeight / 2, 0);
            for (var i = 0, il = boids.length; i < il; i++) {
                boid = boids[i];
                vector.z = boid.position.z;
                boid.repulse(vector);
            }
        }

        function animate() {
            //固定格式
            requestAnimationFrame(animate);
            //监控开始
            stats.begin();
            //渲染
            render();
            //监控结束
            stats.end();
        }

        function render() {
            for (var i = 0, il = birds.length; i < il; i++) {

                boid = boids[i];
                boid.run(boids);

                bird = birds[i];
                bird.position.copy(boids[i].position);

                var color = bird.material.color;
                color.r = color.g = color.b = (500 - bird.position.z) / 1000;

                bird.rotation.y = Math.atan2(-boid.velocity.z, boid.velocity.x);
                bird.rotation.z = Math.asin(boid.velocity.y / boid.velocity.length());

                bird.phase = (bird.phase + (Math.max(0, bird.rotation.z) + 0.1)) % 62.83;
                bird.geometry.vertices[5].y = bird.geometry.vertices[4].y = Math.sin(bird.phase) * 5;
            }
            renderer.render(scene, camera);
        }

之后要涉及到airbus官网的效果。


本文由【waitig】发表在等英博客
本文固定链接:THREE.js 第三部分 canvas_geometry_birds.html
欢迎关注本站官方公众号,每日都有干货分享!
等英博客官方公众号
点赞 (0)分享 (0)