这个例子其实没什么,主要是要注意光线坐标系的传递,以及纹理的传递
1,光源坐标系的传递,主要是要比较深度图的大小
gl.useProgram(program_shadowMap);
....
mvpMatrixFromLight_triangle.set(g_mvpMatrix);
....
mvpMatrixFromLight_plane.set(g_mvpMatrix);
.........
gl.useProgram(program_Normal);
gl.uniformMatrix4fv(MvpMatrixFromLightHandle_Normal, false, mvpMatrixFromLight_triangle.elements );
.......
gl.uniformMatrix4fv(MvpMatrixFromLightHandle_Normal, false, mvpMatrixFromLight_plane.elements );
2,纹理的绑定,这里绑定是按照第几个纹理绑定的,
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, fbo.texture);
绑定后,正常绘制后传递时,
var shadowMapHandle_Normal = gl.getUniformLocation(program_Normal, 'u_ShadowMap'); gl.uniform1i(shadowMapHandle_Normal, 0 );
具体代码如下:
<html>
<head>11</head>
<body>
<canvas id = "test" width = "800" height = "800">canvas </canvas>
<script src = "webgltest/cuon-matrix.js"></script>
<script >
//生成阴影贴图的顶点缓冲区
var SHADOW_VSHADER_SOURCE =
'attribute vec4 a_Position;\n' +
'uniform mat4 u_MvpMatrix; \n' +
'void main() {\n' +
'gl_Position = u_MvpMatrix * a_Position; \n' +
'}\n';
//生成阴影贴图的片元缓冲区
var SHADOW_FSHADER_SOURCE =
'precision mediump float;\n' +
'void main() {\n' +
'gl_FragColor = vec4(gl_FragCoord.z, 0.0, 0.0, 0.0); \n' +
'}\n';
//正常绘制时的顶点着色器
var vertexShaderSource =
'attribute vec4 a_Position;\n' +
'attribute vec4 a_Color;\n' +
'uniform mat4 u_MvpMatrix;\n' +
'uniform mat4 u_MvpMatrixFromLight;\n' +
'varying vec4 v_PositionFromLight;\n'+
'varying vec4 v_Color;\n' +
'void main() {\n' +
'gl_Position = u_MvpMatrix * a_Position;\n'+
'v_PositionFromLight = u_MvpMatrixFromLight * a_Position;\n' +
'v_Color = a_Color;\n' +
'}\n';
//片元着色器
var fragmentShaderSource =
'precision mediump float;\n' +
'uniform sampler2D u_ShadowMap;\n' +
'varying vec4 v_PositionFromLight;\n' +
'varying vec4 v_Color;\n' +
'void main() {\n' +
'vec3 shadowCoord = ( v_PositionFromLight.xyz / v_PositionFromLight.w ) / 2.0 + 0.5; \n' +
'vec4 rgbaDepth = texture2D(u_ShadowMap, shadowCoord.xy);\n' +
'float depth = rgbaDepth.r;\n' +
'float visibility = (shadowCoord.z > depth + 0.005 ) ? 0.7 : 1.0;\n' +
'gl_FragColor = vec4(v_Color.rgb * visibility, v_Color.a ); \n' +
'}\n';
//离屏绘制尺寸
var OFFSCREEN_WIDTH = 1024;
var OFFSCREEN_HEIGHT = 1024;
var LIGHT_X = 0.0;
var LIGHT_Y = 7.0;
var LIGHT_Z = 2.0;
var g_modelMatrix = new Matrix4();
var g_mvpMatrix = new Matrix4();
//创建着色器方法,输入参数:渲染上下文,着色器类型,数据源
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;
}
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)
{
return program;
}
gl.deleteProgram(program);
}
//创建顶点缓冲区和索引缓冲区
function initVertexBuffersForTriangle(gl)
{
// Create a triangle
// v2
// / |
// / |
// / |
// v0----v1
// Vertex coordinates
var vertices = new Float32Array([-0.8, 3.5, 0.0, 0.8, 3.5, 0.0, 0.0, 3.5, 1.8]);
// Colors
var colors = new Float32Array([1.0, 0.5, 0.0, 1.0, 0.5, 0.0, 1.0, 0.0, 0.0]);
// Indices of the vertices
var indices = new Uint8Array([0, 1, 2]);
var theObject = new Object();
theObject.vertexBuffer = initArrayBufferForLateruse(gl, vertices, 3, gl.FLOAT);
theObject.colorBuffer = initArrayBufferForLateruse(gl, colors, 3, gl.FLOAT);
theObject.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
if( !theObject.vertexBuffer || !theObject.colorBuffer || !theObject.indexBuffer)
{
return null;
}
theObject.numIndices = indices.length;
//解绑
gl.bindBuffer(gl.ARRAY_BUFFER, null );
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
return theObject;
}
//创建顶点缓冲区和索引缓冲区
function initVertexBuffersForPlane(gl)
{
// Vertex coordinates
var vertices = new Float32Array([
3.0, -1.7, 2.5, -3.0, -1.7, 2.5, -3.0, -1.7, -2.5, 3.0, -1.7, -2.5 // v0-v1-v2-v3
]);
// Colors
var colors = 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
]);
// 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.colorBuffer = initArrayBufferForLateruse(gl, colors, 3, gl.FLOAT);
theObject.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);
if( !theObject.vertexBuffer || !theObject.colorBuffer || !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)
{
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)
{
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 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)
{
return error();
}
//创建纹理对象,并设置大小和参数
texture = gl.createTexture();
if(!texture)
{
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)
{
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 )
{
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 drawTriangle(gl,positionHandle, colorHandle,MvpMatrixHandle, theObject, angle, viewProjMatrix)
{
g_modelMatrix.setRotate(angle, 0, 1, 0 );
initAttributeVariable(gl, positionHandle, theObject.vertexBuffer, theObject.vertexBuffer.num, theObject.vertexBuffer.type );
initAttributeVariable(gl, colorHandle, theObject.colorBuffer, theObject.colorBuffer.num, theObject.colorBuffer.type );
g_mvpMatrix.set(viewProjMatrix);
g_mvpMatrix.multiply(g_modelMatrix);
gl.uniformMatrix4fv(MvpMatrixHandle, false, g_mvpMatrix.elements );
//绘制
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theObject.indexBuffer );
gl.drawElements(gl.TRIANGLES, theObject.numIndices, theObject.indexBuffer.type, 0 );
}
function drawTriangleFBO(gl,positionHandle,MvpMatrixHandle, theObject, angle, viewProjMatrix)
{
g_modelMatrix.setRotate(angle, 0, 1, 0 );
initAttributeVariable(gl, positionHandle, theObject.vertexBuffer, theObject.vertexBuffer.num, theObject.vertexBuffer.type );
g_mvpMatrix.set(viewProjMatrix);
g_mvpMatrix.multiply(g_modelMatrix);
gl.uniformMatrix4fv(MvpMatrixHandle, false, g_mvpMatrix.elements );
//绘制
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theObject.indexBuffer );
gl.drawElements(gl.TRIANGLES, theObject.numIndices, theObject.indexBuffer.type, 0 );
}
function drawPlane(gl,positionHandle, colorHandle,MvpMatrixHandle, theObject, viewProjMatrix)
{
g_modelMatrix.setRotate(-45.0, 0, 1, 1 );
initAttributeVariable(gl, positionHandle, theObject.vertexBuffer, theObject.vertexBuffer.num, theObject.vertexBuffer.type );
initAttributeVariable(gl, colorHandle, theObject.colorBuffer, theObject.colorBuffer.num, theObject.colorBuffer.type );
g_mvpMatrix.set(viewProjMatrix);
g_mvpMatrix.multiply(g_modelMatrix);
gl.uniformMatrix4fv(MvpMatrixHandle, false, g_mvpMatrix.elements );
//绘制
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theObject.indexBuffer );
gl.drawElements(gl.TRIANGLES, theObject.numIndices, theObject.indexBuffer.type, 0 );
}
function drawPlaneFBO(gl, positionHandle,MvpMatrixHandle, theObject, viewProjMatrix)
{
g_modelMatrix.setRotate(-45.0, 0, 1, 1 );
initAttributeVariable(gl, positionHandle, theObject.vertexBuffer, theObject.vertexBuffer.num, theObject.vertexBuffer.type );
g_mvpMatrix.set(viewProjMatrix);
g_mvpMatrix.multiply(g_modelMatrix);
gl.uniformMatrix4fv(MvpMatrixHandle, false, g_mvpMatrix.elements );
//绘制
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theObject.indexBuffer );
gl.drawElements(gl.TRIANGLES, theObject.numIndices, theObject.indexBuffer.type, 0 );
}
var canvas = document.getElementById("test");
//创建webgl渲染上下文
var gl = canvas.getContext("webgl");
//初始化生成阴影贴图的着色器
var vertexShader_shadowMap = createShader(gl,gl.VERTEX_SHADER,SHADOW_VSHADER_SOURCE);
var fragmentShader_shadowMap = createShader(gl,gl.FRAGMENT_SHADER, SHADOW_FSHADER_SOURCE);
var program_shadowMap = createProgram(gl, vertexShader_shadowMap, fragmentShader_shadowMap);
var positionHandle_shadowMap = gl.getAttribLocation(program_shadowMap, 'a_Position');
var MvpMatrixHandle_shadowMap = gl.getUniformLocation(program_shadowMap, 'u_MvpMatrix');
if(positionHandle_shadowMap < 0 || !MvpMatrixHandle_shadowMap )
{
console.log('Failed to get program_shadowMap variable');
}
var vertexShader_Normal = createShader(gl,gl.VERTEX_SHADER,vertexShaderSource);
var fragmentShader_Normal = createShader(gl,gl.FRAGMENT_SHADER, fragmentShaderSource);
var program_Normal = createProgram(gl, vertexShader_Normal, fragmentShader_Normal);
var positionHandle_Normal = gl.getAttribLocation(program_Normal, 'a_Position');
var colorHandle_Normal = gl.getAttribLocation(program_Normal, 'a_Color');
var MvpMatrixHandle_Normal = gl.getUniformLocation(program_Normal, 'u_MvpMatrix');
var MvpMatrixFromLightHandle_Normal = gl.getUniformLocation(program_Normal, 'u_MvpMatrixFromLight');
var shadowMapHandle_Normal = gl.getUniformLocation(program_Normal, 'u_ShadowMap');
if( positionHandle_Normal < 0 || colorHandle_Normal < 0 || !MvpMatrixHandle_Normal || !MvpMatrixFromLightHandle_Normal || !shadowMapHandle_Normal )
{
console.log('Failed to get program_Normal variable');
}
//创建顶点数组
var triangle = initVertexBuffersForTriangle(gl);
var plane = initVertexBuffersForPlane(gl);
if(!triangle || !plane )
{
console.log('Failed to set the Vertex information');
}
//创建帧缓存对象
var fbo = initFrameBufferObject(gl);
if(!fbo)
{
console.log('Failed to initialize FBO');
}
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, fbo.texture);
//模型矩阵
//var g_modelMatrix = new Matrix4();
//模型视图投影矩阵
//var g_mvpMatrix = new Matrix4();
var rotateDeg = 1.0;
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
//开启隐藏面消除功能
gl.enable(gl.DEPTH_TEST);
var viewProjMatrixFromLight = new Matrix4();
viewProjMatrixFromLight.setPerspective(70.0, OFFSCREEN_WIDTH / OFFSCREEN_HEIGHT,1.0, 100.0);
viewProjMatrixFromLight.lookAt(LIGHT_X,LIGHT_Y,LIGHT_Z,0,0,0,0,1,0);
var viewProjMatrix = new Matrix4();
viewProjMatrix.setPerspective(45, canvas.width / canvas.height,1.0, 100.0);
viewProjMatrix.lookAt(10,20,30,9.0,0,0,0,1,0);
var mvpMatrixFromLight_triangle = new Matrix4();
var mvpMatrixFromLight_plane = new Matrix4();
var mytick = function()
{
//绑定帧缓冲区对象
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo );
//定义离线绘图的绘图区域
gl.viewport(0, 0, OFFSCREEN_WIDTH, OFFSCREEN_HEIGHT );
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
gl.useProgram(program_shadowMap);
//绘制三角形
drawTriangleFBO(gl, positionHandle_shadowMap, MvpMatrixHandle_shadowMap,triangle, rotateDeg,viewProjMatrixFromLight);
mvpMatrixFromLight_triangle.set(g_mvpMatrix);
drawPlaneFBO(gl, positionHandle_shadowMap, MvpMatrixHandle_shadowMap,plane, viewProjMatrixFromLight);
mvpMatrixFromLight_plane.set(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 );
gl.useProgram(program_Normal);
gl.uniform1i(shadowMapHandle_Normal, 0 );
gl.uniformMatrix4fv(MvpMatrixFromLightHandle_Normal, false, mvpMatrixFromLight_triangle.elements );
drawTriangle(gl, positionHandle_Normal, colorHandle_Normal, MvpMatrixHandle_Normal,triangle, rotateDeg, viewProjMatrix);
gl.uniformMatrix4fv(MvpMatrixFromLightHandle_Normal, false, mvpMatrixFromLight_plane.elements );
drawPlane(gl, positionHandle_Normal, colorHandle_Normal, MvpMatrixHandle_Normal, plane, viewProjMatrix);
rotateDeg += 1
requestAnimationFrame(mytick);
}
mytick();
</script>
</body>
</html>
图示如下:
提到了马赫带,果然去掉那个微调值出现了条纹