HTML、Canvas 和 WebGL 之间的质量差异

Niq*_*r31 0 html javascript canvas image webgl

我想在 WebGL 中绘制图像,但缩小了尺寸。当我不缩放它时,图像的质量很好,但如果我缩小它,那么图像的质量很差。

我从这里读到“在 WebGL 中处理高 DPI(视网膜)显示”: http: //www.khronos.org/webgl/wiki/HandlingHighDPI,我尝试做同样的事情。我在 WebGL 中的代码是:

        Initializations:

        var devicePixelRatio = window.devicePixelRatio || 1;

        gl.canvas.style.width = "800px";
        gl.canvas.style.height = "600px";

        canvas.width = Math.round(800 * devicePixelRatio);
        canvas.height = Math.round(600 * devicePixelRatio);


        For drawing:

        gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
        matrix = m3.scale(matrix, 28/800, 35/600); // matrix for scaling texture

        Textures:

        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
Run Code Online (Sandbox Code Playgroud)

但这并不具有与 HTML 图像相同的质量。我的 HTML 代码是:

        setTimeout(function() {

            var imagine = new Image();
            imagine.src = 'Tank.png';
            imagine.width = '28';
            imagine.height = '35';
            document.body.appendChild(imagine);

        }, 1000);
Run Code Online (Sandbox Code Playgroud)

我在画布中的代码是:

        var imagine = new Image();
        imagine.src = 'Tank.png';
        imagine.width = '28';
        imagine.height = '35';
        imagine.onload = function() {
            context.drawImage(imagine, 0, 0, 28, 35);
        }
        context = canvas.getContext('2d');
Run Code Online (Sandbox Code Playgroud)



图像质量之间的差异如下(质量:WebGL < Canvas < HTML)

网页GL 帆布 超文本标记语言

我知道这并不是很大的区别,但我真的想以高质量展示图片。在 HTML 中,图片更加流畅。我观察到,如果我放大 Chrome 浏览器,来自 HTML 的图片质量会提高,但 WebGL 图片仍保持相同的分辨率,并且质量会下降。如果我刷新页面,更新 WebGL 的 devicePixelRatio,那么图片的质量会更好,但我的浏览器在 500% 缩放时工作速度会变慢,我想是因为它使画布更大并且必须绘制更多内容。但在 HTML 中,如果我以 500% 缩放移动图像,则没有问题,图像移动良好且质量良好。


在这种情况下 - WebGL 图像渲染质量较差- 图像未缩放,但我需要缩小图片。

与这种情况相比 -画布绘制图像质量- 我在所有三个程序中将值设置为整数。



最后一个问题:

如何在 webGL 中以与在 HTML 中相同的质量(看不到这些轨道中的线条)绘制图像,并且即使浏览器放大也能获得良好的质量?我还有什么其他的可能性来绘制它们?我应该使用什么技术?我想使用 WebGL,因为它具有 HTML 所没有的一些功能,并且我想从头开始绘制一些东西,例如线条或点。


编辑1:这是正常分辨率的图片。


坦克图片


在这张图中,铁轨的线条似乎不是直的,而是交叉的。如果您可以仔细观察 Canvas 和 WebGL 中的图像,就会发现轨道的第一条线(第一条在左边,第一条在右边)是直的。而且,使用Canvas的图片有更多的直线轨迹,甚至是最后的轨迹。HTML 的最后一个图像具有相同形状的所有轨道。


抱歉,因为我放了很小的照片。这是因为我需要这个比例,并且我需要图片不要更大。如果我要绘制更大的图片,那么 devicePixelRatio 将使图片看起来更好,但我不使用正常尺寸的图片。这样的话,这个问题就可以通过devicePixelRatio来解决。对于较小的尺寸,这种使用 devicePixelRatio 的方法对我没有帮助。这就是为什么我正在寻找另一种解决方案。

Bli*_*n67 5

随机缩放、位置和旋转

如果图像经过变换和动画处理,则最好使用线性插值,原始图像至少比渲染结果大 2 倍。

确保画布(2D 或 WebGL)与设备像素对齐,并且与物理设备像素一对一匹配。

如果它是 1 或 2 以外的任何其他值(2 表示 HDPI 或视网膜) ,请勿使用devicePixelRatio,因为其他值意味着页面已缩放,并且您无法获得一对一的像素与设备像素匹配。尝试缩放画布(2D 或 WebGL)只会降低质量。

原始图像

这最适用于绘制到像素边界的轴对齐渲染图像。然而,它对于缩放、旋转和/或未对齐渲染仍然有一些好处。

高质量画布(2d 或 webGL)图像渲染最重要的部分是原始图像大小与渲染结果之间的关系。

如果将图像缩小到 28 x 35 像素,则原始图像必须为 2* (68, 92) 4* (136, 184) 等...最终渲染结果大小的 2 倍幂。 注意您必须考虑较大图像的 GPU RAM 成本。

原始图像细节与渲染像素对齐

图像中必须尽可能保持清晰的重要细节必须与渲染的像素边缘对齐,否则最终会得到模糊的细节。

下图是最终尺寸的16*。它上面有一个棋盘(每个正方形 16 × 16 像素),用于显示渲染像素的大小。

注意履带、车身、枪管、炮塔的边缘如何与最终缩小的像素对齐。

在此输入图像描述

渲染

下图显示了渲染结果,像素对齐(WebGL 顶部两行在 2D 中具有相同的结果)

从左到右是原始源图像的尺寸,是最终尺寸的2倍到16倍。

每行使用不同的像素查找

  • 最近的。最终渲染最接近每个像素左上角的像素的最快渲染

  • 线性。默认为 2d(平滑 = true),webGL ( gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR))。像素颜色是最终像素附近(下、右、下、右下)的 4 个像素的线性插值。

  • 对数的意思。仅限自定义 WebGL。片段着色器使用渲染像素下所有像素的总光子计数来计算最终的 RGB 像素颜色。对于原始大小的 2 倍 GPU 成本与线性大致相同,对于 16 倍仅适用于高端设备,或低图像渲染计数(每像素比线性慢 64 倍)

  • 对数平均值+。使用与 Log Mean 相同的片段着色器进行渲染,但使用修改后的锐化卷积滤波器对原始数据进行预处理(及时)以在2/3 * invScale(Log 计算)处锐化,以增加低对比度边界处的视觉对比度。成本是一次性初始成本。

在此输入图像描述

就个人而言,对于实时项目,我使用第二行第一列 2 * 线性,在 HDPI 或高渲染计数上渲染时,我使用最简单的 1 * 线性(未显示)。

大多数人无法区分第二行、第三行和最后一行。可以不放大图像吗?

回转

下图显示了从左到右 2 次到 16 次的相同方法,然后是线性行、最近行和对数平均值、+。

在此输入图像描述

笔记

  • Log RGB 图像处理仅对具有高色彩对比度的高饱和度图像有显着的改进。坦克图像的颜色对比度非常低,因此无法从对数均值中获得太多好处。下图从左到右显示了高颜色对比度版本的最接近的线性和对数平均值。

在此输入图像描述

  • 本答案中的所有图像都是在 GPU 加速的 Chrome 80 Win 10 x64 上创建的。OP 提供的原始坦克参考图像。

  • 我刚刚注意到,当我完成时,Nearest旋转的图像在外边缘都有抗锯齿功能。这是我的一个错误,因为我忘记给图像一些透明的填充。抗锯齿是由于多边形边缘而不是像素gl.TEXTURE_MIN_FILTER, gl.LINEAR查找过程的一部分。需要修复的工作量很大,抱歉。