我第一次尝试使用webGL,这是因为我正在使用expo-gl软件包来开发Expo,目的是为照片编辑构建滤镜组件。到目前为止,我已经能够成功创建上下文。创建着色器时,一切正常(我可以渲染一个三角形,两个三角形等) 问题是,当我尝试将图像加载为纹理时,没有任何错误,但是我得到的只是模拟器和手机(均为android)上的黑屏。 我已经检查了powOf2图片和image.onload,并为gl.texImage2D做了console.log,但未定义。对于这个问题的任何见解或帮助,我将不胜感激。 我将我认为与该问题相关的代码分为四个部分。
1.shaders(模板文字):
const vertexShaderSource = '
attribute vec2 a_texCoord;
attribute vec4 a_position;
varying vec2 v_texCoord;
void main() {
gl_Position = a_position;
v_texCoord = a_texCoord;
}
';
const fragmentShaderSource = '
precision mediump float;
uniform sampler2D u_image;
varying vec2 v_texCoord;
void main() {
gl_FragColor = texture2D(u_image, v_texCoord);
}
';
2.ReactNative(expo)状态和生命周期:
export default class App extends React.Component {
state = {
ready: false,
image: null,
};
componentDidMount() {
(async () => {
const image = Asset.fromModule(require('./bw.jpg'));
await image.downloadAsync();
this.setState({
ready: true,
image,
});
})();
}
render() {
return (
<View style={styles.container}>
<Image source={require('./back.jpg')} style={{ width: '100%' }} />
<GLView
style={{ width: '100%', height: '100%', position: 'absolute' }}
onContextCreate={this._onContextCreate}
/>
</View>
);
}
3.gl上下文:
_onContextCreate = gl => {
if (_initialized) { return }
function createShader(gl, type, source) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) {
return shader;
}
//on error
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
}
//get shaders
var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
function createProgram(gl, vertexShader, fragmentShader) {
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
//on error
var success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) {
return program;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
}
//create program
var program = createProgram(gl, vertexShader, fragmentShader);
//get attributes
var positionAttributeLocation = gl.getAttribLocation(program, "a_position");
//a_position buffer for fragment shader
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// three 2d points
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
-1, -1,
-1, 1,
1, -1,
1, 1,
1, -1,
-1, 1,
]), gl.STATIC_DRAW);
//create the viewport
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
// Clear the canvas
gl.clearColor(0.0, 0.0, 0.0, 0.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// use program
gl.useProgram(program);
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(
positionAttributeLocation, 2, gl.FLOAT, false, 0, 0)
gl.drawArrays(gl.TRIANGLES, 0, 6);
4。纹理代码,_onContextCreate的结尾:
//get image from state
const image = this.state.image
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
var uSampler = gl.getUniformLocation(program, 'u_image');
// provide texture coordinates for the rectangle.
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
var positions = [
-1,-1,
-1, 1,
1,-1,
1, 1,
1,-1,
-1, 1,
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
//create texture
var texture = gl.createTexture();
//check if image is ready
if (image.downloaded) loadTexture(texture, image)
//get image width & height for pow2 check.
const { width, height } = Image.resolveAssetSource(image);
function loadTexture(texture, img) {
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.uniform1i(uSampler, 0);
//pow2 check
if (isPowerOf2(width) && isPowerOf2(height)) {
gl.generateMipmap(gl.TEXTURE_2D);
} else {
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);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
}
return texture
}
function isPowerOf2(value) {
return (value & (value - 1)) == 0;
}
gl.flush();
gl.endFrameEXP();
_initialized = true;
};
谢谢!