在 webGL 中用.jpg图像覆盖矩形
covering rectangle with .jpg image in 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>
有什么想法吗?
查看控制台会发现您正在应用不兼容的纹理过滤:
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
接下来是您的顶点数据,您没有转换顶点位置,因此您使用从 -1 到 +1 的规范化设备坐标 (NDC),但是您的坐标超过了这个范围。查看此链接以了解有关坐标空间的详细信息。创建屏幕对齐的四边形并添加缺少的纹理坐标,顶点数据如下所示:
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];
最后相应地设置顶点属性指针:
// 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>
相关文章:
- 点击(右键点击)使用传单地图库获取图像覆盖的像素坐标
- PNG图像被覆盖,但每个图像都有一个链接可以更改,每次一个-Javascript/jQuery/CSS
- 将谷歌地图中的平移边界设置为图像覆盖
- TinyMCE图像上传覆盖images_upload_handler
- 如何使用 OnClick 事件更改结构 JS 的覆盖图像
- 多个背景图像,一个覆盖另一个
- node.js在覆盖图像时无法提供图像
- 如何使用PHP、提交和单选按钮复制/重命名/覆盖图像
- 在HTML中覆盖图像
- 如何删除覆盖图像查看器的溢出(滚动条)
- 使用CSS悬停类悬停在链接上,并在页面的其他位置显示覆盖图像
- 覆盖图像与砌体在WP
- 如何覆盖图像和链接路径在iframe对象
- 使用Javascript覆盖图像文件
- 覆盖图像与文本,保存和共享
- 添加多个水印/覆盖图像到amcharts.com图表
- 是否有可能隐藏(切换)主地图层,只显示地面覆盖图像本身?
- 覆盖图像与JS, HTML, CSS
- 防止在加载覆盖图像时显示列表项
- 谷歌地图api v3覆盖图像与搜索栏