简单封装绘制前流程
前言
webgl绘制前流程复杂繁琐,这里将其做一个简单封装,以便了解其流程。
提示:以下是本篇文章正文内容,下面案例可供参考
一、引入cuon-utils.js和cuon-matrix.js
import cuonUtils from './cuon-utils'
import cuonMatrix from './cuon-matrix'
cuonUtils封装了一些webgl方法,这里就用来创建webgl程序,cuonMatrix提供矩阵方法,这里拿来设置modelMatrix
二、主要流程
1.先获取着色器申明变量getAttribLocation
2.将顶点信息写入缓冲区对象 将数据保存
3.设置getUniformLocation
4.创建VP矩阵
5.绘制时先分配缓冲对象并启用赋值,再绘制
总结
有错误希望大佬指正
代码(mesh.js):
import cuonUtils from './cuon-utils'
import cuonMatrix from './cuon-matrix'
class mesh {
/*
attributeData:{
vertices:Float32Array,
normals:Float32Array,
indices:Uint8Array,
}
*/
constructor(gl,attributeData={}){
this.gl = gl
this.modelMatrix = new cuonMatrix.Matrix4();
this.geometry = {}
this.material = {
VSHADER_SOURCE:`
attribute vec3 a_Position;
attribute vec3 a_Normal;
// attribute vec3 a_Color;
uniform mat4 u_ModelMatrix;
uniform mat4 u_VPMatrix;
// varying vec3 v_Color;
varying vec3 v_Normal;
void main(){
// v_Color = a_Color;
v_Normal = a_Normal;
gl_Position = u_VPMatrix * u_ModelMatrix * vec4( a_Position , 1.0 );
}`,
FSHADER_SOURCE:`
#ifdef GL_ES
precision mediump float;
#endif
// varying vec3 v_Color;
varying vec3 v_Normal;
void main(){
// gl_FragColor = vec4( v_Color , 1.0 );
gl_FragColor = vec4( v_Normal , 1.0 );
// gl_FragColor = vec4( 1.0 , 0 ,0 , 1.0 );
}`
}
this.program = cuonUtils.createProgram( gl, this.material.VSHADER_SOURCE , this.material.FSHADER_SOURCE )
this.setAttribute(attributeData)
}
/*
设置uniform
@param type 数据类型
@param target uniform名称 (string)
@param value uniform值
@param isBefore 是否为预先准备(只获取UniformLocation)
@return void
*/
setUniform(type,target,value){
if(this.gl.program !== this.program){
this.gl.useProgram(this.program);
}
let u_target;
if(this.program[target] === void 0){
u_target = this.gl.getUniformLocation( this.program, target );
if (u_target < 0) {
console.log(`无法获取${target}uniform`);
return;
}
this.program[target] = u_target
}else{
u_target = this.uniformTarget[target]
}
if(type == 'bool'){
}
if(type == 'int'){
}
if(type == 'float'){
}
if(type == 'vec3'){
}
if(type == 'mat4'){
this.gl.uniformMatrix4fv(u_target,false,value)
}
}
//设置geo数据
setAttribute(attributeData){
let gl = this.gl;
this.program.a_Position = gl.getAttribLocation(this.program, "a_Position");
this.program.a_Normal = gl.getAttribLocation(this.program, "a_Normal");
let vertices = attributeData.vertices
let normals = attributeData.normals
let texCoords = new Float32Array([ // 纹理的坐标
1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v1-v2-v3 front
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, // v0-v3-v4-v5 right
1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, // v0-v5-v6-v1 up
1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v1-v6-v7-v2 left
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, // v7-v4-v3-v2 down
0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0 // v4-v7-v6-v5 back
]);
let indices = attributeData.indices
//将顶点信息写入缓冲区对象
this.geometry.vertexBuffer = this.initArrayBufferForLaterUse( vertices, 3, gl.FLOAT);
this.geometry.normalBuffer = this.initArrayBufferForLaterUse( normals, 3, gl.FLOAT);
// this.geometry.texCoordBuffer = this.initArrayBufferForLaterUse( texCoords, 2, gl.FLOAT);
this.geometry.indexBuffer = this.initElementArrayBufferForLaterUse( indices, gl.UNSIGNED_BYTE);
// if (!this.geometry.vertexBuffer || !this.geometry.normalBuffer || !this.geometry.texCoordBuffer || !this.geometry.indexBuffer) {
// return this.$message.error("顶点信息写入缓冲区对象错误");;
// }
if (!this.geometry.vertexBuffer || !this.geometry.normalBuffer || !this.geometry.indexBuffer) {
return this.$message.error("顶点信息写入缓冲区对象错误");;
}
this.geometry.numIndices = indices.length;
//取消绑定焦点的数据
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
}
draw(){
let gl = this.gl;
let program = this.program
//分配缓冲对象并启用赋值
this.initAttributeVariable(gl, program.a_Position, this.geometry.vertexBuffer); //顶点坐标
this.initAttributeVariable(gl, program.a_Normal, this.geometry.normalBuffer); //法向量
// this.initAttributeVariable(gl, program.a_TexCoord, this.geometry.texCoordBuffer); //纹理坐标
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.geometry.indexBuffer);
//设置好纹理对象,开启使用0号的纹理
// gl.activeTexture(gl.TEXTURE0);
// gl.bindTexture(gl.TEXTURE_2D, texture);
this.setUniform('mat4',"u_ModelMatrix",this.modelMatrix.elements)
gl.drawElements(gl.TRIANGLES, this.geometry.numIndices, this.geometry.indexBuffer.type, 0);
}
//初始化缓冲区对象
initElementArrayBufferForLaterUse(data, type) {
let gl = this.gl;
let buffer = gl.createBuffer(); //创建一个缓冲区对象
if (!buffer) {
console.log("无法创建缓冲区对象");
return;
}
//将数据写入缓冲区
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);
buffer.type = type;
return buffer;
}
//初始化缓冲区对象
initArrayBufferForLaterUse(data, num, type) {
let gl = this.gl;
let buffer = gl.createBuffer(); // 创建一个缓冲区对象
if (!buffer) {
console.log("无法创建缓冲区对象");
return;
}
//将数据写入缓冲区对象
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
//保留必要的信息,以便后面使用
buffer.num = num;
buffer.type = type;
return buffer;
}
//绑定attribute
initAttributeVariable(gl, a_attribute, buffer) {
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);
gl.enableVertexAttribArray(a_attribute);
}
}
export default mesh
使用:
<template>
<div>
<div>
<canvas id="mycanvas"></canvas>
</div>
</div>
</template>
<script>
import Stats from './js/stats'//刷新率展示
import cuonMatrix from './js/cuon-matrix'
import Mesh from './js/mesh.js'
export default {
data () {
return {
stats:'',//刷新率展示插件
canvas:'',
gl:'',
clock:0,
myMesh:'',
myMesh2:'',
}
},
mounted(){
this.$nextTick(()=>{
this.init()
})
},
methods: {
init(){
let canvas = document.getElementById('mycanvas')
canvas.width = 300
canvas.height = 300
canvas.style.border = '10px solid yellow'
this.canvas = canvas
this.gl = canvas.getContext('webgl')
//刷新率插件
this.initStats()
this.main()
},
main(){
let gl = this.gl
if(!gl){return this.$message.error('垃圾浏览器')}
//添加mesh
let a01 = this.getAttributeData01()
let a02 = this.getAttributeData02()
this.myMesh = new Mesh( gl, a01 )
this.myMesh2 = new Mesh( gl, a02 )
//设置底色 和隐藏面消除
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
//进入场景初始化
this.animation()
},
animation(){
this.clock += 1
this.stats.update();//更新刷新率插件
this.draw(this.gl)
// window.requestAnimationFrame(this.animation);
},
draw(gl){
//获取视图VP矩阵
let VPmat4 = this.getviewprojMatrix()
// VPmat4.elements[12] = 8
//开启隐藏面清除(深度测试)
gl.enable(gl.DEPTH_TEST);
//清空颜色和深度缓冲区
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//绘制图形
this.myMesh.setUniform('mat4',"u_VPMatrix",VPmat4.elements)
// console.log(this.myMesh)
this.myMesh.draw()
// VPmat4.elements[13] = 8
this.myMesh2.modelMatrix.elements[13] = 8
this.myMesh2.setUniform('mat4',"u_VPMatrix",VPmat4.elements)
this.myMesh2.draw()
},
/*
获取vp矩阵
*/
getviewprojMatrix(){
let canvas = this.canvas
//设置视角矩阵的相关信息(视点,视线,上方向)
let viewMatrix = new cuonMatrix.Matrix4();
viewMatrix.setLookAt(0,10,10,0,0,0,0,1,0);
//设置透视投影矩阵
let projMatrix = new cuonMatrix.Matrix4();
projMatrix.setPerspective(75,canvas.width/canvas.height,0.1,1000);
return projMatrix.multiply(viewMatrix)
},
/* 获取立方体数据 */
getAttributeData01(){
let attributeData = {}
attributeData.vertices = new Float32Array([ // 单色立方体的顶点位置数据
1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, // v0-v1-v2-v3 front
1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, // v0-v3-v4-v5 right
1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, // v0-v5-v6-v1 up
-1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, // v1-v6-v7-v2 left
-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, // v7-v4-v3-v2 down
1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0 // v4-v7-v6-v5 back
]);
attributeData.normals = new Float32Array([ // 单色立方体的法相量
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, // v7-v4-v3-v2 down
0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0 // v4-v7-v6-v5 back
]);
attributeData.indices = new Uint8Array([// 索引值
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9, 10, 8, 10, 11, // up
12, 13, 14, 12, 14, 15, // left
16, 17, 18, 16, 18, 19, // down
20, 21, 22, 20, 22, 23 // back
]);
return attributeData
},
/* 获取三角面数据 */
getAttributeData02(){
let attributeData = {}
attributeData.vertices = new Float32Array([
1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0
]);
attributeData.normals = new Float32Array([
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0
]);
attributeData.indices = new Uint8Array([// 索引值
0, 1, 2,
]);
return attributeData
},
/* 初始化刷新率 */
initStats(){
let stats = new Stats();
this.stats = stats
stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
document.body.appendChild( stats.dom );
},
}
}
</script>
<style lang="scss" scoped>
</style>