문제 설명
HTML, Canvas 및 WebGL 간의 품질 차이 (Quality differences between HTML, Canvas and WebGL)
WebGL로 이미지를 그리고 싶지만 축소되었습니다. 크기를 조정하지 않으면 이미지 품질이 좋지만 크기를 줄이면 품질이 떨어집니다.
'Handling High DPI(Retina) display in WebGL'에 대해 다음에서 읽었습니다. 여기: 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);
하지만 이것은 HTML 이미지와 같은 품질을 가지고 있지 않았습니다. HTML의 내 코드:
setTimeout(function() {
var imagine = new Image();
imagine.src = 'Tank.png';
imagine.width = '28';
imagine.height = '35';
document.body.appendChild(imagine);
}, 1000);
캔버스의 내 코드:
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');
이미지 품질의 차이는 아래 ( 품질: WebGL <캔버스
큰 차이는 아니지만 좋은 품질의 사진을 보여줍니다. HTML에서는 그림이 더 부드럽습니다. Chrome 브라우저를 확대하면 HTML의 그림이 품질이 향상되는 것을 관찰했습니다. 그러나 WebGL 사진은 동일한 해상도로 유지되며 품질이 저하됩니다. 그리고 페이지를 새로고침하여 WebGL용 devicePixelRatio를 업데이트하면 사진의 품질은 더 좋아지지만 내 브라우저는 500% 확대/축소에서 느리게 작동합니다. 캔버스를 더 크게 만들고 더 많이 그려야 하기 때문이라고 생각합니다. 하지만 HTML에서는 500% 줌으로 이미지를 움직이면 문제가 없고, 이미지도 잘 움직이고 화질도 좋습니다.
여기서 상황 ‑ WebGL 이미지 렌더링 품질이 좋지 않음 ‑ 이미지 크기가 조정되지 않았지만 크기 조정이 필요합니다. 다운 사진.
이 상황과 비교 ‑ canvas drawImage 품질 ‑ 세 프로그램 모두에서 값을 정수로 입력했습니다.
마지막 질문:
HTML에서와 같은 품질로 webGL에서 이미지를 그리고(해당 트랙에서 해당 선이 보이지 않음) 브라우저 확대 시에도 좋은 품질을 얻으려면 어떻게 해야 합니까? 내가 그들을 그릴 수 있는 다른 가능성은 무엇입니까? 어떤 기술을 사용해야 합니까? WebGL에는 HTML에 없는 몇 가지 기능이 있기 때문에 사용하고 싶었고 선이나 점과 같이 처음부터 몇 가지를 그리고 싶었습니다.
편집 1: 이것은 일반 해상도의 사진입니다.
Rendering
The next image show the rendered results, pixel aligned (WebGL top tow rows have same result in 2D)
From left to right is the size of the original source image, 2 times to 16 times the final size.
Each row uses a different pixel lookup
Nearest. The fastest rendering the pixel nearest the top left of each pixel the final render
Linear. Default for 2d (smoothing = true), webGL (
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
). The pixel color is a linear interpolation of the 4 pixels near (under, right, below, below right) the final pixel.Log mean. Custom WebGL only. The fragment shader uses the total photon count of all pixels under the rendered pixel to calculate the final RGB pixel color. For original 2 times the size GPU cost is about the same as Linear, For 16 times is only for the high end devices, or low image rendering counts (64 times slower than linear per pixel)
Log Mean +. Uses same fragment shader as Log Mean to render but pre processes (Just in time) the original using a modified sharpen convolution filter to sharpen at
2/3 * invScale
(Log calcs) to increase the visual contrast at low contrast boundaries. The Cost is a one time init cost.
Personally for real‑time projects I use second row first column 2 * linear, and when rendering on HDPI or high render counts I use the simplest 1 * linear (not shown).
Most people can not tell the difference between the 2nd, 3rd and last rows. Can you without zooming in on the image?
Rotation
The next image shows the same method from 2 times to 16 times left to right, then rows linear, nearest, and log mean, +.
Notes
- Log RGB image processing only has a significant improvement with highly saturated images with high colour contrast. The tank image has very low colour contrast and thus does not get much benefit from Log Mean. The next image shows from left to right nearest, linear, and log mean of high colour contrast version.
All images in this answer were created on GPU accelerated Chrome 80 Win 10 x64. Original tank reference image by the OP.
I just noticed, as I finish, that the
Nearest
rotated images all have anti‑aliasing on the outer edges. This is an error on my part as I forgot to give the image some transparent padding. The anti‑aliasing is due to the polygon edge and not part of the pixelgl.TEXTURE_MIN_FILTER, gl.LINEAR
lookup process. To much work to fix, sorry.
방법 2:
If you want your pictures to be drawn more smooth, then you could use mipmaps! Try to make the pictures to have both dimensions a power at 2 and after you can generate mipmaps, like this:
gl.generateMipmap(gl.TEXTURE_2D);
With mipmaps you can choose what WebGL does by setting the texture filtering for each texture. And if you want to your image to be smooth, then you have to change the texture filtering to be LINEAR_MIPMAP_LINEAR. So after you generate the mipmaps you have to write:
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
The pictures with the differences are below ( LINEAR vs LINEAR_MIPMAP_LINEAR ):
In first picture the tracks are asymmetric, but the second picture is drawn smooth. I think that the second picture looks more like the HTML picture that you provided.
There is a great tutorial about WebGL Textures: https://webglfundamentals.org/webgl/lessons/webgl‑3d‑textures.html. There is written that this type of texture filtering is the slowest and it takes 33% more memory, so be aware of that!
(by Niqusor31、Blindman67、Niqusor31)