纹理贴图旋转-阴影绘制
以texture_rotateCude.html为基础
1.新建着色器
1.//创建一个阴影顶点、片元着色器
var SHADOW_VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'uniform mat4 u_MvpMatrix;\n' +
'uniform mat4 u_rotateMatrix;\n' +
'void main() {\n' +
//gl_Position有深度记录Fshader中可以拿到
' gl_Position = (a_Position.y >= -1.0) ? (u_MvpMatrix * u_rotateMatrix * a_Position) : (u_MvpMatrix * a_Position);\n' +
'}\n';
// Fragment shader program for generating a shadow map
var SHADOW_FSHADER_SOURCE =
'#ifdef GL_ES\n' +
'precision mediump float;\n' +
'#endif\n' +
'void main() {\n' +
//gl_FragCoord定位片元位置,记录纹理信息
' gl_FragColor = vec4(gl_FragCoord.z, 0.0, 0.0, 0.0);\n' + // Write the z-value in R
'}\n';
- 在主顶点着色器中
'uniform mat4 u_MvpMatrixFromLight;\n' +//从光源出发的视图投影矩阵
'varying vec4 v_PositionFromLight;\n' +//光源出发的模型位置
Main
' v_PositionFromLight = u_MvpMatrixFromLight * a_Position;\n' +//确定在光源下的模型位置
- 在主Fragment shader中
'uniform sampler2D u_ShadowMap;\n' +//传阴影贴图
'varying vec4 v_PositionFromLight;\n' +
Main
//阴影
' vec3 shadowCoord = (v_PositionFromLight.xyz/v_PositionFromLight.w)/2.0 + 0.5;\n' +//坐标转换(webGL的XY坐标-1-1->纹理坐标0-1)
' vec4 rgbaDepth = texture2D(u_ShadowMap, shadowCoord.xy);\n' +//取纹理值
' float depth = rgbaDepth.r;\n' + // 取以光源相机为视角的深度
' float visibility = (shadowCoord.z > depth + 0.005) ? 0.5 : 1.0;\n' +//比较渲染片元与shadowmap的情况,描述阴影
//颜色渲染(阴影渲染)
' gl_FragColor = vec4(r_Color.rgb * visibility, r_Color.a);\n' +
- 将关于program的封装为
//创建程序
function createProgram (gl, vSource, fSource) {
var program = gl.createProgram()
// define vertex shader
var vertexShader = createShader(gl, vSource, gl.VERTEX_SHADER)
// define frament shader
var fragmentShader = createShader(gl, fSource, gl.FRAGMENT_SHADER)
// attach shader to program
gl.attachShader(program, vertexShader)
gl.attachShader(program, fragmentShader)
// link program to context
gl.linkProgram(program)
return program
}
在主函数JS中
var normalProgram = createProgram(gl, VSHADER_SOURCE, FSHADER_SOURCE)//主程序
var shadowProgram = createProgram(gl, SHADOW_VSHADER_SOURCE, SHADOW_FSHADER_SOURCE)//shadowmap程序
gl.useProgram(normalProgram)
gl.program = normalProgram
- 重新定义initVertexBuffers
数据不变
其他改为
// Create a buffer object
var o = new Object();
var indexBuffer = gl.createBuffer();
// Write the indices to the buffer object主缓冲区灌入数据
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
o.indexBuffer = indexBuffer;
o.positionBuffer = initArrayBuffer(gl, vertices, 3, gl.FLOAT, gl.program);
o.normalBuffer = initArrayBuffer(gl, normals, 3, gl.FLOAT, gl.program)
o.texCoordBuffer = initArrayBuffer(gl, verticesTexCoords, 2, gl.FLOAT, gl.program)
//阴影缓冲区灌入数据
var shadowIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, shadowIndexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
o.shadowIndexBuffer = shadowIndexBuffer;
o.shadowPositionBuffer = initArrayBuffer(gl, vertices, 3, gl.FLOAT, shadowProgram);
o.n = indices.length;
return o;//返回对象
- 封装initAttributeVariable
//绑定attribute
function initAttributeVariable(gl,a_attribute,buffer) {
// Assign the buffer object to the attribute variable
// var a_attribute = gl.getAttribLocation(gl.program, attribute);
// if (a_attribute < 0) {
// console.log('Failed to get the storage location of ' + attribute);
// return false;
// }
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);//绑定缓冲区
//将当前绑定到gl.ARRAY_BUFFER的缓冲区到顶点缓存区
gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);
// Enable the assignment of the buffer object to the attribute variable
gl.enableVertexAttribArray(a_attribute);//许可缓冲区分配变量
}
- 改变initArrayBuffer
function initArrayBuffer(gl, data, num, type, program) {
// Create a buffer object
var buffer = gl.createBuffer();
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);
gl.bindBuffer(gl.ARRAY_BUFFER, null);//清空bindBuffer中的gl.ARRAY_BUFFER缓存区
buffer.num = num
buffer.type = type
return buffer;
}
- 在JS主程中
// write the positions of vertices to a vertex shader
var o = initVertexBuffers(gl)
var n = o.n
initTexture(gl, n)//加载纹理贴图
var fbo = initFramebufferObject(gl);//创建阴影对象
gl.activeTexture(gl.TEXTURE0); // Set a texture object to the texture unit激活
gl.bindTexture(gl.TEXTURE_2D, fbo.texture);//绑定纹理
//阴影设置
var u_MvpMatrixFromLight = gl.getUniformLocation(gl.program, 'u_MvpMatrixFromLight');
var u_ShadowMvpMatrix = gl.getUniformLocation(shadowProgram, 'u_MvpMatrix');
var u_ShadowRotateMatrix = gl.getUniformLocation(shadowProgram, 'u_rotateMatrix');
var shadowMvpMatrix = new Matrix4();
shadowMvpMatrix.setPerspective(30, 1, 1, 100);
shadowMvpMatrix.lookAt(0, 21, 0, 0, 0, 0, 0, 0, 1);//阴影位置
gl.uniformMatrix4fv(u_MvpMatrixFromLight, false, shadowMvpMatrix.elements)
//attribute获取设置
var u_ShadowMap = gl.getUniformLocation(gl.program, 'u_ShadowMap');//阴影纹理
var positionLocation = gl.getAttribLocation(gl.program, 'a_Position');
var normalLocation = gl.getAttribLocation(gl.program, 'a_Normal');
var texCoordLocation = gl.getAttribLocation(gl.program, 'a_TexCoord');
var shadowPositionLocation = gl.getAttribLocation(shadowProgram, 'a_Position');
- draw中
//绘制阴影的片元
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.viewport(0, 0, OFFSCREEN_HEIGHT, OFFSCREEN_HEIGHT);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Clear FBO
gl.useProgram(shadowProgram); // Set shaders for generating a shadow map
initAttributeVariable(gl, shadowPositionLocation, o.shadowPositionBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, o.shadowIndexBuffer);
gl.uniformMatrix4fv(u_ShadowRotateMatrix, false, rotateMatrix.elements);
gl.uniformMatrix4fv(u_ShadowMvpMatrix, false, shadowMvpMatrix.elements);
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
//回到主程序改变贴图添加阴影
gl.bindFramebuffer(gl.FRAMEBUFFER, null); // Change the drawing destination to color buffer
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Clear color and depth buffer
gl.useProgram(gl.program);
initAttributeVariable(gl, normalLocation, o.normalBuffer);
initAttributeVariable(gl, positionLocation, o.positionBuffer);
initAttributeVariable(gl, texCoordLocation, o.texCoordBuffer);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, o.indexBuffer);
gl.uniform1i(u_ShadowMap, 0); // Pass 0 because gl.TEXTURE0 is enabledする
gl.uniformMatrix4fv(u_RotateMatrix, false, rotateMatrix.elements);
// Draw the cube索引方式绘制(三角面,绘制点数,前面的数据类型,偏移)
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
- initFramebufferObject
//初始化片元对象-阴影帧缓存区创建
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;
}
// Create a framebuffer object (FBO)
framebuffer = gl.createFramebuffer();//创建片元缓冲区
if (!framebuffer) {
console.log('Failed to create frame buffer object');
return error();
}
// Create a texture object and set its size and parameters
texture = gl.createTexture(); // Create a texture object
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);//将纹理放入activeTexture
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);//纹理映射
// Create a renderbuffer object and Set its size and parameters
//真正使用的缓冲区
depthBuffer = gl.createRenderbuffer(); // Create a renderbuffer object
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);//分配存储区
// Attach the texture and the renderbuffer object to the 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);
// Check if FBO is configured correctly
var e = gl.checkFramebufferStatus(gl.FRAMEBUFFER);//检查帧缓冲区状态
if (gl.FRAMEBUFFER_COMPLETE !== e) {
console.log('Frame buffer object is incomplete: ' + e.toString());
return error();
}
framebuffer.texture = texture; // keep the required object
// Unbind the buffer object清空绑定
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
return framebuffer;
}
结束。源码github。