在webGL中覆盖带有.jpg图像的矩形

时间:2016-02-27 22:08:03

标签: javascript html5 canvas 3d webgl

我是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>

请问任何想法?

1 个答案:

答案 0 :(得分:2)

查看控制台会发现您正在应用不兼容的纹理过滤:

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.

确实你的纹理尺寸不是2的幂(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

接下来是您的顶点数据,您不会转换顶点位置,因此您正在使用规范化设备坐标(NDC),它们从-1到+1但是你的坐标超过了这一点。 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);

结果:

&#13;
&#13;
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);
}
&#13;
<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>
&#13;
&#13;
&#13;