我编写了一个 WebGL-React-App,当我导入文件时,它应该加载 4 个平面和 4 个图像。当我导入文件时,所有平面都是蓝色的,并且只有在移动视图时才会加载图像。我如何管理文件导入后立即加载图像?我读过几个类似的问题,这些问题都是用“Promise”解决的,但没有运气将其转移到我的代码中。
这是我的代码:
export function createLabel(gl, desc) {
console.log("create label: " + desc);
let coords = buildQuadricTriangleStrip(0.5);
let texture = null;
if (desc === DESC.N) {
coords = translateQuad(coords, 0.5, -0.25, 0);
texture = loadTexture(gl, "/images/n.png");
}
if (desc === DESC.S) {
coords = rotateQuad(coords, ROT_AXIS.Z, 180);
coords = translateQuad(coords, -0.5, 0.25, 0);
texture = loadTexture(gl, "/images/s.png");
}
if (desc === DESC.E) {
coords = rotateQuad(coords, ROT_AXIS.Z, 180);
//coords = rotateQuad(coords, ROT_AXIS.Z, 180);
coords = translateQuad(coords, 0.25, -0.5, 0);
texture = loadTexture(gl, "/images/e.png");
}
if (desc === DESC.W) {
coords = rotateQuad(coords, ROT_AXIS.Z, 180);
coords = translateQuad(coords, 0.25, 1, 0);
texture = loadTexture(gl, "/images/w.png");
}
//console.log(texture);
const textureCoordinates = [
0, 1,
1, 1,
0, 0,
1, 0
]
const indices = [
2, 3, 1,
0, 1, 2
]
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(coords), gl.STATIC_DRAW);
const textureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gl.STATIC_DRAW);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
let vs = document.getElementById("vshaderlabel").textContent;
let fs = document.getElementById("fshaderlabel").textContent;
const shaderProgram = shader.initShaderProgram(gl, vs, fs);
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
},
};
return {
position: positionBuffer,
textureCoord: textureCoordBuffer,
indices: indexBuffer,
positionSize: coords.length,
texture,
programInfo
};
}
function loadTexture(gl, url) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
const level = 0;
const internalFormat = gl.RGBA;
const width = 1;
const height = 1;
const border = 0;
const srcFormat = gl.RGBA;
const srcType = gl.UNSIGNED_BYTE;
const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
gl.texImage2D(
gl.TEXTURE_2D,
level,
internalFormat,
width,
height,
border,
srcFormat,
srcType,
pixel,
);
const image = new Image();
image.addEventListener('load', function () {
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
gl.TEXTURE_2D,
level,
internalFormat,
srcFormat,
srcType,
image,
);
// WebGL1 has different requirements for power of 2 images
// vs non power of 2 images so check if the image is a
// power of 2 in both dimensions.
if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
// Yes, it's a power of 2. Generate mips.
gl.generateMipmap(gl.TEXTURE_2D);
} else {
// No, it's not a power of 2. Turn off mips and set
// wrapping to 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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
}
});
image.src = url;
return texture;
}
function isPowerOf2(value) {
return (value & (value - 1)) === 0;
}
export function draw(gl, projectionMatrix, modelViewMatrix, buffers) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
gl.vertexAttribPointer(buffers.programInfo.attribLocations.vertexPosition, 3, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(buffers.programInfo.attribLocations.vertexPosition);
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.textureCoord);
gl.vertexAttribPointer(buffers.programInfo.attribLocations.textureCoord, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(buffers.programInfo.attribLocations.textureCoord);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);
gl.useProgram(buffers.programInfo.program);
gl.uniformMatrix4fv(
buffers.programInfo.uniformLocations.projectionMatrix,
false,
projectionMatrix
);
gl.uniformMatrix4fv(
buffers.programInfo.uniformLocations.modelViewMatrix,
false,
modelViewMatrix
);
gl.activeTexture(gl.TEXTURE0);
// Bind the texture to texture unit 0
gl.bindTexture(gl.TEXTURE_2D, buffers.texture);
// Tell the shader we bound the texture to texture unit 0
gl.uniform1i(buffers.programInfo.uniformLocations.uSampler, 0);
//gl.drawArrays(gl.TRIANGLE_STRIP, 0, buffers.positionSize / 3);
{
const vertexCount = buffers.positionSize / 2;
const type = gl.UNSIGNED_SHORT;
const offset = 0;
gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
}
}
Finally i found my educated solution by using promise and async await:
Createlabel:
export async function createLabel(gl, desc) {
console.log("create label: " + desc);
let coords = buildQuadricTriangleStrip(0.5);
let texture = null;
if (desc === DESC.N) {
coords = translateQuad(coords, 0.5, -0.25, 0);
texture = await loadTexture(gl, "/images/n.png");
}
if (desc === DESC.S) {
coords = rotateQuad(coords, ROT_AXIS.Z, 180);
coords = translateQuad(coords, -0.5, 0.25, 0);
texture = await loadTexture(gl, "/images/s.png");
}
if (desc === DESC.E) {
coords = rotateQuad(coords, ROT_AXIS.Z, 180);
//coords = rotateQuad(coords, ROT_AXIS.Z, 180);
coords = translateQuad(coords, 0.25, -0.5, 0);
texture = await loadTexture(gl, "/images/e.png");
}
if (desc === DESC.W) {
coords = rotateQuad(coords, ROT_AXIS.Z, 180);
coords = translateQuad(coords, 0.25, 1, 0);
texture = await loadTexture(gl, "/images/w.png");
}
const textureCoordinates = [
0, 1,
1, 1,
0, 0,
1, 0
]
const indices = [
2, 3, 1,
0, 1, 2
]
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(coords), gl.STATIC_DRAW);
const textureCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gl.STATIC_DRAW);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
let vs = document.getElementById("vshaderlabel").textContent;
let fs = document.getElementById("fshaderlabel").textContent;
const shaderProgram = shader.initShaderProgram(gl, vs, fs);
const programInfo = {
program: shaderProgram,
attribLocations: {
vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),
textureCoord: gl.getAttribLocation(shaderProgram, 'aTextureCoord'),
},
uniformLocations: {
projectionMatrix: gl.getUniformLocation(shaderProgram, "uProjectionMatrix"),
modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),
uSampler: gl.getUniformLocation(shaderProgram, 'uSampler'),
},
};
return {
position: positionBuffer,
textureCoord: textureCoordBuffer,
indices: indexBuffer,
positionSize: coords.length,
texture,
programInfo
};
}
Loadimage:
async function loadTexture(gl, url) {
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
const level = 0;
const internalFormat = gl.RGBA;
const width = 1;
const height = 1;
const border = 0;
const srcFormat = gl.RGBA;
const srcType = gl.UNSIGNED_BYTE;
const pixel = new Uint8Array([0, 0, 255, 255]); // opaque blue
gl.texImage2D(
gl.TEXTURE_2D,
level,
internalFormat,
width,
height,
border,
srcFormat,
srcType,
pixel,
);
let image = await loadImage(url);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
gl.TEXTURE_2D,
level,
internalFormat,
srcFormat,
srcType,
image,
);
// WebGL1 has different requirements for power of 2 images
// vs non power of 2 images so check if the image is a
// power of 2 in both dimensions.
if (isPowerOf2(image.width) && isPowerOf2(image.height)) {
// Yes, it's a power of 2. Generate mips.
gl.generateMipmap(gl.TEXTURE_2D);
} else {
// No, it's not a power of 2. Turn off mips and set
// wrapping to 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);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
}
return texture;
}
function loadImage(url) {
return new Promise(resolve => {
const image = new Image();
image.addEventListener('load', () => {
resolve(image);
});
image.src = url;
});
}
Call in View3D:
init = async(props) => {
const canvas = document.querySelector("#glCanvas");
const surr = document.querySelector("#draw");
canvas.style.width = "100%";
//canvas.style.height = "100%";
canvas.width = surr.offsetWidth;
const gl = canvas.getContext("webgl");
if (!gl) {
alert(
"Unable to initialize WebGL. Your browser or machine may not support it."
);
return;
}
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
if (props != null) {
let p = plane.createPlane(gl, props, props.colors);
let n = await tex.createLabel(gl, tex.DESC.N);
let s = await tex.createLabel(gl, tex.DESC.S);
let e = await tex.createLabel(gl, tex.DESC.E);
let w = await tex.createLabel(gl, tex.DESC.W);
let m = marker.createMarker(gl, props);
let objects3d = {
plane: p,
n,
s,
e,
w,
m,
};
this.setState({ gl, objects3d });
this.drawScene(gl, objects3d);
}
};