【发布时间】:2016-01-14 13:34:45
【问题描述】:
我第一次尝试在 WebGL 场景中实现阴影,据我所知,最直接的方法是使用阴影贴图,但我找不到解释这个概念的教程,这与 OpenGL 或包含诸如three.js 之类的库无关。
但是,我读到过,我必须编写两对着色器。第一对着色器用于构建阴影贴图,它必须以某种方式存储在帧缓冲区对象中。然后我必须从帧缓冲区中取出存储的阴影贴图并将其传递给第二对着色器,用于绘制场景中的对象。
阴影贴图必须包含信息,即光线在撞击物体之前可以从光源传播多远的距离,并且通过将此信息传递给用于绘制物体的着色器,可以指定,哪些部分由光源发出的光照亮,哪些部分仅由环境光照亮。
理论上讲了这么多,但我不知道如何让它发挥作用......
为了进行实验,我设置了一个非常简单的场景,渲染两个由单点光源照亮的球体,如下所示:
创建的两个球体均以[0.0, 0.0, 0.0] 为中心,以1.0 为半径。
较大球体的矩阵由[-2.0, 0.0, -2.0] 平移并由[2.0, 2.0, 2.0] 缩放。
较小球体的矩阵由[2.0, 0.0, 2.0] 平移并由[0.5, 0.5, 0.5] 缩放。
点光源的位置是[4.0, 0.0, 4.0]。
因此,较小的球体现在正好位于较大的球体和光源之间,因此较大球体的表面上应该有一个区域,该区域不被直接照亮。
我用于这个场景的两个着色器如下所示:
顶点着色器
attribute vec4 aPosition;
attribute vec3 aNormal;
uniform mat4 uProjectionMatrix;
uniform mat4 uModelViewMatrix;
uniform mat3 uNormalMatrix;
varying vec4 vPosition;
varying vec3 vTransformedNormal;
void main ( ) {
vTransformedNormal = uNormalMatrix * aNormal;
vPosition = uModelViewMatrix * aPosition;
gl_Position = uProjectionMatrix * vPosition;
}
片段着色器
precision highp float;
uniform vec3 uLightPosition;
varying vec4 vPosition;
varying vec3 vTransformedNormal;
void main ( ) {
vec3 lightDirection = normalize(uLightPosition - vPosition.xyz);
float diffuseLightWeighting = max(
dot(normalize(vTransformedNormal), lightDirection), 0.0);
vec3 lightWeighting = vec3(0.1, 0.1, 0.1) +
vec3(0.8, 0.8, 0.8) * diffuseLightWeighting;
gl_FragColor = vec4(vec3(1.0, 1.0, 1.0) * lightWeighting, 1.0);
}
所以,我现在要做的第一件事是编写另一对着色器,因为它们不用于实际绘制某些东西,所以我可以省略法线的属性以及统一的属性正常矩阵,也不需要投影矩阵吧?
第二个顶点着色器可能看起来像这样:
attribute vec4 aPosition;
uniform mat4 uModelViewMatrix;
varying vec4 vPosition;
void main ( ) {
vPosition = uModelViewMatrix * aPosition;
gl_Position = vPosition;
}
但是片段着色器呢?而且,无论如何,我如何找出来自点光源的光照射到物体的位置?我的意思是,这通常需要从所有相关对象一次传入顶点位置数据,不是吗? (虽然在这种特殊情况下,只需要传入较小球体的顶点位置......)
现在,我的问题是,我该如何从这里继续下去?片段着色器中必须写入什么内容,如何保存阴影贴图以及如何使用它来计算较小球体在较大球体上的阴影?
我担心我可能要求太多,但如果有人至少能指出我正确的方向,那就太好了。
【问题讨论】:
标签: javascript webgl