WebGL 图像渲染质量差
WebGL image rendering bad quality
我在使用 WebGL 进行图像渲染时遇到问题:我有一个画布,其中有一个四边形占据了整个 canvas,还有一个应该映射到整个四边形上的纹理(我已经设置正确的纹理坐标)。
图像是一个包含RGB数据(按此顺序)的Uint8array,图像为1024*768像素。我有正确的缓冲区。这是图像的link。
问题如下:当渲染到 WebGL 中时,我的图片变得模糊不清,即使我有一个与图像大小相同的画布。查看以下结果:
现在是代码:这是我用来创建纹理句柄的代码:
//texture
that.Texture = that.gl.createTexture();
that.gl.bindTexture(that.gl.TEXTURE_2D, that.Texture);
// Set the parameters so we can render any size image.
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_S, that.gl.CLAMP_TO_EDGE);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_T, that.gl.CLAMP_TO_EDGE);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_MIN_FILTER, that.gl.NEAREST);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_MAG_FILTER, that.gl.NEAREST);
数据按如下方式加载到纹理上:
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGB, this.m_iImageWidth, this.m_iImageHeight,
0, this.gl.RGB, this.gl.UNSIGNED_BYTE, this.m_aImage);
最后,这是我使用的片段着色器:
precision mediump float;
uniform sampler2D u_image;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = texture2D(u_image, v_texCoord);
}
我尝试了很多选项,从过滤到设置样式选项图像渲染像素化,将图像转换为 RGBA 并赋予它 RGBA 值,结果总是同样糟糕的纹理渲染。看起来 WebGL 没有正确地插入数据,即使 canvas 与纹理的大小完全相同。
有人有提示吗?
提前致谢。
确保 canvas 宽度和高度与像素显示大小相匹配。显示大小通过样式宽度和高度设置。
分辨率是图像中的像素数。显示大小是它在页面上占据的 space 的大小。两者应该匹配才能得到最好的结果。
canvas = document.createElement("canvas");
canvas.width = 1024; // set the canvas resolution
canvas.height = 784;
canvas.style.width = "1024px"; // set the display size.
canvas.style.height = "784px";
如果显示尺寸大于分辨率,则会拉伸 canvas 并导致模糊
我们来试试吧。
var vs = `
attribute vec4 position;
attribute vec2 texcoord;
varying vec2 v_texCoord;
void main() {
gl_Position = vec4(position.xy * vec2(1, -1), 0, 1);
v_texCoord = texcoord;
}
`;
var fs = `
precision mediump float;
uniform sampler2D u_image;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = texture2D(u_image, v_texCoord);
}`
;
var gl = document.querySelector("canvas").getContext("webgl");
var that = {
gl: gl,
};
var img = new Image();
img.crossOrigin = "";
img.onload = function() {
that.m_aImage = img;
that.m_iImageWidth = img.width;
that.m_iImageHeight = img.height;
gl.canvas.width = img.width;
gl.canvas.height = img.height;
console.log("size: ", img.width, "x ", img.height);
render.call(that);
}
img.src = "https://i.imgur.com/ZCfccZh.png";
function render() {
//texture
that.Texture = that.gl.createTexture();
that.gl.bindTexture(that.gl.TEXTURE_2D, that.Texture);
// Set the parameters so we can render any size image.
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_S, that.gl.CLAMP_TO_EDGE);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_T, that.gl.CLAMP_TO_EDGE);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_MIN_FILTER, that.gl.NEAREST);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_MAG_FILTER, that.gl.NEAREST);
// upload the image directly.
// this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGB, this.gl.RGB, this.gl.UNSIGNED_BYTE, img);
// upload the image indirectly
var ctx = document.createElement("canvas").getContext("2d");
ctx.canvas.width = this.m_iImageWidth;
ctx.canvas.height = this.m_iImageHeight;
ctx.drawImage(this.m_aImage, 0, 0);
var imageData = ctx.getImageData(0, 0, this.m_iImageWidth, this.m_iImageHeight);
var numPixels = this.m_iImageWidth * this.m_iImageHeight;
var pixels = new Uint8Array(numPixels * 3);
var src = 0;
var dst = 0;
for (var i = 0; i < numPixels; ++i) {
pixels[src++] = imageData.data[dst++];
pixels[src++] = imageData.data[dst++];
pixels[src++] = imageData.data[dst++];
++dst;
}
this.m_aImage = pixels;
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGB, this.m_iImageWidth, this.m_iImageHeight, 0, this.gl.RGB, this.gl.UNSIGNED_BYTE, this.m_aImage);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
var programInfo = twgl.createProgramInfo(gl, [vs, fs]);
var bufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo);
}
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
适合我。尽管图像显然是 800x600 而不是 1024x768。如果您的图像与 canvas 大小不同,那么您可能想使用 LINEAR
过滤而不是 NEAREST
。
此外,您可以直接上传图像,而不是通过数组缓冲区(结果相同,但可能更小更快,内存更少)
我在使用 WebGL 进行图像渲染时遇到问题:我有一个画布,其中有一个四边形占据了整个 canvas,还有一个应该映射到整个四边形上的纹理(我已经设置正确的纹理坐标)。
图像是一个包含RGB数据(按此顺序)的Uint8array,图像为1024*768像素。我有正确的缓冲区。这是图像的link。
问题如下:当渲染到 WebGL 中时,我的图片变得模糊不清,即使我有一个与图像大小相同的画布。查看以下结果:
现在是代码:这是我用来创建纹理句柄的代码:
//texture
that.Texture = that.gl.createTexture();
that.gl.bindTexture(that.gl.TEXTURE_2D, that.Texture);
// Set the parameters so we can render any size image.
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_S, that.gl.CLAMP_TO_EDGE);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_T, that.gl.CLAMP_TO_EDGE);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_MIN_FILTER, that.gl.NEAREST);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_MAG_FILTER, that.gl.NEAREST);
数据按如下方式加载到纹理上:
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGB, this.m_iImageWidth, this.m_iImageHeight,
0, this.gl.RGB, this.gl.UNSIGNED_BYTE, this.m_aImage);
最后,这是我使用的片段着色器:
precision mediump float;
uniform sampler2D u_image;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = texture2D(u_image, v_texCoord);
}
我尝试了很多选项,从过滤到设置样式选项图像渲染像素化,将图像转换为 RGBA 并赋予它 RGBA 值,结果总是同样糟糕的纹理渲染。看起来 WebGL 没有正确地插入数据,即使 canvas 与纹理的大小完全相同。
有人有提示吗?
提前致谢。
确保 canvas 宽度和高度与像素显示大小相匹配。显示大小通过样式宽度和高度设置。
分辨率是图像中的像素数。显示大小是它在页面上占据的 space 的大小。两者应该匹配才能得到最好的结果。
canvas = document.createElement("canvas");
canvas.width = 1024; // set the canvas resolution
canvas.height = 784;
canvas.style.width = "1024px"; // set the display size.
canvas.style.height = "784px";
如果显示尺寸大于分辨率,则会拉伸 canvas 并导致模糊
我们来试试吧。
var vs = `
attribute vec4 position;
attribute vec2 texcoord;
varying vec2 v_texCoord;
void main() {
gl_Position = vec4(position.xy * vec2(1, -1), 0, 1);
v_texCoord = texcoord;
}
`;
var fs = `
precision mediump float;
uniform sampler2D u_image;
varying vec2 v_texCoord;
void main()
{
gl_FragColor = texture2D(u_image, v_texCoord);
}`
;
var gl = document.querySelector("canvas").getContext("webgl");
var that = {
gl: gl,
};
var img = new Image();
img.crossOrigin = "";
img.onload = function() {
that.m_aImage = img;
that.m_iImageWidth = img.width;
that.m_iImageHeight = img.height;
gl.canvas.width = img.width;
gl.canvas.height = img.height;
console.log("size: ", img.width, "x ", img.height);
render.call(that);
}
img.src = "https://i.imgur.com/ZCfccZh.png";
function render() {
//texture
that.Texture = that.gl.createTexture();
that.gl.bindTexture(that.gl.TEXTURE_2D, that.Texture);
// Set the parameters so we can render any size image.
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_S, that.gl.CLAMP_TO_EDGE);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_WRAP_T, that.gl.CLAMP_TO_EDGE);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_MIN_FILTER, that.gl.NEAREST);
that.gl.texParameteri(that.gl.TEXTURE_2D, that.gl.TEXTURE_MAG_FILTER, that.gl.NEAREST);
// upload the image directly.
// this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGB, this.gl.RGB, this.gl.UNSIGNED_BYTE, img);
// upload the image indirectly
var ctx = document.createElement("canvas").getContext("2d");
ctx.canvas.width = this.m_iImageWidth;
ctx.canvas.height = this.m_iImageHeight;
ctx.drawImage(this.m_aImage, 0, 0);
var imageData = ctx.getImageData(0, 0, this.m_iImageWidth, this.m_iImageHeight);
var numPixels = this.m_iImageWidth * this.m_iImageHeight;
var pixels = new Uint8Array(numPixels * 3);
var src = 0;
var dst = 0;
for (var i = 0; i < numPixels; ++i) {
pixels[src++] = imageData.data[dst++];
pixels[src++] = imageData.data[dst++];
pixels[src++] = imageData.data[dst++];
++dst;
}
this.m_aImage = pixels;
this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGB, this.m_iImageWidth, this.m_iImageHeight, 0, this.gl.RGB, this.gl.UNSIGNED_BYTE, this.m_aImage);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
var programInfo = twgl.createProgramInfo(gl, [vs, fs]);
var bufferInfo = twgl.primitives.createXYQuadBufferInfo(gl);
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.drawBufferInfo(gl, bufferInfo);
}
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
适合我。尽管图像显然是 800x600 而不是 1024x768。如果您的图像与 canvas 大小不同,那么您可能想使用 LINEAR
过滤而不是 NEAREST
。
此外,您可以直接上传图像,而不是通过数组缓冲区(结果相同,但可能更小更快,内存更少)