简体   繁体   English

三.js - webgl 和 canvas 渲染性能问题

[英]three.js - webgl and canvas rendering performance issue

I've created a 3d scene with below code.我用下面的代码创建了一个 3d 场景。

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>3d Model using HTML5 and three.js</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <style>
            body {
                font-family: Monospace;
                background-color: #f0f0f0;
                margin: 0px;
                overflow: hidden;
            }
        </style>
    </head>
    <body>

        <script src="three.min.js" type="text/javascript"></script>
        <script src="Curve.js" type="text/javascript"></script>
        <script src="TubeGeometry.js" type="text/javascript"></script>      
        <script src="Stats.js" type="text/javascript"></script>
        <script src="Detector.js" type="text/javascript"></script>

        <script>
        // variables
        var container, stats;

        var camera, scene, renderer, splineCamera, cameraHelper, cameraEye;

        var text, plane, tube, tubeMesh, parent;

        var targetRotation = 0;
        var targetRotationOnMouseDown = 0;

        var mouseX = 0;
        var mouseXOnMouseDown = 0;

        var windowHalfX = window.innerWidth / 2;
        var windowHalfY = window.innerHeight / 2;

        var binormal = new THREE.Vector3();
        var normal = new THREE.Vector3();



        init();                     
        animate();

        function init(){

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

            // info div
            info = document.createElement( 'div' );
            info.style.position = 'absolute';
            info.style.top = '10px';
            info.style.width = '100%';
            info.style.textAlign = 'center';
            //info.innerHTML = 'Drag to spin the cylinder<br/> You can identify cylinder face by clicking on it.</br>';         
            container.appendChild( info );

            // camera
            camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
            camera.position.set(30,10,10);
            //camera.up = new THREE.Vector3( 0, 1, 1 );

            // scene            
            scene = new THREE.Scene();
            camera.lookAt(scene.position);

            // light            
            scene.add( new THREE.AmbientLight( 0x404040 ) );
            light = new THREE.DirectionalLight( 0xffffff );
            light.position.set( 0, 1, 0 );
            scene.add( light );

            // CONTROLS
            controls = new THREE.TrackballControls( camera );

            // Grid
            geometry = new THREE.Geometry();
            geometry.vertices.push( new THREE.Vector3( - 500, 0, 0 ) );
            geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );

            for ( var i = 0; i <= 20; i ++ ) {

                line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
                line.position.z = ( i * 50 ) - 500;
                scene.add( line );

                line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
                line.position.x = ( i * 50 ) - 500;
                line.rotation.y = 90 * Math.PI / 180;
                scene.add( line );
            }

            // extrudePath, Helix Curve
            extrudePath = new THREE.SplineCurve3([
                                                new THREE.Vector3(0, 10, 10),
                                                new THREE.Vector3(10, 0, 10),
                                                new THREE.Vector3(10, 0, 0)
                                            ]);

            console.log(extrudePath);

            // Tube Geometry
            var segments = 50;
            var closed = false;
            var debug = true;
            var radiusSegments = 12;

            //alert('hello');                       
            var tube = new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed, debug);

            // Tube Mesh
            tubeMesh = THREE.SceneUtils.createMultiMaterialObject( tube, [
                new THREE.MeshLambertMaterial({
                    color: 0xff00ff,
                    opacity: tube.debug ? 0.2 : 0.8,
                    transparent: true
                }),
                new THREE.MeshBasicMaterial({
                    color: 0x000000,
                    opacity: 0.5,
                    wireframe: true
            })]);

            parent = new THREE.Object3D();
            parent.position.y = 100;

            if ( tube.debug ) tubeMesh.add( tube.debug );
            //parent.add( tubeMesh );                   
            scene.add( tubeMesh );

            // projector
            projector = new THREE.Projector();

            // renderer
            //renderer = new THREE.CanvasRenderer();
            renderer = new THREE.WebGLRenderer( { antialias: true } ); 
            renderer.setSize( window.innerWidth, window.innerHeight );
            container.appendChild( renderer.domElement );               

            // stats
            stats = new Stats();
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.top = '0px';
            container.appendChild( stats.domElement );

            document.addEventListener( 'mousedown', onDocumentMouseDown, false );
            document.addEventListener( 'mouseover', onDocumentMouseOver, false );
            document.addEventListener( 'touchstart', onDocumentTouchStart, false );
            document.addEventListener( 'touchmove', onDocumentTouchMove, false );               

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

        }           

        function onWindowResize() {

            camera.left = window.innerWidth / - 2;
            camera.right = window.innerWidth / 2;
            camera.top = window.innerHeight / 2;
            camera.bottom = window.innerHeight / - 2;
            camera.aspect = window.innerWidth / window.innerHeight;
            //camera.updateProjectionMatrix();
            renderer.setSize( window.innerWidth, window.innerHeight );

        }

        function onDocumentMouseDown( event ) {
            event.preventDefault();

            document.addEventListener( 'mousemove', onDocumentMouseMove, false );
            document.addEventListener( 'mouseup', onDocumentMouseUp, false );
            document.addEventListener( 'mouseout', onDocumentMouseOut, false );

            mouseXOnMouseDown = event.clientX - windowHalfX;
            targetRotationOnMouseDown = targetRotation;         
        }

        function onDocumentMouseMove( event ) {

            mouseX = event.clientX - windowHalfX;

            targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.02;

        }

        function onDocumentMouseUp( event ) {

            document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
            document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
            document.removeEventListener( 'mouseout', onDocumentMouseOut, false );

        }

        function onDocumentMouseOut( event ) {

            document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
            document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
            document.removeEventListener( 'mouseout', onDocumentMouseOut, false );

        }

        function onDocumentMouseOver( event ) {

            document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
            document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
            document.removeEventListener( 'mouseout', onDocumentMouseOut, false );

        }

        function onDocumentTouchStart( event ) {

            if ( event.touches.length === 1 ) {

                event.preventDefault();

                mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
                targetRotationOnMouseDown = targetRotation;

            }

        }

        function onDocumentTouchMove( event ) {
            if ( event.touches.length === 1 ) {
                event.preventDefault();
                mouseX = event.touches[ 0 ].pageX - windowHalfX;
                targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
            }
        }

        function animate() {
            requestAnimationFrame( animate );
            render();
            update();
        }

        function update()
        {
            controls.update();
            stats.update();
        }

        function render() {             
            tubeMesh.rotation.y += ( targetRotation - tubeMesh.rotation.y ) * 0.15;         
            camera.updateMatrixWorld();
            renderer.render( scene, camera );
        }           

        </script>
    </body>
</html> 

Now when I change rendering from WebGL to Canvas, the FPS drops down to 1-2 FPS from 56-57 FPS on mobile browser.现在,当我将渲染从 WebGL 更改为 Canvas 时,FPS 在移动浏览器上从 56-57 FPS 下降到 1-2 FPS。 Native browser does not display anything on page and in Opera page becomes too slow for operations.本机浏览器在页面上不显示任何内容,并且在 Opera 页面中操作变得太慢。 How do I make page operations fast with Canvas rendering or how do I enable webgl rendering on mobile browsers ?如何使用 Canvas 渲染快速进行页面操作,或者如何在移动浏览器上启用 webgl 渲染?

canvas renderer is software mode only, that means no GPU acceleration, the CPU has to do all the hard work that's why your fps drop.画布渲染器仅是软件模式,这意味着没有 GPU 加速,CPU 必须完成所有艰苦的工作,这就是您的 fps 下降的原因。

AFAIK not every mobile browser is able to use webgl renderer yet, you could give opera mobile a try it's capable of webgl. AFAIK 并非每个移动浏览器都能够使用 webgl 渲染器,您可以尝试使用 opera mobile 来支持 webgl。

加速画布渲染的一种方法是减少 TubeGeometry 中使用的段数

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM