Three.js创建运动立体几何体示例

时间:2022-06-07 04:26:38

效果图

Three.js创建运动立体几何体示例

安装

npm install three

帧率统计工具

// 监听动画帧率

var Stats = function () {

    var mode = 0;

    var container = document.createElement( 'div' );
    container.style.cssText = 'position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000';
    container.addEventListener( 'click', function ( event ) {

        event.preventDefault();
        showPanel( ++ mode % container.children.length );

    }, false );

    //

    function addPanel( panel ) {

        container.appendChild( panel.dom );
        return panel;

    }

    function showPanel( id ) {

        for ( var i = 0; i < container.children.length; i ++ ) {

            container.children[ i ].style.display = i === id ? 'block' : 'none';

        }

        mode = id;

    }

    //

    var beginTime = ( performance || Date ).now(), prevTime = beginTime, frames = 0;

    var fpsPanel = addPanel( new Stats.Panel( 'FPS', '#0ff', '#002' ) );
    var msPanel = addPanel( new Stats.Panel( 'MS', '#0f0', '#020' ) );

    if ( self.performance && self.performance.memory ) {

        var memPanel = addPanel( new Stats.Panel( 'MB', '#f08', '#201' ) );

    }

    showPanel( 0 );

    return {

        REVISION: 16,

        dom: container,

        addPanel: addPanel,
        showPanel: showPanel,

        begin: function () {

            beginTime = ( performance || Date ).now();

        },

        end: function () {

            frames ++;

            var time = ( performance || Date ).now();

            msPanel.update( time - beginTime, 200 );

            if ( time >= prevTime + 1000 ) {

                fpsPanel.update( ( frames * 1000 ) / ( time - prevTime ), 100 );

                prevTime = time;
                frames = 0;

                if ( memPanel ) {

                    var memory = performance.memory;
                    memPanel.update( memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576 );

                }

            }

            return time;

        },

        update: function () {

            beginTime = this.end();

        },

        // Backwards Compatibility

        domElement: container,
        setMode: showPanel

    };

};

Stats.Panel = function ( name, fg, bg ) {

    var min = Infinity, max = 0, round = Math.round;
    var PR = round( window.devicePixelRatio || 1 );

    var WIDTH = 80 * PR, HEIGHT = 48 * PR,
            TEXT_X = 3 * PR, TEXT_Y = 2 * PR,
            GRAPH_X = 3 * PR, GRAPH_Y = 15 * PR,
            GRAPH_WIDTH = 74 * PR, GRAPH_HEIGHT = 30 * PR;

    var canvas = document.createElement( 'canvas' );
    canvas.width = WIDTH;
    canvas.height = HEIGHT;
    canvas.style.cssText = 'width:80px;height:48px';

    var context = canvas.getContext( '2d' );
    context.font = 'bold ' + ( 9 * PR ) + 'px Helvetica,Arial,sans-serif';
    context.textBaseline = 'top';

    context.fillStyle = bg;
    context.fillRect( 0, 0, WIDTH, HEIGHT );

    context.fillStyle = fg;
    context.fillText( name, TEXT_X, TEXT_Y );
    context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT );

    context.fillStyle = bg;
    context.globalAlpha = 0.9;
    context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT );

    return {

        dom: canvas,

        update: function ( value, maxValue ) {

            min = Math.min( min, value );
            max = Math.max( max, value );

            context.fillStyle = bg;
            context.globalAlpha = 1;
            context.fillRect( 0, 0, WIDTH, GRAPH_Y );
            context.fillStyle = fg;
            context.fillText( round( value ) + ' ' + name + ' (' + round( min ) + '-' + round( max ) + ')', TEXT_X, TEXT_Y );

            context.drawImage( canvas, GRAPH_X + PR, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT, GRAPH_X, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT );

            context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT );

            context.fillStyle = bg;
            context.globalAlpha = 0.9;
            context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, round( ( 1 - ( value / maxValue ) ) * GRAPH_HEIGHT ) );

        }

    };

};

export { Stats as default };

变量控制GUI

创建一个小窗口,能够方便的控制变量

安装 npm install --save dat.gui 

demo

<template>
    <div>
        <div id="Stats-output"></div>
        <div ref="ThreeBox"></div>
    </div>
</template>

<script>
/* eslint-disable */
import * as THREE from 'three';
import Stats from '../assets/js/stats.js';
import * as dat from 'dat.gui';

var scene = new THREE.Scene(); // 场景,用来保存渲染的物体
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 ); // 相机,定义渲染的物体
var mousecontrols = new THREE.OrbitControls(camera);

var renderer = new THREE.WebGLRenderer(); // 渲染器,定义角度,WebGLRenderer表示使用显卡来渲染场景
renderer.setClearColor(0xEEEEEE); // 设置背景颜色
renderer.setSize( window.innerWidth, window.innerHeight ); // 设置背景大小
renderer.shadowMap.enabled = true; // 开启阴影映射

var axes= new THREE.AxesHelper(20); // 创建坐标轴
scene.add(axes);

var spotLight = new THREE.SpotLight(0xffffff); // 创建光源
spotLight.position.set(-40, 60, -10);
spotLight.castShadow = true; // 此光源开启阴影效果
scene.add(spotLight);

var planeGeometry = new THREE.PlaneGeometry(60,20,1,1);  // 创建平面,宽60高20
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xffffff}); // 设置平面的材质,MeshBasicMaterial材质不会对光源产生效果
var plane = new THREE.Mesh(planeGeometry,planeMaterial); // 将平面放置到Mesh对象中
plane.rotation.x = -0.5*Math.PI; 
plane.position.x = 15;
plane.position.y = 0;
plane.position.z = 0;
plane.receiveShadow = true; // 生成阴影
scene.add(plane);

var cubeGeometry = new THREE.CubeGeometry(4,4,4); // 创建立方体
var cubeMaterial = new THREE.MeshLambertMaterial({color : 0xff0000}); // 可以添加,wireframe: true表示线框
var cube= new THREE.Mesh(cubeGeometry, cubeMaterial );
cube.position.x = -4;
cube.position.y = 3;
cube.position.z = 0;
cube.castShadow = true; 
scene.add(cube);

var sphereGeometry = new THREE.SphereGeometry(4,20,20); // 创建球体
var sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});
var sphere= new THREE.Mesh(sphereGeometry,sphereMaterial);
sphere.position.x = 20;
sphere.position.y = 4 ;
sphere.position.z = 2 ;
sphere.castShadow = true; 
scene.add (sphere) ;

camera.position.x = -30;
camera.position.y = 40;
camera.position.z = 30;

camera.lookAt(scene.position); // 场景中心

let step = 0;
const gui = new dat.GUI(); // 创建gui工具,控制变量
var controls= new function() {
    this.rotationSpeed = 0.02;
    this.bouncingSpeed = 0.03 ; 
}
gui.add(controls,'rotationSpeed', 0, 0.5); 
gui.add(controls,'bouncingSpeed', 0, 0.5); 

export default {
    mounted() {
        this.$refs.ThreeBox.appendChild( renderer.domElement );
        renderer.render(scene, camera );
        this.renderScene();
    },
    methods: {
        renderScene(){
            let stats = this.initStats(); // stats.js代码如下,用来监听动画帧率的

            stats.begin();

            cube.rotation.x += 0.02; // 旋转正方体
            cube.rotation.y += 0.02;
            cube.rotation.z += 0.02;

            step+=0.04; // 球运动的速度
            sphere.position.x = 20+(10*(Math.cos(step)));
            sphere.position.y = 2+(10*Math.abs(Math.sin(step)));

            renderer.render(scene, camera);
            stats.end();

            requestAnimationFrame(this.renderScene); // 重画场景,从而方便应用动画效果
        },

        initStats () {
            var stats= new Stats ();
            stats.showPanel( 1 );
            this.$refs.StatsBox.appendChild(stats.dom);
            return stats;
        }
    }
}
</script>