【问题标题】:covering rectangle with .jpg image in webGL在 webGL 中用 .jpg 图像覆盖矩形
【发布时间】:2016-02-28 17:28:00
【问题描述】:

我是 webGL 世界的初学者,我在将图像绘制成我制作的矩形时遇到了一些问题。

首先我为矩形制作了形状:

var posLoc = gl.getAttribLocation(program, "pos");
gl.enableVertexAttribArray(posLoc);
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
var vertices = [
 1.0,  2.0,  0.0, 
-1.0,  2.0,  0.0, 
-1.0, -2.0,  0.0, 
 1.0, -2.0,  0.0  
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(posLoc, 3, gl.FLOAT, false, 0, 0);

然后我创建了纹理,使其处于活动状态并像这样制作了 mitmap:

var texture = null;
var image = document.createElement("img");
image.crossOrigin = "anonymous";
image.src = "https://upload.wikimedia.org/wikipedia/commons/3/38/JPEG_example_JPG_RIP_010.jpg";
image.onload = function() {
    texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
    gl.generateMipmap(gl.TEXTURE_2D);
    ...
}

最后我没有成功地尝试绘制所有东西:

gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0);

这是完整的代码

var gl = document.querySelector("canvas").getContext("experimental-webgl");

var str = document.querySelector("#vs").textContent;
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, str);
gl.compileShader(vs);
	
var str = document.querySelector("#fs").textContent;
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, str);
gl.compileShader(fs);

var program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
gl.useProgram(program);

var samplerLoc = gl.getUniformLocation(program, "sampler");
gl.uniform1i(samplerLoc, 0);

gl.enable(gl.DEPTH_TEST);
gl.clearColor(0.8, 0.6, 0.2, 1);

var texture = null;
var image = document.createElement("img");
image.crossOrigin = "anonymous";
image.src = "https://upload.wikimedia.org/wikipedia/commons/3/38/JPEG_example_JPG_RIP_010.jpg";
image.onload = function() {
		var posLoc = gl.getAttribLocation(program, "pos");
    gl.enableVertexAttribArray(posLoc);
    var vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    var vertices = [
       1.0,  2.0,  0.0, 
      -1.0,  2.0,  0.0, 
      -1.0, -2.0,  0.0, 
       1.0, -2.0,  0.0  
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    gl.vertexAttribPointer(posLoc, 3, gl.FLOAT, false, 0, 0);

    var indexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    var indices = [0, 1, 2, 0, 1, 3, 1, 2, 3, 0, 2, 3];
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices), gl.STATIC_DRAW);
		
    texture = gl.createTexture();
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
		gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
    gl.generateMipmap(gl.TEXTURE_2D);
    
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture);

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    gl.enable(gl.DEPTH_TEST);
    gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0);
}
<canvas></canvas>

<script id="vs" type="x-shader/x-vertex">
attribute vec3 pos;
attribute vec2 texture;
varying vec2 varyingTexture;

void main(void) {
	gl_Position = vec4(pos, 1.0);
	varyingTexture = texture;
}
</script>

<script id="fs" type="x-shader/x-fragment">
precision mediump float;

varying vec2 varyingTexture;
uniform sampler2D sampler;	
    
void main(void) {
	gl_FragColor = texture2D(sampler, varyingTexture);
}
</script>

有什么想法吗?

【问题讨论】:

标签: javascript html canvas 3d webgl


【解决方案1】:

查看控制台显示您正在应用不兼容的纹理过滤:

texture bound to texture unit 0 is not renderable. It maybe non-power-of-2 and have incompatible texture filtering or is not 'texture complete'. Or the texture is Float or Half Float type with linear filtering while OES_float_linear or OES_half_float_linear extension is not enabled.

确实,您的纹理尺寸不是二的幂(NPOT),因此您必须使用不需要 mipmap 的纹理过滤器,也不能生成 mipmap:

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
// Use linear filter for minification
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
// removed generate mipmap call

接下来你需要设置一个合适的包裹模式,对于 NPOT 纹理,唯一兼容的包裹模式是CLAMP_TO_EDGE

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

然后你会看到矩形改变了它的颜色,但是你的顶点数据不包含任何纹理坐标,所以它们将被0 替换,导致只应用最顶部像素的颜色。要解决这个问题,您需要获取 texture 属性的位置并启用属性数组:

var texLoc = gl.getAttribLocation(program, "texture");
gl.enableVertexAttribArray(texLoc); // Could use 1 directly here

接下来是你的顶点数据,你没有改变你的顶点位置,所以你正在使用从 -1 到 +1 的标准化设备坐标(NDC),但是你'用你的坐标重新超过这个。 Check this link to learn more about coordinate spaces。创建一个屏幕对齐的四边形并添加缺失的纹理坐标,顶点数据如下所示:

var vertices = [// \/\/ texture coordinates
   1.0,  1.0,  0.0, 1,0,
  -1.0,  1.0,  0.0, 0,0,
  -1.0, -1.0,  0.0, 0,1,
   1.0, -1.0,  0.0, 1,1
];// /\/\/\/\ Fixed positions to lie within NDC

您还使用索引缓冲区定义了四个三角形,而您只需要两个来构建一个四边形:

var indices = [0, 1, 2, 3, 2, 0];

最后相应地设置您的vertex attribute pointers

// Note the last two arguments are defined in BYTES
gl.vertexAttribPointer(posLoc, 3, gl.FLOAT, false, 20, 0);
gl.vertexAttribPointer(texLoc, 2, gl.FLOAT, false, 20, 12);

结果:

var gl = document.querySelector("canvas").getContext("experimental-webgl");

var str = document.querySelector("#vs").textContent;
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, str);
gl.compileShader(vs);
	
var str = document.querySelector("#fs").textContent;
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, str);
gl.compileShader(fs);

var program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
gl.useProgram(program);

var samplerLoc = gl.getUniformLocation(program, "sampler");
gl.uniform1i(samplerLoc, 0);

gl.clearColor(0.8, 0.6, 0.2, 1);

var texture = null;
var image = document.createElement("img");
image.crossOrigin = "anonymous";
image.src = "http://upload.wikimedia.org/wikipedia/commons/3/38/JPEG_example_JPG_RIP_010.jpg";
image.onload = function() {
    // Get and enable vertex attribute for texture, note I renamed "texture" to "tex" in the shader and here
    var posLoc = gl.getAttribLocation(program, "pos");
    var texLoc = gl.getAttribLocation(program, "tex");
    gl.enableVertexAttribArray(0);
    gl.enableVertexAttribArray(1);
    var vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    // Add texture coordinates, fix positions
    var vertices = [
       1.0,  1.0,  0.0, 1,0,
      -1.0,  1.0,  0.0, 0,0,
      -1.0, -1.0,  0.0, 0,1,
       1.0, -1.0,  0.0, 1,1
    ];
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    gl.vertexAttribPointer(posLoc, 3, gl.FLOAT, false, 20, 0);
    gl.vertexAttribPointer(texLoc, 2, gl.FLOAT, false, 20, 12);

    var indexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
    // Remove excess indices
    var indices = [0, 1, 2, 3, 2, 0];
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices), gl.STATIC_DRAW);
		
    texture = gl.createTexture();
    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    // Use linear filter for minification
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    // Do not generate mip maps

    // Apply appropriate wrap mode
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);

    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    gl.enable(gl.DEPTH_TEST);
    gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0);
}
<canvas></canvas>

<script id="vs" type="x-shader/x-vertex">
attribute vec3 pos;
attribute vec2 tex;
varying vec2 varyingTexture;

void main(void) {
	gl_Position = vec4(pos, 1.0);
	varyingTexture = tex;
}
</script>

<script id="fs" type="x-shader/x-fragment">
precision mediump float;

varying vec2 varyingTexture;
uniform sampler2D sampler;	
    
void main(void) {
	gl_FragColor = texture2D(sampler, varyingTexture);
}
</script>

【讨论】:

  • 这是一个非常棒的答案&&帮助,非常感谢!
  • 只是为了让它完整,你制作的顶点数组中的最后两个数字究竟代表什么?我希望前三个是 x、y 和 z 的浮点数,但后两个?因为我现在正试图用这个图像而不是 od 矩形覆盖多边形,它有点不起作用。你可以在那里看到jsfiddle.net/bimbochobot/mqpzfgd0/2
  • 那是用来做UV mapping的纹理坐标,范围从左下角(0,0)到右上角(1,1)。更多信息请参考@gman 提到的教程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-23
  • 2023-04-08
  • 1970-01-01
  • 2011-07-09
  • 2020-07-04
相关资源
最近更新 更多