问答

关于webgl的fbo缓冲帧的问题。

作者:admin 2021-09-17 我要评论

有一个业务需求是在webgl画布上绘制一张图片纹理,然后在图片纹理上绘制一个多边形,需要两步绘制完,再输出到画布上,所以就用到fbo离屏渲染,但不知道是不是我...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

有一个业务需求是在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 () { }
})

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • 关于webgl的fbo缓冲帧的问题。

    关于webgl的fbo缓冲帧的问题。

  • IDEA在mapper.xml中快速执行sql测试时,

    IDEA在mapper.xml中快速执行sql测试时,

  • POI读取xlsx出错?

    POI读取xlsx出错?

  • react项目install时报错

    react项目install时报错

腾讯云代理商
海外云服务器