shadowmap2,扩展z值范围

本文详细介绍使用WebGL实现阴影贴图的过程,包括创建顶点和片元着色器、生成离屏绘制尺寸的帧缓存对象、绘制三角形和平面以创建阴影效果。文章深入探讨了如何通过调整z值来优化阴影质量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

书上是用rgba表示浮点型的z值,扩大了范围,但是大点了也会出问题。以后可能考虑用cascade shadowmap

<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 =
  '#ifdef GL_ES\n' +
  'precision mediump float;\n' +
  '#endif\n' +
  'void main() {\n' +
  '  const vec4 bitShift = vec4(1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0);\n' +
  '  const vec4 bitMask = vec4(1.0/256.0, 1.0/256.0, 1.0/256.0, 0.0);\n' +
  '  vec4 rgbaDepth = fract(gl_FragCoord.z * bitShift);\n' + // Calculate the value stored into each byte
  '  rgbaDepth -= rgbaDepth.gbaa * bitMask;\n' + // Cut off the value which do not fit in 8 bits
  '  gl_FragColor = rgbaDepth;\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 =
  '#ifdef GL_ES\n' +
  'precision mediump float;\n' +
  '#endif\n' +
  'uniform sampler2D u_ShadowMap;\n' +
  'varying vec4 v_PositionFromLight;\n' +
  'varying vec4 v_Color;\n' +
  // Recalculate the z value from the rgba
  'float unpackDepth(const in vec4 rgbaDepth) {\n' +
  '  const vec4 bitShift = vec4(1.0, 1.0/256.0, 1.0/(256.0*256.0), 1.0/(256.0*256.0*256.0));\n' +
  '  float depth = dot(rgbaDepth, bitShift);\n' + // Use dot() since the calculations is same
  '  return depth;\n' +
  '}\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 = unpackDepth(rgbaDepth);\n' + // Recalculate the z value from the rgba
  '  float visibility = (shadowCoord.z > depth + 0.0015) ? 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 = 100.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);
    console.log('ok1');
    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>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值