threejs webgl性能优化

Posted web与webGL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了threejs webgl性能优化相关的知识,希望对你有一定的参考价值。

threejs webgl性能优化

WEBGL性能优化的方法有很多,以下是一些常见的方法:

  1. 减少渲染次数:在WEBGL中,渲染次数越少,性能越好。因此,您可以通过减少渲染次数来提高性能。例如,使用批处理技术将多个对象合并为一个批处理对象进行渲染。

    1. WebGL 中的渲染次数越少,性能越好。这是因为在渲染过程中,WebGL 需要将场景中的每个对象都渲染一次,并将它们合成为最终的图像。如果场景中有很多对象需要渲染,那么就需要进行多次渲染,这会占用大量的 GPU 时间,导致性能下降。

      以下是一些减少渲染次数的技巧:

      1. 合并网格:如果你的场景中有很多小的网格对象,可以将它们合并成一个大的网格对象,这样可以减少渲染次数。

      2. 使用物体实例化:如果你的场景中有很多相同的对象,可以使用物体实例化技术来减少渲染次数。这样可以将一个对象实例化多次,而不是在场景中创建多个相同的对象。

      3. 使用 LOD(Level of Detail):如果你的场景中有很多复杂的模型,可以使用 LOD 技术来减少渲染次数。这样可以根据距离和大小来动态地选择适当的模型细节级别,以便在不影响质量的情况下减少渲染次数。

      4. 避免不必要的渲染:如果你的场景中有很多对象,但只有一部分需要在每帧中进行渲染,可以使用 frustum culling 技术来避免不必要的渲染。这样可以根据相机的视锥体来剔除那些不在相机范围内的对象,从而减少渲染次数。

      5. 使用批处理技术:如果你的场景中有很多需要相同材质的对象,可以使用批处理技术来减少渲染次数。这样可以将多个对象的几何数据合并成一个大的几何体,并使用一个共享的材质来渲染它们。这样可以减少 WebGL 中的状态转换次数,从而提高性能。

  2. 降低纹理分辨率:纹理分辨率越高,渲染的时间就越长。因此,您可以降低纹理分辨率来提高性能。但是,要注意在降低纹理分辨率时不要过度,否则会影响渲染效果。

    1. 降低 WebGL 纹理分辨率可以帮助提高渲染性能,可以通过多种方式实现。

      一种方式是使用纹理压缩,例如使用 S3TC/DXT 等压缩格式。这些格式可以将纹理压缩到更小的尺寸,同时保持相对较高的质量。但是,这些格式并不是所有设备都支持,需要进行适当的检测和回退处理。

      另一种方式是在加载纹理时指定较低的分辨率。例如,可以将原始纹理缩小为其一半或四分之一的大小,然后将其加载到 WebGL 中。这样可以减少纹理的大小,从而减少渲染所需的内存和带宽。但是,这种方法可能会导致纹理模糊或失真,需要根据具体情况进行调整和测试。

      还有一种方式是使用 mipmaps。Mipmaps 是一种预先生成的纹理序列,每个纹理都是原始纹理缩小版本的一半。在渲染时,WebGL 可以根据距离和尺寸自动选择最适合的 mipmap 级别,从而提高渲染性能并减少锯齿和纹理失真。可以使用 `gl.generateMipmap()` 方法生成 mipmaps。

      综上所述,降低 WebGL 纹理分辨率可以通过纹理压缩、缩小原始纹理、使用 mipmaps 等方式实现,需要根据具体情况进行选择和调整。

     

  3. 减少重绘区域:在WEBGL中,如果只有部分区域需要重绘,那么只有这部分区域需要进行渲染,这可以大大提高性能。因此,您可以通过优化重绘区域来提高性能。

    如果只有部分区域需要重绘,那么只有这部分区域需要进行渲染,这可以大大提高 WebGL 的性能。

    在 WebGL 中,可以使用剪裁(clipping)来指定需要渲染的区域。剪裁可以通过设置视口(viewport)和裁剪矩形(scissor rectangle)实现。视口指定了渲染结果在 canvas 中的位置和大小,而裁剪矩形指定了实际需要渲染的区域。

    当需要重绘的区域只占 canvas 的一部分时,可以通过重新设置视口和裁剪矩形来减少渲染的区域。例如,可以将视口设置为需要重绘的区域,然后将裁剪矩形设置为整个 canvas,这样 WebGL 就只会渲染需要重绘的区域,而不是整个 canvas。

    // 设置视口
    gl.viewport(x, y, width, height);
    
    // 设置裁剪矩形
    gl.scissor(x, y, width, height);
    
    // 启用裁剪
    gl.enable(gl.SCISSOR_TEST);
    
    // 渲染需要重绘的区域
    
    // 禁用裁剪
    gl.disable(gl.SCISSOR_TEST);
    需要注意的是,使用裁剪可能会导致一些额外的计算开销,因此应该在需要时才使用,避免不必要的性能损失。
  4. 减少顶点数:在WEBGL中,顶点数越多,渲染的时间就越长。因此,您可以通过减少顶点数来提高性能。例如,在模型中去掉一些不必要的细节,或者使用LOD技术来降低模型的细节等级。

    顶点数越多,渲染的时间就越长。这是因为WebGL是一种基于三角形渲染的技术,每个三角形都需要计算、插值、绘制。当顶点数量增加时,需要绘制更多的三角形,因此渲染时间就会增加。

    为了优化WebGL的性能,我们可以尝试减少顶点数量,例如使用简化算法来减少模型的细节,或者使用LOD(Level of Detail)技术来根据距离远近动态调整模型的细节等级。此外,还可以使用批处理技术来合并多个物体的渲染请求,从而减少WebGL的调用次数,提高渲染效率。

  5. 使用缓存:在WEBGL中,缓存可以大大提高性能。您可以使用缓存来缓存经常使用的数据,例如纹理数据、顶点数据等。这样可以减少数据传输和计算,从而提高性能。

    缓存可以大大提高WebGL的性能。WebGL中有两种类型的缓存:顶点缓存和索引缓存。

     

    顶点缓存是将顶点数据存储在GPU中,可以在多次绘制中重复使用,从而减少数据传输和CPU计算量,提高渲染效率。

     

    索引缓存是将绘制三角形所需的顶点索引存储在GPU中,也可以在多次绘制中重复使用,从而减少数据传输和CPU计算量,提高渲染效率。

     

    使用缓存需要注意缓存的大小和使用方式。如果缓存过大,会占用过多的GPU内存,导致性能下降。如果缓存过小,可能会导致频繁的数据传输和CPU计算,影响渲染效率。因此,需要根据具体情况来优化缓存大小和使用方式。

     

    在实际开发中,我们可以使用像Three.js这样的WebGL框架来管理缓存,从而简化缓存优化的过程。

     

  6. 使用GPU加速:在WEBGL中,GPU可以加速计算和渲染,因此您可以使用GPU来加速计算和渲染。例如,使用WebGL的着色器语言来编写GPU加速的着色器程序。

    GPU可以加速计算和渲染。GPU(Graphics Processing Unit,图形处理器)是一种专门用于处理图形和图像的处理器,与CPU(Central Processing Unit,中央处理器)不同,它具有更多的并行处理能力和更高的浮点计算性能。

     

    在WebGL中,GPU主要用于渲染和计算。在渲染过程中,GPU可以并行地计算每个像素的颜色值,从而提高渲染效率;在计算过程中,GPU可以执行大量的浮点计算,从而提高计算速度。

     

    为了充分利用GPU的性能,我们需要注意以下几点:

     

    1. 编写高效的着色器代码,避免使用过多的分支和循环等控制流语句,以充分利用GPU的并行处理能力。

     

    2. 使用合适的数据结构和算法,避免不必要的计算和内存访问,以提高计算效率。

     

    3. 尽量减少数据传输和CPU和GPU之间的通信,避免影响渲染效率。

     

    4. 优化纹理的使用,避免过多的纹理切换和浪费GPU内存。

     

    总之,GPU是WebGL的重要组成部分,充分利用GPU的性能可以提高WebGL的渲染和计算效率。

 

three.js是一个非常强大的3D库,但如果不注意性能优化,渲染大型场景或复杂模型时可能会出现性能问题。以下是一些three.js性能优化的建议:

1. 减少三角形数量:使用较少的三角形数量来表示模型或场景,并尽量避免使用过多的细节和多余的面。

2. 合并几何体:将多个几何体合并为一个几何体,以减少渲染调用和状态更改。

3. 简化材质:使用简单的材质和纹理,减少材质数量和贴图大小。

4. 使用LOD:使用层级细节模型(LOD)以在不同距离上使用不同的模型细节,从而提高性能。

5. 避免透明度:尽量避免使用透明度,因为它需要更多的计算来处理混合。

6. 避免过多的光源:尽量避免使用过多的光源,它们会增加渲染时间。

7. 使用WebGL渲染器:使用WebGL渲染器而不是Canvas渲染器,它更快并且支持更多的特性。

8. 使用缓存:使用缓存来避免重复计算和渲染。

9. 优化代码:避免使用过多的循环和分支,并使用高效的算法。

10. 维护帧率:在渲染器循环中维护帧率,以确保性能稳定。

ThreeJS简介

参考技术A

近年来web得到了快速的发展。随着HTML5的普及,网页的表现能力越来越强大。网页上已经可以做出很多复杂的动画,精美的效果。 但是,人总是贪的。那么,在此之上还能做什么呢?其中一种就是通过WebGL在网页中绘制高性能的3D图形。

OpenGL 它是最常用的跨平台图形库。
WebGL 是基于 OpenGL 设计的面向web的图形标准,提供了一系列JavaScript API,通过这些API进行图形渲染将得以利用图形硬件从而获得较高性能。
Three.js 是通过对 WebGL 接口的封装与简化而形成的一个易用的图形库。
简单点的说法 threejs=three + js ,three表示3D的意思,js表示javascript的意思。那么合起来,three.js就是使用javascript 来写3D程序的意思。而javascript的计算能力因为google的V8引 擎得到了迅猛的增强,做3D程序,做服务器都没有问题。
WebGL 门槛相对较高,需要相对较多的数学知识(线性代数、解析几何)。因此,想要短时间上手 WebGL 还是挺有难度的。 Three.js WebGL 提供的接口进行了非常好的封装,简化了很多细节,大大降低了学习成本。并且,几乎没有损失 WebGL 的灵活性。
因此,从 Three.js入 手是值得推荐的,这可以让你在较短的学习后就能面对大部分需求场景。

Three.js 的入门是相对简单的,但是当我们真的去学的时候,会发现一个很尴尬的问题:相关的学习资料很少。
通常这种流行的库都有很完善的文档,很多时候跟着官方的文档或官方的入门教程学习就是最好的路线。但Three不是的,它的文档对初学者来说太过简明扼要。
不过官方提供了非常丰富的examples,几乎所有你需要的用法都在某个example中有所体现。但这些example不太适合用来入门,倒是适合入门之后的进一步学习。
这里推荐一些相对较好的教程:

当然,实际的学习过程中这些资料肯定是不太够的,遇到问题还是要自己去查资料。不过这里要提醒一下,Three.js的更新是相当频繁的,现在是r80版本,自2010年4月发布r1以来,这已经是第72个版本了(中间有的版本号跳过了)。因此,在网上找到的资料有些可能是不适合当前版本的,需要注意甄别(前面推荐的资料也都或多或少存在这样的问题)。

要在屏幕上展示3D图形,思路大体上都是这样的:
1、构建一个三维空间
Three中称之为场景(Scene)
2、选择一个观察点,并确定观察方向/角度等
Three中称之为相机(Camera)
3、在场景中添加供观察的物体
Three中的物体有很多种,包括Mesh,Line,Points等,它们都继承自Object3D类
4、将观察到的场景渲染到屏幕上的指定区域
Three中使用Renderer完成这一工作

场景是所有物体的容器,也对应着我们创建的三维世界。

Camera是三维世界中的观察者,为了观察这个世界,首先我们要描述空间中的位置。 Three中使用采用常见的右手坐标系定位。

Three中的相机有两种,分别是正投影相机THREE.OrthographicCamera和透视投影相机THREE.PerspectiveCamera。

这里补充一个视景体的概念:视景体是一个几何体,只有视景体内的物体才会被我们看到,视景体之外的物体将被裁剪掉。这是为了去除不必要的运算。

正交投影相机的视景体是一个长方体,OrthographicCamera的构造函数是这样的:

Camera本身可以看作是一个点,left则表示左平面在左右方向上与Camera的距离。另外几个参数同理。于是六个参数分别定义了视景体六个面的位置。

可以近似地认为,视景体里的物体平行投影到近平面上,然后近平面上的图像被渲染到屏幕上。
2)透视投影相机

fov对应着图中的视角,是上下两面的夹角。aspect是近平面的宽高比。在加上近平面距离near,远平面距离far,就可以唯一确定这个视景体了。
透视投影相机很符合我们通常的看东西的感觉,因此大多数情况下我们都是用透视投影相机展示3D效果。

有了相机,总要看点什么吧?在场景中添加一些物体吧。
Three中供显示的物体有很多,它们都继承自Object3D类,这里我们主要看一下Mesh和Points两种。
1)Mesh
我们都知道,计算机的世界里,一条弧线是由有限个点构成的有限条线段连接得到的。线段很多时,看起来就是一条平滑的弧线了。
计算机中的三维模型也是类似的,普遍的做法是用三角形组成的网格来描述,我们把这种模型称之为Mesh模型。

geometry是它的形状,material是它的材质。
不止是Mesh,创建很多物体都要用到这两个属性。下面我们来看看这两个重要的属性。
2)Geometry
Geometry,形状,相当直观。Geometry通过存储模型用到的点集和点间关系(哪些点构成一个三角形)来达到描述物体形状的目的。
Three提供了立方体(其实是长方体)、平面(其实是长方形)、球体、圆形、圆柱、圆台等许多基本形状;
你也可以通过自己定义每个点的位置来构造形状;
对于比较复杂的形状,我们还可以通过外部的模型文件导入。
3)Material
Material,材质,这就没有形状那么直观了。
材质其实是物体表面除了形状以为所有可视属性的集合,例如色彩、纹理、光滑度、透明度、反射率、折射率、发光度。
这里讲一下材质(Material)、贴图(Map)和纹理(Texture)的关系。
材质上面已经提到了,它包括了贴图以及其它。
贴图其实是‘贴’和‘图’,它包括了图片和图片应当贴到什么位置。
纹理嘛,其实就是‘图’了。
Three提供了多种材质可供选择,能够自由地选择漫反射/镜面反射等材质。
4)Points
讲完了Mesh,我们来看看另一种Object——Points。
Points其实就是一堆点的集合,它在之前很长时间都被称为ParticleSystem(粒子系统),r68版本时更名为PointCloud,r72版本时才更名为Points。更名主要是因为,Mr.doob认为,粒子系统应当是包括粒子和相关的物理特性的处理的一套完整体系,而Three中的Points简单得多。因此最终这个类被命名为Points。
5)Light
神说:要有光!
光影效果是让画面丰富的重要因素。
Three提供了包括环境光AmbientLight、点光源PointLight、 聚光灯SpotLight、方向光DirectionalLight、半球光HemisphereLight等多种光源。
只要在场景中添加需要的光源就好了。
6)Renderer
在场景中建立了各种物体,也有了光,还有观察物体的相机,是时候把看到的东西渲染到屏幕上了。这就是Render做的事情了。
Renderer绑定一个canvas对象,并可以设置大小,默认背景颜色等属性。
调用Renderer的render函数,传入scene和camera,就可以把图像渲染到canvas中了。

现在,一个静态的画面已经可以得到了,怎么才能让它动起来?
很简单的想法,改变场景中object的位置啊角度啊各种属性,然后重新调用render函数渲染就好了。
那么重新渲染的时机怎么确定?
HTML5为我们提供了requestAnimFrame,它会自动在每次页面重绘前调用传入的函数。
如果我们一开始这样渲染:

只需要改成这样:

object就可以动起来了!

下面我们用一个简单的例子来梳理一下这个过程。
首先写一个有Canvas元素的页面吧。

下面来做Javascript的部分
首先初始化Renderer

初始化场景:

初始化相机:

要唯一确定一个相机的位置与方向,position、up、lookAt三个属性是缺一不可的。
这里我们创建了一个正交投影相机,这里我将视景体大小与屏幕分辨率保持一致只是为了方便,这样坐标系中的一个单位长度就对应屏幕的一个像素了。
我们将相机放在Z轴上,面向坐标原点,相机的上方向为Y轴方向,注意up的方向和lookAt的方向必然是垂直的(类比自己的头就知道了)。
下面添加一个立方体到场景中:

注意我们使用了法向材质 MeshNormalMaterial ,这样立方体每个面的颜色与这个面对着的方向是相关的,更便于观察/调试。
在这个简单的demo里我不打算添加光影效果,而法向材质对光也是没有反应的。 最后来创建一个动画循环吧

每次重绘都让这个立方体转动一点点。 当页面加载好时,调用前面这些函数就好了。

WebGL中文网 强烈推荐!!
WebGL中文教程网

以上是关于threejs webgl性能优化的主要内容,如果未能解决你的问题,请参考以下文章

ThreeJS简介

WebGPU 导入[1]

THREEJS性能优化

学习threejs / webGL - 颜色和透明度

Webgl/Threejs 学习及实践总结

WebGL之Threejs概述