Skip to content

Commit 5bba760

Browse files
committed
feat: Store shadow map Z in four channels to optimize precision
1 parent fe1b99c commit 5bba760

File tree

5 files changed

+74
-58
lines changed

5 files changed

+74
-58
lines changed

examples/shadow.html

Lines changed: 27 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
rotationX: -90,
5151
geometry: new Hilo3d.PlaneGeometry(),
5252
material: new Hilo3d.PBRMaterial({
53+
castShadows: false,
5354
baseColorMap: new Hilo3d.LazyTexture({
5455
src: '//img.alicdn.com/tfs/TB1aNxtQpXXXXX1XVXXXXXXXXXX-1024-1024.jpg'
5556
})
@@ -72,53 +73,48 @@
7273

7374
box.setScale(0.1);
7475

75-
var spotLight = new Hilo3d.SpotLight({
76-
y: 1,
77-
x:0,
78-
cutoff: 8,
79-
outerCutoff: 9,
80-
range: 3,
76+
var directionalLight = new Hilo3d.DirectionalLight({
8177
color:new Hilo3d.Color(1, 1, 1),
82-
direction:new Hilo3d.Vector3(0.1, -1, 0),
83-
amount: 5,
78+
direction:new Hilo3d.Vector3(-.8, -1, 0),
79+
amount: 3,
8480
shadow: {
85-
debug: false,
8681
cameraInfo:{
87-
// fov:180,
88-
// aspect:1,
89-
// near:0.1,
90-
// far:2
82+
left:-.5,
83+
right:.5,
84+
near:-.5,
85+
far:.5,
86+
top:-.5,
87+
bottom:.5
9188
},
92-
minBias: 0.0001
89+
debug: true
9390
},
9491
onUpdate: function() {
9592
this.direction.rotateY(new Hilo3d.Vector3(0, 0, 0), Math.PI/180);
9693
this.isDirty = true;
9794
}
98-
});
99-
stage.addChild(spotLight);
95+
})
96+
stage.addChild(directionalLight);
10097

101-
var directionalLight = new Hilo3d.DirectionalLight({
98+
var spotLight = new Hilo3d.SpotLight({
99+
y: 1,
100+
x:0,
101+
cutoff: 8,
102+
outerCutoff: 9,
103+
range: 3,
102104
color:new Hilo3d.Color(1, 0, 0),
103-
direction:new Hilo3d.Vector3(-1, -1, 0),
104-
amount: 3.5,
105+
direction:new Hilo3d.Vector3(0.2, -1, 0),
106+
amount: 5,
105107
shadow: {
106-
// cameraInfo:{
107-
// left:-2,
108-
// right:2,
109-
// near:-2,
110-
// far:2,
111-
// top:-2,
112-
// bottom:2
113-
// },
114-
debug: true
108+
debug: true,
109+
minBias: 0.0001
115110
},
116111
onUpdate: function() {
117-
this.direction.rotateY(new Hilo3d.Vector3(0, 0, 0), Math.PI/180);
112+
this.direction.rotateY(new Hilo3d.Vector3(0, 0, 0), Math.PI/180*0.5);
118113
this.isDirty = true;
119114
}
120-
})
121-
stage.addChild(directionalLight);
115+
});
116+
stage.addChild(spotLight);
117+
122118

123119
new Hilo3d.AmbientLight({
124120
color:new Hilo3d.Color(1, 1, 1),

examples/ssao.html

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@
5555
writeOriginData:writeOriginData
5656
});
5757

58-
var depthFramebuffer = new Hilo3d.Framebuffer(renderer, {
59-
type:Hilo3d.constants.FLOAT
60-
});
58+
var depthFramebuffer = new Hilo3d.Framebuffer(renderer);
6159
depthFramebuffer.init();
6260
var depthMaterial = new Hilo3d.GeometryMaterial({
6361
vertexType:Hilo3d.constants.DEPTH,
@@ -93,6 +91,15 @@
9391
uniform mat4 u_projection;
9492
uniform vec2 u_noiseScale;
9593
uniform float u_radius;
94+
uniform float u_cameraFar;
95+
uniform float u_cameraNear;
96+
97+
float unpackFloat(vec4 rgbaDepth) {
98+
const vec4 bitShift = vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0);
99+
float depth = dot(rgbaDepth, bitShift);
100+
return depth;
101+
}
102+
96103
void main(void) {
97104
vec4 fragPosAll = texture2D(u_position, v_texcoord0);
98105
if(fragPosAll.a < 1.0){
@@ -117,7 +124,9 @@
117124
offset.xyz /= offset.w; // 透视划分
118125
offset.xyz = offset.xyz * 0.5 + 0.5; // 变换到0.0 - 1.0的值域
119126
120-
float sampleDepth = -texture2D(u_depth, offset.xy).x;
127+
float sampleDepth = unpackFloat(texture2D(u_depth, offset.xy));
128+
sampleDepth = sampleDepth * 2.0 - 1.0;
129+
sampleDepth = (-2.0 * u_cameraNear * u_cameraFar) / (u_cameraFar + u_cameraNear - sampleDepth * (u_cameraFar - u_cameraNear));
121130
float rangeCheck = smoothstep(0.0, 1.0, u_radius / abs(fragPos.z - sampleDepth));
122131
occlusion += (sampleDepth >= samplePos.z ? 1.0 : 0.0) * rangeCheck;
123132
}
@@ -136,6 +145,16 @@
136145
get:function(){
137146
return camera.projectionMatrix.elements;
138147
}
148+
},
149+
u_cameraFar:{
150+
get:function(){
151+
return camera.far;
152+
}
153+
},
154+
u_cameraNear:{
155+
get:function(){
156+
return camera.near;
157+
}
139158
}
140159
}
141160
});

src/light/LightShadow.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ const LightShadow = Class.create(/** @lends LightShadow.prototype */{
150150
shadowMaterial = new GeometryMaterial({
151151
vertexType: DEPTH,
152152
side: BACK,
153-
writeOriginData: true
153+
writeOriginData: false
154154
});
155155
}
156156

src/shader/geometry.frag

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
#elif defined(HILO_VERTEX_TYPE_NORMAL)
88
varying vec3 v_normal;
99
#elif defined(HILO_VERTEX_TYPE_DEPTH)
10+
#pragma glslify: import('./method/packFloat.glsl');
11+
1012
uniform float u_cameraFar;
1113
uniform float u_cameraNear;
1214
uniform float u_cameraType;
@@ -34,21 +36,11 @@ void main(void) {
3436
#elif defined(HILO_VERTEX_TYPE_NORMAL)
3537
gl_FragColor = transformDataToColor(v_normal);
3638
#elif defined(HILO_VERTEX_TYPE_DEPTH)
37-
float z;
3839
#ifdef HILO_WRITE_ORIGIN_DATA
39-
z = gl_FragCoord.z;
40+
gl_FragColor = vec4(gl_FragCoord.z, gl_FragCoord.z, gl_FragCoord.z, 1.0);
4041
#else
41-
// OrthographicCamera
42-
if(u_cameraType < 1.0){
43-
z = gl_FragCoord.z;
44-
}
45-
// PerspectiveCamera
46-
else{
47-
z = gl_FragCoord.z * 2.0 - 1.0;
48-
z = (2.0 * u_cameraNear * u_cameraFar) / (u_cameraFar + u_cameraNear - z * (u_cameraFar - u_cameraNear));
49-
}
42+
gl_FragColor = packFloat(gl_FragCoord.z);
5043
#endif
51-
gl_FragColor = vec4(z, z, z, 1.0);
5244
#elif defined(HILO_VERTEX_TYPE_DISTANCE)
5345
float distance = length(v_fragPos);
5446
#ifdef HILO_WRITE_ORIGIN_DATA

src/shader/method/getShadow.glsl

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,34 @@ bool isOutOfRange(vec2 pos) {
55
return false;
66
}
77

8+
float getShadow(vec2 pos, sampler2D shadowMap, float currentDepth) {
9+
if (isOutOfRange(pos)) {
10+
return 0.0;
11+
}
12+
float pcfDepth = unpackFloat(texture2D(shadowMap, pos));
13+
return step(pcfDepth, currentDepth);
14+
}
15+
816
float getShadow(sampler2D shadowMap, vec2 shadowMapSize, float bias, vec3 fragPos, mat4 lightSpaceMatrix) {
917
vec4 fragPosLightSpace = lightSpaceMatrix * vec4(fragPos, 1.0);
1018
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
1119
projCoords = projCoords * 0.5 + 0.5;
1220
if (isOutOfRange(projCoords.xy)) {
1321
return 1.0;
1422
}
15-
float currentDepth = projCoords.z;
23+
float currentDepth = projCoords.z - bias;
1624
float shadow = 0.0;
1725
vec2 texelSize = 1.0 / shadowMapSize;
18-
for (int x = -1; x <= 1; ++x) {
19-
for (int y = -1; y <= 1; ++y) {
20-
vec2 pos = projCoords.xy + vec2(x, y) * texelSize;
21-
if (!isOutOfRange(pos)) {
22-
float pcfDepth = texture2D(shadowMap, pos).r;
23-
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
24-
}
25-
}
26-
}
26+
shadow += getShadow(projCoords.xy + vec2(-1, -1) * texelSize, shadowMap, currentDepth);
27+
shadow += getShadow(projCoords.xy + vec2(0, -1) * texelSize, shadowMap, currentDepth);
28+
shadow += getShadow(projCoords.xy + vec2(1, -1) * texelSize, shadowMap, currentDepth);
29+
shadow += getShadow(projCoords.xy + vec2(-1, 0) * texelSize, shadowMap, currentDepth);
30+
shadow += getShadow(projCoords.xy + vec2(0, 0) * texelSize, shadowMap, currentDepth);
31+
shadow += getShadow(projCoords.xy + vec2(1, 0) * texelSize, shadowMap, currentDepth);
32+
shadow += getShadow(projCoords.xy + vec2(-1, 1) * texelSize, shadowMap, currentDepth);
33+
shadow += getShadow(projCoords.xy + vec2(0, 1) * texelSize, shadowMap, currentDepth);
34+
shadow += getShadow(projCoords.xy + vec2(1, 1) * texelSize, shadowMap, currentDepth);
35+
2736
return 1.0 - shadow / 9.0;
2837
}
2938

0 commit comments

Comments
 (0)