-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathShadow.cs
More file actions
146 lines (113 loc) · 5.27 KB
/
Shadow.cs
File metadata and controls
146 lines (113 loc) · 5.27 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
using Microsoft.Xna.Framework;
using System;
namespace LevelEditor.Engine
{
/// <summary>
/// Represents a shadow which can be attached to a light.
/// </summary>
class Shadow
{
private readonly Light mLight;
public float mDistance;
public float mBias;
public int mNumSamples;
public float mSampleRange;
public Matrix mViewMatrix;
public Matrix mProjectionMatrix;
public bool mActivated;
/// <summary>
/// Constructs a <see cref="Shadow"/>
/// </summary>
/// <param name="light">The light where the shadow is attached to.</param>
public Shadow(Light light)
{
mLight = light;
mDistance = 60.0f;
mBias = 0.002f;
mNumSamples = 16;
mSampleRange = 0.4f;
mProjectionMatrix = Matrix.CreateOrthographicOffCenter(-25.0f, 25.0f, -25.0f, 25.0f, -100.0f, 100.0f);
mViewMatrix = Matrix.Identity;
mActivated = true;
}
/// <summary>
/// Updates the shadow matrices according to the cameras view frustum.
/// </summary>
/// <param name="camera">The camera which is used in the scene</param>
public void Update(Camera camera)
{
/*
* Here is a quick overview of what this method does:
* First we create the middle point of the shadow map in view space
* Afterwards we use this information to create a light view matrix.
* We then calulcate the widths and heights of the nearPlane and the
* projected shadow distance plane. We then calculate all 8 points of
* the resulting frustum. After we've done that we loop trough all of
* these points, transform them into light view space and check the for
* the mins and max of the X, Y, and Z components of these points. These
* mins and maxs are needed to calculate the light projection matrix which
* should fit the view frustum perfectly now.
*/
var shadowMiddle = camera.mLocation + camera.Direction * mDistance / 2.0f;
var direction = Vector3.Normalize(shadowMiddle - mLight.mLocation);
mViewMatrix = Matrix.CreateLookAt(shadowMiddle, shadowMiddle + direction, Vector3.Up);
var tang = (float)Math.Tan(camera.mFieldOfView * Math.PI / 360.0f);
var farPlaneHeight = mDistance * tang;
var farPlaneWidth = camera.mAspectRatio * farPlaneHeight;
var nearPlaneHeight = camera.mNearPlane * tang;
var nearPlaneWidth = camera.mAspectRatio * nearPlaneHeight;
var far = camera.mLocation + camera.Direction * mDistance;
var near = camera.mLocation + camera.Direction * camera.mNearPlane;
var farUpperLeft = far + farPlaneHeight * camera.Up - farPlaneWidth * camera.Right;
var farUpperRight = far + farPlaneHeight * camera.Up + farPlaneWidth * camera.Right;
var farLowerLeft = far - farPlaneHeight * camera.Up - farPlaneWidth * camera.Right;
var farLowerRight = far - farPlaneHeight * camera.Up + farPlaneWidth * camera.Right;
var nearUpperLeft = near + nearPlaneHeight * camera.Up - nearPlaneWidth * camera.Right;
var nearUpperRight = near + nearPlaneHeight * camera.Up + nearPlaneWidth * camera.Right;
var nearLowerLeft = near - nearPlaneHeight * camera.Up - nearPlaneWidth * camera.Right;
var nearLowerRight = near - nearPlaneHeight * camera.Up + nearPlaneWidth * camera.Right;
var array = new[] {farUpperLeft, farUpperRight, farLowerLeft, farLowerRight, nearUpperLeft, nearUpperRight, nearLowerLeft, nearLowerRight};
var vec = Vector3.Transform(farUpperLeft, mViewMatrix);
var maxX = vec.X;
var minX = vec.X;
var maxY = vec.Y;
var minY = vec.Y;
var maxZ = vec.Z;
var minZ = vec.Z;
foreach (var vector in array)
{
var transform = Vector3.Transform(vector, mViewMatrix);
if (transform.X > maxX)
{
maxX = transform.X;
}
if (transform.X < minX)
{
minX = transform.X;
}
if (transform.Y > maxY)
{
maxY = transform.Y;
}
if (transform.Y < minY)
{
minY = transform.Y;
}
if (transform.Z > maxZ)
{
maxZ = transform.Z;
}
if (transform.Z < minZ)
{
minZ = transform.Z;
}
}
/*
* We have to reduce -z even further to get the shadows nearer to light rendered correctly
* To be honest I don't even know why we have to use -maxZ for -z and -minZ for z. My guess
* is that it has to do with the different orientation of the coordinate system in DirectX.
*/
mProjectionMatrix = Matrix.CreateOrthographicOffCenter(minX, maxX, minY, maxY, -maxZ - 50.0f, -minZ);
}
}
}