这节是重点,应该多写写。高级的渲染都要涉及到渲染到纹理。
在dx中,初始化设定surface和纹理后,每帧 setrendertarget,获得离屏纹理,然后传递给需要的物体。
同样,在webgl中,也是这样,
dx中的surface,在webgl称作帧缓冲区对象,后者分为颜色关联对象,深度关联对象和模板关联对象
dx中 的texture,在webgl中划分为两部分,纹理对象和渲染缓冲区对象。其中纹理对象对应颜色关联对象,即绘制颜色;渲染缓冲区对象是个控制消隐和模板的,即对应深度关联对象和模板关联对象。
步骤即:先创建对象,再关联对象绑定,再检查帧缓冲区是否正确配置,最后配置
具体如下:
1,创建帧缓冲区对象(gl.createFrameBuffer());
2,创建纹理对象并设置尺寸和参数(gl.createTexture(),gl.bindTexture(), gl.texImage2D(),gl.Parameteri()
3,创建渲染缓冲区对象(gl.createRenderBuffer())
4,绑定渲染缓冲区对象并设置其尺寸(gl.bindRenderBuffer(),gl.renderBufferStorage())
5,将帧缓冲区的颜色关联对象指定为一个纹理对象(gl.FrameBufferTexture2d())
6,将帧缓冲区的深度管理对象指定为一个渲染缓冲区对象(gl.framebufferRenderBuffer())
7,检查帧缓冲区是否正确配置(gl.checkFrameBufferStatus())
8,在帧缓冲区中进行绘制(gl.bindFrameBuffer())
代码如下:
<html>
<head>11</head>
<body>
<canvas id = "test" width = "800" height = "800">canvas </canvas>
<script src = "webgltest/cuon-matrix.js"></script>
<script >
//顶点着色器
var vertexShaderSource =
'attribute vec4 a_Position;\n' +
'attribute vec2 a_TexCoord;\n' +
'uniform mat4 u_MvpMatrix;\n' +
'varying vec2 v_TexCoord;\n'+
'void main() {\n' +
'gl_Position = u_MvpMatrix * a_Position;\n'+
'v_TexCoord = a_TexCoord;\n' +
'}\n';
//片元着色器
var fragmentShaderSource =
'precision mediump float;\n' +
'uniform sampler2D u_Sampler;\n' +
'varying vec2 v_TexCoord;\n' +
'void main() {\n' +
'gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' + //将数据传给片元着色器
'}\n';
//离屏绘制尺寸
var OFFSCREEN_WIDTH = 256;
var OFFSCREEN_HEIGHT = 256;
//创建着色器方法,输入参数:渲染上下文,着色器类型,数据源
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;
}
console.log(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
}
//将顶点着色器和像素着色器链接到一个着色程序
function createProgram(gl, vertexShader, fragmentShader)
{
var program = gl.createProgram();
gl.attachShader( program, vertexShader);
gl.attachShader( program, fragmentShader);
gl.linkProgram( program );
var success = gl.getProgramParameter(program, gl.LINK_STATUS);
if(success)
{
console.log("link right");
return program;
}
console.log(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
}
//创建顶点缓冲区和索引缓冲区
function initVertexBuffersForCube(gl) {
// Create a cube
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
// Vertex coordinates
var 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
]);
// Texture coordinates
var 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
]);
// Indices of the vertices
var 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
]);
var theObject = new Object();
theObject.vertexBuffer = initArrayBufferForLateruse(gl, vertices, 3, gl.FLOAT);
theObject.texcoordBuffer = initArrayBufferForLateruse(gl, texCoords, 2, gl.FLOAT);
theObject.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
if( !theObject.vertexBuffer || !theObject.texcoordBuffer || !theObject.indexBuffer)
{
console.log("theObject.vertexBuffer texcoordBuffer indexBuffer error");
return null;
}
theObject.numIndices = indices.length;
console.log(theObject.numIndices);
//解绑
gl.bindBuffer(gl.ARRAY_BUFFER, null );
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
return theObject;
}
//创建顶点缓冲区和索引缓冲区
function initVertexBuffersForPlane(gl) {
// Create face
// v1------v0
// | |
// | |
// | |
// v2------v3
// Vertex coordinates
var vertices = new Float32Array([
1.0, 1.0, 0.0, -1.0, 1.0, 0.0, -1.0,-1.0, 0.0, 1.0,-1.0, 0.0 // v0-v1-v2-v3
]);
// Texture coordinates
var texCoords = new Float32Array([1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0]);
// Indices of the vertices
var indices = new Uint8Array([0, 1, 2, 0, 2, 3]);
var theObject = new Object();
theObject.vertexBuffer = initArrayBufferForLateruse(gl, vertices, 3, gl.FLOAT);
theObject.texcoordBuffer = initArrayBufferForLateruse(gl, texCoords, 2, gl.FLOAT);
theObject.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
if( !theObject.vertexBuffer || !theObject.texcoordBuffer || !theObject.indexBuffer)
{
return null;
}
theObject.numIndices = indices.length;
//解绑
gl.bindBuffer(gl.ARRAY_BUFFER, null );
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
return theObject;
}
function initElementArrayBufferForLaterUse(gl, data, type)
{
// Create a buffer object
var indexBuffer = gl.createBuffer();
if (!indexBuffer)
{
console.log('Failed to create the buffer object');
return -1;
}
// Write the indices to the buffer object
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);
indexBuffer.type = type;
return indexBuffer;
}
function initArrayBufferForLateruse(gl, data, num, type) {
var buffer = gl.createBuffer(); // Create a buffer object
if (!buffer) {
console.log('Failed to create the buffer object');
return false;
}
// Write date into the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
buffer.num = num;
buffer.type = type
return buffer;
}
function loadTexture(gl, texture, u_Sampler, image)
{
//对纹理图像进行y轴翻转
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);
//开启0号纹理单元
//gl.activeTexture(gl.TEXTURE0);
//向target绑定纹理对象
gl.bindTexture(gl.TEXTURE_2D, texture);
//配置纹理参数
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
//配置纹理图像
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
//将0号纹理传递给着色器
gl.uniform1i(u_Sampler, 0 );
//解绑纹理
gl.bindTexture(gl.TEXTURE_2D, null);
}
function initTextures(gl,program)
{
//创建纹理对象
var texture = gl.createTexture();
if (!texture)
{
console.log('Failed to create the texture object');
return false;
}
console.log('success to create the texture object');
//获取u_Sampler的存储位置
var u_Sampler = gl.getUniformLocation(program,'u_Sampler');
if (!u_Sampler)
{
console.log('Failed to get the storage location of u_Sampler');
return false;
}
console.log('success to get the storage location of u_Sampler');
//创建一个image对象
var image = new Image();
if (!image)
{
console.log('Failed to create the image object');
return false;
}
console.log('success to create the image object');
//注册图像加载事件的响应函数
image.onload = function()
{
loadTexture(gl, texture, u_Sampler, image);
}
image.src = 'http://localhost:8080/apps/resources/sky.jpg';
return texture;
}
function initFrameBufferObject(gl)
{
var frameBuffer, texture, depthBuffer;
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);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT, 0, gl.RGBA, gl.UNSIGNED_BYTE, null );
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR );
frameBuffer.texture = texture;
//创建渲染缓冲区对象,并设置大小和参数
depthBuffer = gl.createRenderbuffer();
if(!depthBuffer)
{
console.log('Failed to create renderbuffer object');
return error();
}
//连接对象到目标
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT );
//连接纹理对象和渲染缓冲区对象到FBO
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);
//判断FBO是否配置正确
var e = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if(gl.FRAMEBUFFER_COMPLETE !== e )
{
console.log('Frame buffer object is incomplete:' + e.toString());
return error();
}
//解绑缓存对象
gl.bindFramebuffer(gl.FRAMEBUFFER, null );
gl.bindTexture(gl.TEXTURE_2D, null );
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
return frameBuffer;
}
function initAttributeVariable(gl, a_attribute, buffer, bufferNum, bufferType )
{
gl.bindBuffer(gl.ARRAY_BUFFER, buffer );
gl.vertexAttribPointer(a_attribute, bufferNum, bufferType, false, 0, 0 );
gl.enableVertexAttribArray(a_attribute);
}
function drawTexturedObject(gl, program, positionHandle, texCoordHandle,MvpMatrixHandle,theObject, texture )
{
initAttributeVariable(gl, positionHandle, theObject.vertexBuffer, theObject.vertexBuffer.num, theObject.vertexBuffer.type );
initAttributeVariable(gl, texCoordHandle, theObject.texcoordBuffer, theObject.texcoordBuffer.num, theObject.texcoordBuffer.type );
//绑定纹理对象到目标
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture );
//绘制
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theObject.indexBuffer );
gl.drawElements(gl.TRIANGLES, theObject.numIndices, theObject.indexBuffer.type, 0 );
}
function drawTexturedCube(gl, program,positionHandle, texCoordHandle,MvpMatrixHandle, theObject, angle, texture, g_modelMatrix, viewProjMatrix, g_mvpMatrix)
{
g_modelMatrix.setRotate(20.0, 1.0, 0.0, 0.0 );
g_modelMatrix.rotate(angle, 0.0, 1.0, 0.0 );
g_mvpMatrix.set(viewProjMatrix);
g_mvpMatrix.multiply(g_modelMatrix);
gl.uniformMatrix4fv(MvpMatrixHandle, false, g_mvpMatrix.elements );
drawTexturedObject(gl, program, positionHandle, texCoordHandle,MvpMatrixHandle,theObject, texture );
console.log(theObject.numIndices);
}
function drawTexturedPlane(gl, program,positionHandle, texCoordHandle,MvpMatrixHandle, theObject, angle, texture, g_modelMatrix, viewProjMatrix, g_mvpMatrix)
{
g_modelMatrix.setTranslate(0,0,1);
g_modelMatrix.rotate(20.0, 1.0, 0.0, 0.0 );
g_modelMatrix.rotate(angle, 0.0, 1.0, 0.0 );
g_mvpMatrix.set(viewProjMatrix);
g_mvpMatrix.multiply(g_modelMatrix);
gl.uniformMatrix4fv(MvpMatrixHandle, false, g_mvpMatrix.elements );
drawTexturedObject(gl, program,positionHandle, texCoordHandle, MvpMatrixHandle,theObject, texture );
}
var canvas = document.getElementById("test");
//创建webgl渲染上下文
var gl = canvas.getContext("webgl");
if(!gl)
{
console.log("wrong");
}
else
{
console.log("right");
}
//初始化着色器
var vertexShader = createShader(gl,gl.VERTEX_SHADER,vertexShaderSource);
var fragmentShader = createShader(gl,gl.FRAGMENT_SHADER, fragmentShaderSource);
var program = createProgram(gl, vertexShader, fragmentShader);
var positionHandle = gl.getAttribLocation(program, 'a_Position');
var texCoordHandle = gl.getAttribLocation(program, 'a_TexCoord');
var MvpMatrixHandle = gl.getUniformLocation(program, 'u_MvpMatrix');
gl.useProgram(program);
//创建顶点数组
var cube = initVertexBuffersForCube(gl);
var plane = initVertexBuffersForPlane(gl);
if(!cube || !plane )
{
console.log('Failed to set the Vertex information');
}
//设置纹理
var texture = initTextures(gl,program);
if( !texture )
{
console.log('Failed to initialize the texture');
}
//创建帧缓存对象
var fbo = initFrameBufferObject(gl);
if(!fbo)
{
console.log('Failed to initialize FBO');
}
//模型矩阵
var g_modelMatrix = new Matrix4();
//模型视图投影矩阵
var g_mvpMatrix = new Matrix4();
var rotateDeg = 1.0;
//开启隐藏面消除功能
gl.enable(gl.DEPTH_TEST);
var viewProjMatrix = new Matrix4();
viewProjMatrix.setPerspective(30, canvas.width / canvas.height,0.1, 100.0);
viewProjMatrix.lookAt(0,0,7,0,0,0,0,1,0);
var viewProjMatrixFBO = new Matrix4();
viewProjMatrixFBO.setPerspective(30, OFFSCREEN_WIDTH / OFFSCREEN_HEIGHT,0.1, 100.0);
viewProjMatrixFBO.lookAt(0,2.0,7,0,0,0,0,1,0);
var mytick = function()
{
//绑定帧缓冲区对象
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo );
//定义离线绘图的绘图区域
gl.viewport(0, 0, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT );
//清空帧缓冲区
gl.clearColor( 0.2, 0.2, 0.4, 1.0 );
//gl.clearColor( 1.0, 0.0, 0.0, 1.0 );
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
//绘制立方体
drawTexturedCube(gl, program, positionHandle, texCoordHandle, MvpMatrixHandle,cube, rotateDeg, texture, g_modelMatrix, viewProjMatrixFBO, g_mvpMatrix);
//
//解绑fbo
gl.bindFramebuffer(gl.FRAMEBUFFER, null );
gl.viewport(0, 0, canvas.width, canvas.height );
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
drawTexturedPlane(gl, program, positionHandle, texCoordHandle,MvpMatrixHandle,plane, 0, fbo.texture, g_modelMatrix, viewProjMatrix, g_mvpMatrix);
rotateDeg += 1
requestAnimationFrame(mytick);
}
mytick();
</script>
</body>
</html>