第1话 使用帧率监测器和dat.gui来查看当前页面刷新的帧率

第一个threejs程序

<!DOCTYPE html>
<html>
<head>
<title>第一个threejs程序</title>
<script type="text/javascript" src="../libs/three.js"></script>
</head>
<body>
<div id="threejs-example">
</div>
<script type="text/javascript">
    function init() {
        // 新建场景
        var scene = new THREE.Scene();

        // 设置相机
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // 构造渲染器,这里使用WebGL渲染器
        var renderer = new THREE.WebGLRenderer();
        // 设置背景色
        renderer.setClearColor(new THREE.Color(0xEEEEEE));
        renderer.setSize(window.innerWidth, window.innerHeight);

        // 向场景中添加坐标轴
        var axes = new THREE.AxisHelper(20);
        scene.add(axes);

        // 新建一个平面plane
        var planeGeometry = new THREE.PlaneGeometry(60, 20);    // 长60,宽20的平面
        var planeMaterial = new THREE.MeshBasicMaterial({color: 0xcccccc});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);

        // 确定平面坐标
        plane.rotation.x = -0.5 * Math.PI;  // 沿x轴旋转90度
        plane.position.x = 15;  // 在x,y,z三个方向上的偏移
        plane.position.y = 0;
        plane.position.z = 0;

        // 向场景中添加平面
        scene.add(plane);

        // 创建一个方块cube
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshBasicMaterial({color: 0xff0000, wireframe: true});  // 打开wireframe则可以看到物体的结构框架
        var cube = new THREE.Mesh(cubeGeometry, cubeMaterial);

        // 确定方块坐标
        cube.position.x = -4;
        cube.position.y = 3;
        cube.position.z = 0;

        scene.add(cube);

        // 创建一个球体sphere
        var sphereGeometry = new THREE.SphereGeometry(4, 20, 20);
        var sphereMaterial = new THREE.MeshBasicMaterial({color: 0x7777ff, wireframe: true});
        var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);

        // 确定球体位置
        sphere.position.x = 20;
        sphere.position.y = 4;
        sphere.position.z = 2;

        // 向场景中添加球体
        scene.add(sphere);

        // 确定相机位置
        camera.position.x = -30;
        camera.position.y = 40;
        camera.position.z = 30;
        camera.lookAt(scene.position);      // 使用lookAt()函数将相机指向场景的中心

        document.getElementById("threejs-example").appendChild(renderer.domElement);
        renderer.render(scene, camera);     // 渲染场景
    }
    window.onload = init;
</script>
</body>
</html>

请添加图片描述

渲染阴影——添加光源并更改材质

MeshBasicMaterial基本材质不能对场景中的光源产生反应,它只能按照指定的颜色渲染物体,threejs中提供了两种材质可以对光源产生反应——MeshLambertMaterial和MeshPhongMaterial材质。

由于渲染阴影要消耗大量的计算资源,因此默认情况下threejs并不生成阴影。
要使threejs渲染出阴影效果,除了打开threejs的阴影渲染许可(renderer.shadowMapEnabled = true)外,还要确定哪些物体是接收阴影的,哪些物体是发出阴影的,分别打开相应物体Mesh对象的receiveShadow和castShadow设置。

另外,还要使场景中的光源渲染出阴影。

<!DOCTYPE html>
<html>
<head>
<title>第一个threejs程序</title>
<script type="text/javascript" src="../libs/three.js"></script>
</head>
<body>
<div id="threejs-example"></div>
<script type="text/javascript">
    function init() {
        var scene = new THREE.Scene();

        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE));
        renderer.setSize(window.innerWidth, window.innerHeight);

         // 使threejs允许场景渲染出阴影(由于渲染阴影要消耗大量的计算资源,因此默认情况下threejs并不生成阴影)
         renderer.shadowMapEnabled = true;

        var axes = new THREE.AxisHelper(20);
        scene.add(axes);

        // 新建一个平面plane
        var planeGeometry = new THREE.PlaneGeometry(60, 20);    // 设置物体材质为MeshLambertMaterial,它可以对光源做出反应
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);

        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);

        // 创建一个方块cube
        var cubeGeometry = new THREE.BoxGeometry(4, 4, 4);
        // var cubeMaterial = new THREE.MeshBasicMaterial({color: 0xff0000, wireframe: true});
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
        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);

        // 创建一个球体sphere
        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);  // 使用lookAt函数将相机指向场景的中心

        // 向场景中添加光源
        var spotLight = new THREE.SpotLight( 0xffffff );
        spotLight.position.set( -40, 60, -10 );
        spotLight.castShadow = true;                // 让聚光灯光源发出阴影
        scene.add(spotLight);

        document.getElementById("threejs-example").appendChild(renderer.domElement);
        renderer.render(scene, camera);
    }
    window.onload = init;
</script>
</body>
</html>

请添加图片描述

持续渲染场景和开启渲染帧率监测器stats

可以利用requestAnimationFrame()写一个函数renderScene()达到持续渲染场景的效果,而要开启渲染帧率监测器,则需要引入stats.js,初始化stats对象后,需要在renderScene()函数中使用update()更新帧率。

<!DOCTYPE html>
<html>
<head>
<title>第一个threejs程序</title>
<script type="text/javascript" src="../libs/three.js"></script>
<script type="text/javascript" src="../libs/stats.js"></script>
</head>
<body>

<div id="threejs-example"></div>
<div id="Stats-output"></div>

<script type="text/javascript">
    function init() {
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE));
        renderer.setSize(window.innerWidth, window.innerHeight);

         renderer.shadowMapEnabled = true;

        var axes = new THREE.AxisHelper(20);
        scene.add(axes);

        // 新建一个平面plane
        var planeGeometry = new THREE.PlaneGeometry(60, 20);
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);

        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.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
        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);

        // 创建一个球体sphere
        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);

        var spotLight = new THREE.SpotLight( 0xffffff );
        spotLight.position.set( -40, 60, -10 );
        spotLight.castShadow = true;
        scene.add(spotLight);

        document.getElementById("threejs-example").appendChild(renderer.domElement);

        // 利用requestAnimationFrame()写一个函数达到持续渲染场景的效果
        var stats = initStats();    // stats的初始化必须在renderScene()调用之前(因为renderScene()函数中要使用stats实例对象)
        renderScene();

        function renderScene() {
            stats.update();   // 刷新帧率
            renderer.render(scene, camera);
            requestAnimationFrame(renderScene);
        }

        function initStats() {
            // 初始化帧率监测器
            var stats = new Stats();

            stats.setMode(0); // 模式值: 0: fps, 1: ms

            // 把帧率监测器放在屏幕的左边
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';

            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

请添加图片描述

添加动画交互

场景持续渲染时就可以在场景中添加一些交互动画了,在renderScene()函数中添加更改方块旋转角度和更改球体坐标的代码,即可实现动画。

<!DOCTYPE html>
<html>
<head>
<title>第一个threejs程序</title>
<script type="text/javascript" src="../libs/three.js"></script>
<script type="text/javascript" src="../libs/stats.js"></script>
</head>
<body>

<div id="threejs-example"></div>
<div id="Stats-output"></div>

<script type="text/javascript">
    function init() {
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE));
        renderer.setSize(window.innerWidth, window.innerHeight);

         renderer.shadowMapEnabled = true;

        var axes = new THREE.AxisHelper(20);
        scene.add(axes);

        // 新建一个平面plane
        var planeGeometry = new THREE.PlaneGeometry(60, 20);
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);

        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.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
        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);

        // 创建一个球体sphere
        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);

        var spotLight = new THREE.SpotLight( 0xffffff );
        spotLight.position.set( -40, 60, -10 );
        spotLight.castShadow = true;
        scene.add(spotLight);

        document.getElementById("threejs-example").appendChild(renderer.domElement);

        var stats = initStats();
        renderScene();
        var step = 0;
        function renderScene() {
            stats.update();

            // 方块旋转
            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);
            requestAnimationFrame(renderScene);
        }

        function initStats() {
            var stats = new Stats();
            stats.setMode(0);

            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';

            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

请添加图片描述

使用dat.GUI库

通过引入dat.gui.js库来生成一个控制界面,通过滑动条来控制方块的旋转速度和球体的弹跳速度。

<!DOCTYPE html>
<html>
<head>
<title>第一个threejs程序</title>
<script type="text/javascript" src="../libs/three.js"></script>
<script type="text/javascript" src="../libs/stats.js"></script>
<script type="text/javascript" src="../libs/dat.gui.js"></script>
</head>
<body>

<div id="threejs-example"></div>
<div id="Stats-output"></div>

<script type="text/javascript">
    function init() {
        var scene = new THREE.Scene();
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        var renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(new THREE.Color(0xEEEEEE));
        renderer.setSize(window.innerWidth, window.innerHeight);

        renderer.shadowMapEnabled = true;

        var axes = new THREE.AxisHelper(20);
        scene.add(axes);

        // 新建一个平面plane
        var planeGeometry = new THREE.PlaneGeometry(60, 20);
        var planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});
        var plane = new THREE.Mesh(planeGeometry, planeMaterial);

        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.BoxGeometry(4, 4, 4);
        var cubeMaterial = new THREE.MeshLambertMaterial({color: 0xff0000});
        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);

        // 创建一个球体sphere
        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);

        var spotLight = new THREE.SpotLight( 0xffffff );
        spotLight.position.set( -40, 60, -10 );
        spotLight.castShadow = true;
        scene.add(spotLight);

        document.getElementById("threejs-example").appendChild(renderer.domElement);

        var controls = new function () {
            this.rotationSpeed = 0.02;
            this.bouncingSpeed = 0.03;
        };

        var gui = new dat.GUI();
        gui.add(controls, 'rotationSpeed', 0, 0.5); // 取值范围是0 -- 0.5
        gui.add(controls, 'bouncingSpeed', 0, 0.5); // GUI控制变量bouncingSpeed的取值

        var stats = initStats();
        var step = 0;

        renderScene();      // 在renderScene()函数中使用到的变量必须在调用点之前被定义
        function renderScene() {
            stats.update();

            // 使用dat.GUI控制方块的旋转速度
            cube.rotation.x += controls.rotationSpeed;
            cube.rotation.y += controls.rotationSpeed;
            cube.rotation.z += controls.rotationSpeed;

            // 使用dat.GUI控制球的弹跳速度
            step += controls.bouncingSpeed;
            sphere.position.x = 20 + ( 10 * (Math.cos(step)));
            sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(step)));

            renderer.render(scene, camera);
            requestAnimationFrame(renderScene);
        }

        function initStats() {
            var stats = new Stats();
            stats.setMode(0);

            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';

            document.getElementById("Stats-output").appendChild(stats.domElement);
            return stats;
        }
    }
    window.onload = init;
</script>
</body>
</html>

请添加图片描述

<think>好的,我现在需要帮助用户了解如何检测手机的屏幕刷新应用程序的帧率。根据用户提供的引用内容,我需要先整理相关的信息,并结合自己的知识来给出清晰的步骤方法。 首先,关于检测屏幕刷新率,用户提供的引用中提到可以通过编程方式获取屏幕刷新率,例如在Android中使用Display.getRefreshRate()方法。这应该是一个关键点。另外,引用[2]提到60Hz更高刷新率的区别,可能用户需要知道如何在实际操作中查看当前屏幕的设置,比如在手机设置中查看显示选项是否有刷新率选项,比如60Hz或120Hz。 然后是检测应用程序的帧率。引用[4]提到使用Android Studio的Profiler、Systrace、GameBench等工具。这里需要详细说明这些工具的使用方法,特别是Profiler中的GPU部分可以显示帧率。另外,开发者选项中的“显示刷新频率”也是一个直接查看当前屏幕刷新率的方法,但可能不是所有手机都支持。 需要注意的是,不同的手机品牌可能有不同的设置路径,比如小米、华为等可能在显示设置里有刷新率选项。而应用内检测可能需要代码实现,比如SurfaceView的帧回调或者Choreographer监听帧时间。 另外,用户的问题可能分为普通用户开发者两种角度,需要区分回答。普通用户可能更倾向于通过系统设置或简单工具查看,而开发者则需要详细的调试工具代码方法。 需要检查是否有遗漏的信息,比如引用[3]提到硬件SPI屏幕刷新率的关系,但可能检测方法无关,可以暂时忽略。确保引用正确标注,比如引用[1][2]关于刷新率设置检测,引用[4]关于帧率检测工具。 最后,整理步骤,分点说明,确保结构清晰,语言口语化,避免使用Markdown格式,但按照用户要求,回答时用中文,并正确标注引用。</think>### 检测手机屏幕刷新率与应用程序帧率的方法 #### **一、检测屏幕刷新率** 1. **系统设置直接查看** - 大多数安卓手机在**显示设置**中提供了刷新率选项。例如: - 小米:设置 > 显示 > 刷新率 - 华为:设置 > 显示亮度 > 屏幕刷新率 这里会显示当前支持的刷新率选项(如60Hz、90Hz、120Hz),用户可直接选择[^1]。 2. **开发者选项查看实时刷新率** - 打开手机的**开发者选项**(连续点击系统版本号激活),找到**“显示刷新频率”**或类似选项。开启后,屏幕角落会实时显示当前刷新率数值(如60Hz、90Hz)[^2]。 3. **通过代码获取(开发者适用)** ```java Display display = getWindowManager().getDefaultDisplay(); float refreshRate = display.getRefreshRate(); // 单位:Hz ``` 此方法可编程获取屏幕的当前刷新率[^2]。 --- #### **二、检测应用程序帧率** 1. **Android Studio Profiler** - 连接设备后,在Android Studio中打开**Profiler**,选择应用的进程。 - 进入**GPU**性能分析模块,可查看实时帧率(FPS)及帧生成时间,帮助定位卡顿问题[^4]。 2. **开发者选项中的GPU渲染模式分析** - 在开发者选项中启用**“GPU渲染模式分析”**或**“Profile GPU Rendering”**,选择“在屏幕上显示为条形图”。 - 屏幕会显示颜色条,每一条对应一帧的渲染时间。绿色横线标记16ms(60FPS的理想阈值),超过则可能掉帧[^4]。 3. **第三方工具** - **Systrace**:生成详细的系统级性能报告,分析帧率波动卡顿原因。 - **GameBench/Perfetto**:提供更直观的帧率曲线图性能数据统计。 4. **代码监听帧率(开发者适用)** - 使用`Choreographer`监听帧回调,计算实际帧间隔: ```java Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() { @Override public void doFrame(long frameTimeNanos) { // 计算与上一帧的时间差(转换为毫秒) long frameIntervalMs = (frameTimeNanos - lastFrameTime) / 1_000_000; fps = 1000 / frameIntervalMs; // 估算当前FPS lastFrameTime = frameTimeNanos; Choreographer.getInstance().postFrameCallback(this); // 持续监听 } }); ``` --- #### **三、注意事项** - **系统限制**:部分手机厂商会限制第三方应用获取刷新率的权限,需测试真机兼容性。 - **高刷新率场景**:若应用需要适配高刷新率(如游戏),需在代码中主动请求更高刷新率(如使用`Surface.setFrameRate()`)[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值