关于webgl的fbo缓冲帧的问题。
有一个业务需求是在webgl画布上绘制一张图片纹理,然后在图片纹理上绘制一个多边形,需要两步绘制完,再输出到画布上,所以就用到fbo离屏渲染,但不知道是不是我写的有问题,还是不同步,总是绘制多边形比图片纹理慢一拍,导致画面不同步;小程序代码`
`
// pages/frame/frame.js
var glMatrix = require('./glMatrix.js')
const mat4 = glMatrix.mat4.create()
const vs = `
attribute vec3 aPos;
uniform mat4 projMat4;
attribute vec2 aVertexTextureCoord;
varying highp vec2 vTextureCoord;
void main(void){
gl_Position = projMat4 * vec4(aPos, 1);
vTextureCoord = aVertexTextureCoord;
}
`
//负责颜色定义
const fs = `
varying highp vec2 vTextureCoord;
uniform sampler2D uSampler;
void main(void) {
gl_FragColor = texture2D(uSampler, vTextureCoord);
}
`
// 顶点着色器程序-绘制到帧缓存
var fvs =
'attribute vec4 a_Position;n' + //位置
'uniform mat4 u_MvpMatrix;n' +
'void main() {n' +
' gl_Position = u_MvpMatrix * a_Position;n' + // 设置顶点坐标
'}n';
// 片元着色器程序-绘制到帧缓存
var ffs =
'precision mediump float;n' +
'uniform vec4 color;n' +
'void main() {n' +
' gl_FragColor = color;n' + //将深度保存在FBO中
'}n';
const vertex = [0, 0, 0.0, 750, 0, 0.0, 750, 750, 0.0, 0, 750, 0.0]
const fvertex = [
50, 50, 0.0,
100, 50, 0.0,
100, 100, 0.0,
50, 100, 0.0
]
const fvertexIndice = [0, 1, 2, 0, 2, 3]
const a_Color = [1, 0, 0, 1]
const vertexIndice = [0, 1, 2, 0, 2, 3]
const texCoords = [0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0]
//用于创建SHADER函数
function createShader(gl, src, type) {
const shader = gl.createShader(type)
//创建SHADER
gl.shaderSource(shader, src)
//编译SHADER
gl.compileShader(shader)
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error('Error compiling shader: ' + gl.getShaderInfoLog(shader))
}
return shader
}
const buffers = {}
function createRenderer(canvas, width, height) {
//获取画布上下文 对象
const gl = canvas.getContext('webgl')
if (!gl) {
console.error('Unable to get webgl context.')
return
}
// 初始化帧缓冲区对象 (FBO)
var fbo = initFramebufferObject(gl);
var fbo2 = initFramebufferObject(gl);
if (!fbo) {
console.log('Failed to intialize the framebuffer object (FBO)');
return;
}
console.log(fbo)
const info = wx.getSystemInfoSync()
gl.canvas.width = info.pixelRatio * width
gl.canvas.height = info.pixelRatio * height
//设置画布大小
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)
glMatrix.mat4.ortho(
mat4,
0,
gl.drawingBufferWidth,
gl.drawingBufferHeight,
0,
-1000,
1000
)
//调用函数创建SHADER
const vertexShader = createShader(gl, vs, gl.VERTEX_SHADER)
const fragmentShader = createShader(gl, fs, gl.FRAGMENT_SHADER)
const fvertexShader = createShader(gl, fvs, gl.VERTEX_SHADER)
const ffragmentShader = createShader(gl, ffs, gl.FRAGMENT_SHADER)
//创建空程序
const program = gl.createProgram()
const fprogram = gl.createProgram()
//关联程序
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
gl.attachShader(fprogram, fvertexShader)
gl.attachShader(fprogram, ffragmentShader)
//链接程序
gl.linkProgram(program)
gl.linkProgram(fprogram)
if (!gl.getProgramParameter(program, gl.LINK_STATUS) || !gl.getProgramParameter(fprogram, gl.LINK_STATUS)) {
console.error('Unable to initialize the shader program.')
return
}
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA);
{
//使用链接好的程序
gl.useProgram(fprogram)
//正交投影
const aprojMat4 = gl.getUniformLocation(fprogram, 'u_MvpMatrix')
gl.uniformMatrix4fv(aprojMat4, false, mat4)
const color = gl.getUniformLocation(fprogram, 'color')
gl.uniform4f(color, 1, 0, 0, .5)
//使用链接好的程序
gl.useProgram(program)
//正交投影
const projMat4 = gl.getUniformLocation(program, 'projMat4')
gl.uniformMatrix4fv(projMat4, false, mat4)
//纹理对应显示区域用的
//创建uv缓冲区
buffers.trianglesTexCoordBuffer = gl.createBuffer()
//指定缓冲区存储类型
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.trianglesTexCoordBuffer)
//给缓冲区赋值(数据类型, 数据, 是否动态)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW)
//设置uv纹理对应显示区域
const vertexTexCoordAttribute = gl.getAttribLocation(
program,
'aVertexTextureCoord'
)
//启用顶点属性数组
gl.enableVertexAttribArray(vertexTexCoordAttribute)
//指定绘制顶点数据 (数据, 维度, 数据类型, 是否规格化, )
gl.vertexAttribPointer(vertexTexCoordAttribute, 2, gl.FLOAT, false, 0, 0)
//启用纹理
const samplerUniform = gl.getUniformLocation(program, 'uSampler')
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, fbo.texture);
gl.uniform1i(samplerUniform, 0)
gl.useProgram(null);
}
return (arrayBuffer, width, height) => {
console.log('render')
//帧缓存绘制
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo); //将绘制目标切换为帧缓冲区对象FBO
gl.viewport(0, 0, 375, 375); // 为FBO设置一个视口
gl.clearColor(0.2, 0.2, 0.4, 1.0); // Set clear color (the color is slightly changed)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Clear FBO
gl.useProgram(program); //准备生成纹理贴图
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGBA,
width,
height,
0,
gl.RGBA,
gl.UNSIGNED_BYTE,
arrayBuffer
)
//绘制索引
//(画三角形, 次数, 数据类型, 偏移量)
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0)
gl.useProgram(fprogram); //准备生成纹理贴图
//显示区域大小
//创建缓冲区
buffers.fvertexBuffer = gl.createBuffer()
//指定缓冲区存储类型
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.fvertexBuffer)
//给缓冲区赋值(数据类型, 数据, 是否动态)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(fvertex), gl.STATIC_DRAW)
//创建索引缓冲区
buffers.fvertexIndiceBuffer = gl.createBuffer()
//指定缓冲区存储类型
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.fvertexIndiceBuffer)
//给缓冲区赋值(数据类型, 数据, 是否动态)
gl.bufferData(
gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array(fvertexIndice),
gl.STATIC_DRAW
)
//设置显示区域大小
//绑定输入变量名
const a_Position = gl.getAttribLocation(fprogram, 'a_Position')
//启用顶点属性数组
gl.enableVertexAttribArray(a_Position)
//指定绘制顶点数据 (数据, 维度, 数据类型, 是否规格化, )
gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, 0, 0)
//绘制索引
//(画三角形, 次数, 数据类型, 偏移量)
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0)
//颜色缓存绘制
gl.bindFramebuffer(gl.FRAMEBUFFER, null); //将绘制目标切换为颜色缓冲区
gl.viewport(0, 0, 750, 750); // 设置视口为当前画布的大小
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Clear the color buffer
gl.useProgram(program); // 准备进行绘制
//显示区域大小
//创建缓冲区
buffers.vertexBuffer = gl.createBuffer()
//指定缓冲区存储类型
gl.bindBuffer(gl.ARRAY_BUFFER, buffers.vertexBuffer)
//给缓冲区赋值(数据类型, 数据, 是否动态)
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertex), gl.STATIC_DRAW)
//创建索引缓冲区
buffers.vertexIndiceBuffer = gl.createBuffer()
//指定缓冲区存储类型
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.vertexIndiceBuffer)
//给缓冲区赋值(数据类型, 数据, 是否动态)
gl.bufferData(
gl.ELEMENT_ARRAY_BUFFER,
new Uint16Array(vertexIndice),
gl.STATIC_DRAW
)
//设置显示区域大小
//绑定输入变量名
const aVertexPosition = gl.getAttribLocation(program, 'aPos')
//启用顶点属性数组
gl.enableVertexAttribArray(aVertexPosition)
//指定绘制顶点数据 (数据, 维度, 数据类型, 是否规格化, )
gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0)
//绘制索引
//(画三角形, 次数, 数据类型, 偏移量)
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0)
}
}
// 初始化帧缓冲区对象 (FBO)
function initFramebufferObject(gl) {
var framebuffer, texture, depthBuffer;
// Define the error handling function
var error = function () {
if (framebuffer) gl.deleteFramebuffer(framebuffer);
if (texture) gl.deleteTexture(texture);
if (depthBuffer) gl.deleteRenderbuffer(depthBuffer);
return null;
}
// 创建帧缓冲区对象 (FBO)
framebuffer = gl.createFramebuffer();
if (!framebuffer) {
console.log('Failed to create frame buffer object');
return error();
}
// 创建纹理对象并设置其尺寸和参数
texture = gl.createTexture(); // 创建纹理对象
if (!texture) {
console.log('Failed to create texture object');
return error();
}
gl.bindTexture(gl.TEXTURE_2D, texture); // Bind the object to target
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 375, 375, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
// 设置纹理参数
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
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);
framebuffer.texture = texture; // 保存纹理对象
// 创建渲染缓冲区对象并设置其尺寸和参数
depthBuffer = gl.createRenderbuffer(); //创建渲染缓冲区
if (!depthBuffer) {
console.log('Failed to create renderbuffer object');
return error();
}
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer); // Bind the object to target
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, 375, 375);
// 将纹理和渲染缓冲区对象关联到帧缓冲区对象上
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); //关联颜色
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer); //关联深度
// 检查帧缓冲区是否被正确设置
var e = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (gl.FRAMEBUFFER_COMPLETE !== e) {
console.log('Frame buffer object is incomplete: ' + e.toString());
return error();
}
// Unbind the buffer object
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
return framebuffer;
}
const img = 'http://192.168.1.185:8080/test.png'
let imageData = null
Page({
/**
- 页面的初始数据
*/
data: {},
/**
- 生命周期函数--监听页面加载
*/
onLoad: function (options) { },
/**
- 生命周期函数--监听页面初次渲染完成
*/
async onReady() {
const that = this
this.canvas = wx.createCanvasContext('pose', this)
await new Promise((resolve, reject) => {
wx.downloadFile({
url: img,
success: async function (sres) {
await that.canvas.drawImage(sres.tempFilePath, 0, 0, 375, 375)
await that.canvas.draw(true)
setTimeout(() => {
wx.canvasGetImageData({
canvasId: 'pose',
x: 0,
y: 0,
width: 375,
height: 375,
success(res) {
const imgData = {
data: new Uint8Array(res.data),
width: 375,
height: 375
}
resolve(imgData)
},
complete(res) { }
})
}, 2000)
},
fail: function (fres) { }
})
}).then(imgData => {
imageData = imgData
})
const query = wx.createSelectorQuery()
query
.select('#webgl')
.node(this.init.bind(this))
.exec()
// query
// .select('#c2d')
// .node(this.init2.bind(this))
// .exec()
},
init(res) {
const canvas = res.node
const render = createRenderer(canvas, 375, 375)
render(imageData.data, imageData.width, imageData.height)
},
/**
- 生命周期函数--监听页面显示
*/
onShow: function () { },
/**
- 生命周期函数--监听页面隐藏
*/
onHide: function () { },
/**
- 生命周期函数--监听页面卸载
*/
onUnload: function () { },
/**
- 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () { },
/**
- 页面上拉触底事件的处理函数
*/
onReachBottom: function () { },
/**
- 用户点击右上角分享
*/
onShareAppMessage: function () { }
})
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论