Rya*_*hel 6 html javascript textures canvas webgl
我正在使用 WebGL 开发一个浏览器游戏,推荐的建议似乎是使用直接的 HTML 元素或在 WebGL 画布之上分层的 2d 画布来执行 UI / HUD。
这一切都很好,但是如何处理纹理共享呢?例如,游戏中可能会有掉落在地面上的物品,因此这些物品存在于世界中,因此必须是 WebGL 纹理,因为它们是存在于地面上的物品。
然而,当你拿起它们时,它们的图标就会出现在 HUD 中,因为它们会出现在屏幕底部的能力栏上。因此,您必须Canvas2D在 UI 上绘制一种纹理,WebGLTexture在 WebGL 画布上绘制一种纹理。
目前,我通过加载纹理两次来处理这个问题,一次作为游戏中的 WebGL 纹理,一次作为画布纹理。但我不认为这个解决方案具有很好的可扩展性,因为在最坏的情况下,我必须加载游戏中的每个纹理两次,并且这会使游戏的内存使用量增加一倍。
作为参考,以下是我加载纹理的两种方法:
// Load canvas texture
static createCanvasFromImage(filename: string) {
return new Promise((resolve, reject) => {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
let newImg = new Image();
newImg.onload = function() {
canvas.width = newImg.width;
canvas.height = newImg.height;
context.drawImage(newImg, 0, 0);
resolve(canvas);
}
newImg.src = filename;
});
}
Run Code Online (Sandbox Code Playgroud)
。
// Load WebGL texture
static loadImageAndCreateTextureInfo(gl: WebGLRenderingContext, url: string) {
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
// Fill the texture with a 1x1 blue pixel.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255]));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
// Don't know size until it loads
var textureInfo = { width: 1, height: 1, texture: tex };
var img = new Image();
img.addEventListener('load', function() {
textureInfo.width = img.width;
textureInfo.height = img.height;
gl.bindTexture(gl.TEXTURE_2D, textureInfo.texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
});
img.src = url;
return textureInfo;
}
Run Code Online (Sandbox Code Playgroud)
通常如何处理这种情况?有什么方法可以共享这些纹理,以便每个纹理仅在内存中加载一次,并且可以在任一画布上使用?
小智 2
我不知道这是否真的有很大帮助,但也许您有一个单独的函数,两个函数都调用它来创建图像,然后将其推送到资产数组?
如果你有这样的事情会怎样:
async newImage (url) {
const img = new Image();
img.src = url;
// Wait for the image to load
await new Promise(resolve => img.onload = () => resolve());
// Once loaded, push to "assets" (Or whatever you'd like to call it) and return image
assets.push(img);
return img;
}
// WebGL Texture, for example
static async loadImageAndCreateTextureInfo (gl: WebGLRenderingContext, url: string) {
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
// Fill the texture with a 1x1 blue pixel.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([0, 0, 255, 255]));
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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);
// Don't know size until it loads
var textureInfo = { width: 1, height: 1, texture: tex };
// "await" makes the code wait for an action to be completed
const img = await this.newImage(url);
textureInfo.width = img.width;
textureInfo.height = img.height;
gl.bindTexture(gl.TEXTURE_2D, textureInfo.texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
return textureInfo;
}
Run Code Online (Sandbox Code Playgroud)
我还没有测试过这段代码,所以它可能有效,也可能无效,但请尝试一下:)