WebGL рендеринг изображений плохого качества

У меня проблема с рендерингом изображений в WebGL: у меня есть канва с квадом, занимающим весь холст, и текстурой, которая должна отображаться на весь квад (я установил правильные координаты текстуры).

Изображение представляет собой массив Uint8, содержащий данные RGB (в этом порядке), и изображение имеет размер 1024*768 пикселей. У меня есть правильный буфер. Вот ссылка на изображение.

Исходное изображение

Проблема заключается в следующем: при рендеринге в WebGL моя картинка становится размытой и размытой, даже если у меня есть канва, которая имеет размер изображения. Смотрите результат ниже:

Оказывается через 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 неправильно интерполирует данные, даже если размер холста точно такой же, как у текстуры.

У кого-нибудь есть подсказка?

Заранее спасибо.

2 ответа

Решение

Убедитесь, что ширина и высота холста соответствуют размеру экрана в пикселях. Размер дисплея устанавливается через ширину и высоту стиля.

Разрешение - это количество пикселей на изображении. Размер дисплея - это объем пространства, которое он занимает на странице. Два должны соответствовать для лучших результатов.

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

Размер экрана, если он больше, чем разрешение, вытянет холст и приведет к размытию

Давай попробуем.

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, gl.TRIANGLES, bufferInfo);
 }
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
<canvas></canvas>

Работает для меня. Хотя изображение видимо 800х600, а не 1024х768. Если ваше изображение не такого размера, как холст, вы, вероятно, хотите использовать LINEAR фильтрация вместо NEAREST,

Кроме того, вы можете загружать изображения напрямую, а не через буфер массива (тот же результат, но, вероятно, намного меньше, быстрее и меньше памяти)

Другие вопросы по тегам