procedure NormalizeFrustumPlane(Var p : TFrustumPlane);
Var denom : single;
Begin
denom := 1 / sqrt((p.normal.x*p.normal.x) + (p.normal.y*p.normal.y) + (p.normal.z*p.normal.z));
p.normal.x := p.normal.x * denom;
p.normal.y := p.normal.y * denom;
p.normal.z := p.normal.z * denom;
p.distance := p.distance * denom;
End;
function Intersect3plane(p1, p2, p3 : TFrustumPlane) : TD3DVector;
Var v : array[0..3] of TD3DVector;
f : single;
Begin
NormalizeFrustumPlane(p1);
NormalizeFrustumPlane(p2);
NormalizeFrustumPlane(p3);
v[0] := D3DVec3Scale(VectorCrossProduct(p2.normal, p3.normal), p1.distance);
v[1] := D3DVec3Scale(VectorCrossProduct(p3.normal, p1.normal), p2.distance);
v[2] := D3DVec3Scale(VectorCrossProduct(p1.normal, p2.normal), p3.distance);
v[3] := VectorAdd(VectorAdd(v[0], v[1]), v[2]);
f := VectorDotProduct(p1.normal, VectorCrossProduct(p2.normal, p3.normal));
result := D3DVec3Div(v[3], f);
End;
function FrustumToAABB(Frustum : TFrustum) : TAABB;
Var v : array[0..7] of TD3DVector;
i : integer;
Begin
// Planes: 0=Left, 1=Right, 2=Top, 3=Bottom, 4=Near, 5=Far
// Bottom
v[0] := Intersect3plane(Frustum.Plane[4], Frustum.Plane[3], Frustum.Plane[0]);
v[1] := Intersect3plane(Frustum.Plane[4], Frustum.Plane[3], Frustum.Plane[1]);
v[2] := Intersect3plane(Frustum.Plane[5], Frustum.Plane[3], Frustum.Plane[0]);
v[3] := Intersect3plane(Frustum.Plane[5], Frustum.Plane[3], Frustum.Plane[1]);
// Top
v[4] := Intersect3plane(Frustum.Plane[4], Frustum.Plane[2], Frustum.Plane[0]);
v[5] := Intersect3plane(Frustum.Plane[4], Frustum.Plane[2], Frustum.Plane[1]);
v[6] := Intersect3plane(Frustum.Plane[5], Frustum.Plane[2], Frustum.Plane[0]);
v[7] := Intersect3plane(Frustum.Plane[5], Frustum.Plane[2], Frustum.Plane[1]);
Result.Min := v[0];
Result.Max := v[0];
for i:=0 to 7 do
Begin
// Max
if v.x > Result.Max.x then Result.Max.x := v.x;
if v.y > Result.Max.y then Result.Max.x := v.y;
if v.z > Result.Max.z then Result.Max.x := v.z;
// Min
if v.x < Result.Min.x then Result.Min.x := v.x;
if v.y < Result.Min.y then Result.Min.y := v.y;
if v.z < Result.Min.z then Result.Min.z := v.z;
End;
End;
function GetShadowMatrix(Dir : TD3DVector; AABB : TAABB) : TD3DMatrix;
Var v,p : TD3DMatrix;
Begin
Case FCamera.Orientation of
coLeftHand : Begin
D3DXMatrixLookAtLH(v, Dir, D3DVector3Zero, FCamera.Up);
D3DXMatrixOrthoOffCenterLH(p, AABB.Min.x, AABB.Max.x, AABB.Min.y, AABB.Max.y, AABB.Min.z, AABB.Max.z);
End;
coRightHand : Begin
D3DXMatrixLookAtRH(v, Dir, D3DVector3Zero, FCamera.Up);
D3DXMatrixOrthoOffCenterRH(p, AABB.Min.x, AABB.Max.x, AABB.Min.y, AABB.Max.y, AABB.Min.z, AABB.Max.z);
End;
End;
Result := MatrixMultiply(v, p);
End;
Sun + ShadowMap
Hi, Im trying to do directional Sun lighting to a ShadowMap.
I have been looking at most Google results on "Sun ShadowMap" etc.
This is what I have come up with, problem is, it dose not work...
Just getting a 0 (Zero) ShadowMapTexture (nothing was rendered).
I know my shader works and the "input" frustum planes are correct.
I must have overlooked something.
Anyone know how to get the OrthoOffCenter matrix based on the frustum and the View matrix based on the Sun's direction vector ?
Have tryed all the stuff I could find on the web, but still no luck :(
Have tryed all the stuff I could find on the web, but still no luck :(
Here's my code for calculating the view and projection matrix of a directional shadow caster. In my code "camFrustumCoords" are the corners of the camera's view frustum in world space, and "lookDirection" is the direction vector of the light source. The basic premise is this:
-Position the shadow caster by starting at the centroid of the view frustum and backing up in the opposite direction of the light's direction, by a value of the the camera's farZ plane divided by two (this is the most you would ever have to back up in order to keep the entire frustum visible to the shadow caster)
-Transform the camera's view frustum to view space relative the shadow caster's new position and the direction of the light
-Determine the min and max x y and z values for the frustum corners in the shadow caster's view space
-Width of the shadow caster's orthographic projection is maxes.x - mins.x, height is maxes.y - mins.y
-FarZ of the projection is maxes.z, NearZ is <= mins.z (to still capture objects outside the camera frustum that could cast shadows on objects inside the camera frustum)
I've been meaning to change this at some point to implement PSSM, but I just never find the time to get around to it.
-Position the shadow caster by starting at the centroid of the view frustum and backing up in the opposite direction of the light's direction, by a value of the the camera's farZ plane divided by two (this is the most you would ever have to back up in order to keep the entire frustum visible to the shadow caster)
-Transform the camera's view frustum to view space relative the shadow caster's new position and the direction of the light
-Determine the min and max x y and z values for the frustum corners in the shadow caster's view space
-Width of the shadow caster's orthographic projection is maxes.x - mins.x, height is maxes.y - mins.y
-FarZ of the projection is maxes.z, NearZ is <= mins.z (to still capture objects outside the camera frustum that could cast shadows on objects inside the camera frustum)
//get some info from the cameraD3DXVECTOR3 camPos = camera->GetWorldPosition();D3DXVECTOR3 camFrustumCentroid = camera->GetFrustumCentroid();const D3DXVECTOR3* camFrustumCoords = camera->GetFrustumCoordinates();FLOAT camFarZ = camera->GetFarZ();//pick a temporary working position for our shadow casterD3DXVECTOR3 tempPos = camFrustumCentroid - lookDirection * (camFarZ / 2.0f);translatedPosition = tempPos;//create a temp view matrixD3DXMatrixLookAtLH( &matView, &tempPos, &camFrustumCentroid, &vUpVec );D3DXMatrixInverse(&worldMatrix, NULL, &matView);//calculate the camera's frustrum in light view spaceD3DXVECTOR3 camFrustumVS [8];D3DXVec3TransformCoordArray( camFrustumVS, sizeof(D3DXVECTOR3), camFrustumCoords, sizeof(D3DXVECTOR3), &matView, 8 );//figure out how big we need to make the shadow caster's view frustum, based//on the camera's view frustumD3DXVECTOR3 mins = camFrustumVS[0];D3DXVECTOR3 maxes = camFrustumVS[1];UINT minIndices[3] = {0,0,0};UINT maxIndices[3] = {1,1,1};for (UINT i = 0; i < 8; i++){ if (camFrustumVS.x < mins.x) { mins.x = camFrustumVS.x; minIndices[0] = i; } else if (camFrustumVS.x > maxes.x) { maxes.x = camFrustumVS.x; maxIndices[0] = i; } if (camFrustumVS.y < mins.y) { mins.y = camFrustumVS.y; minIndices[1] = i; } else if (camFrustumVS.y > maxes.y) { maxes.y = camFrustumVS.y; maxIndices[1] = i; } if (camFrustumVS.z < mins.z) { mins.z = camFrustumVS.z; minIndices[2] = i; } else if (camFrustumVS.z > maxes.z) { maxes.z = camFrustumVS.z; maxIndices[2] = i; }}farZ = maxes.z;nearZ = mins.z / 2.0f;FLOAT width = maxes.x - mins.x; FLOAT height = maxes.y - mins.y;SetProjectionOrthographic(width, height, nearZ, farZ);
I've been meaning to change this at some point to implement PSSM, but I just never find the time to get around to it.
Thanks MJP :)
This helped alot.
Any chance you could post the "camera->GetFrustumCoordinates();" function, please ?
This helped alot.
Any chance you could post the "camera->GetFrustumCoordinates();" function, please ?
You can get corners of the camera's view frustum in world space when you transform corners of view frustum in clipping space (combination of zeros and ones) by Inv(View * Projection) matrix.
Code from my C# project:
Code from my C# project:
#region public virtual void Recompute(Matrix view, Matrix projection) /// <summary> /// Recomputes frustum using view and projection matrices. /// </summary> /// <param name="view">View matrix.</param> /// <param name="projection">Projection matrix.</param> public virtual void Recompute(Matrix view, Matrix projection) { Matrix mat = (view * projection).Invert(); this.m_points[0].X = -1.0f; this.m_points[0].Y = -1.0f; this.m_points[0].Z = 0.0f; // xyz this.m_points[1].X = 1.0f; this.m_points[1].Y = -1.0f; this.m_points[1].Z = 0.0f; // Xyz this.m_points[2].X = -1.0f; this.m_points[2].Y = 1.0f; this.m_points[2].Z = 0.0f; // xYz this.m_points[3].X = 1.0f; this.m_points[3].Y = 1.0f; this.m_points[3].Z = 0.0f; // XYz this.m_points[4].X = -1.0f; this.m_points[4].Y = -1.0f; this.m_points[4].Z = 1.0f; // xyZ this.m_points[5].X = 1.0f; this.m_points[5].Y = -1.0f; this.m_points[5].Z = 1.0f; // XyZ this.m_points[6].X = -1.0f; this.m_points[6].Y = 1.0f; this.m_points[6].Z = 1.0f; // xYZ this.m_points[7].X = 1.0f; this.m_points[7].Y = 1.0f; this.m_points[7].Z = 1.0f; // XYZ for (int i = 0; i < 8; i++) { this.m_points.TransformCoordinate(mat); } this.m_planes[0] = new Plane(this.m_points[0], this.m_points[1], this.m_points[2]); // Near this.m_planes[1] = new Plane(this.m_points[6], this.m_points[7], this.m_points[5]); // Far this.m_planes[2] = new Plane(this.m_points[2], this.m_points[3], this.m_points[6]); // Top this.m_planes[3] = new Plane(this.m_points[1], this.m_points[0], this.m_points[4]); // Bottom this.m_planes[4] = new Plane(this.m_points[2], this.m_points[6], this.m_points[4]); // Left this.m_planes[5] = new Plane(this.m_points[7], this.m_points[3], this.m_points[5]); // Right for (int i = 0; i < 6; i++) { this.m_planes.Normalize(); } } #endregion
Thanks Augi :)
Question : When you set the Unit Cube, why do you use z (0 and 1), should it not be (-1 and +1) ?
Also : When you set the Unit Cube, dose it matter what the WorldUp is, as you find the min and max anyways ?
And what about the GetFrustumCentroid() ?
-> (0,0,0) * (ViewMatrix*ProjectionMatrix) = Center ?
[Edited by - Mythar on December 27, 2007 7:34:52 AM]
Question : When you set the Unit Cube, why do you use z (0 and 1), should it not be (-1 and +1) ?
Also : When you set the Unit Cube, dose it matter what the WorldUp is, as you find the min and max anyways ?
And what about the GetFrustumCentroid() ?
-> (0,0,0) * (ViewMatrix*ProjectionMatrix) = Center ?
[Edited by - Mythar on December 27, 2007 7:34:52 AM]
DX SDK says that Z values range (in clipping space) is from 0 to 1. In OpenGL it is from -1 to 1 (imho).
Centroid can be imho computed as mean of corners of the camera's view frustum (sum of all positions and divide by 8).
Centroid can be imho computed as mean of corners of the camera's view frustum (sum of all positions and divide by 8).
My GetFrustumCoords() function just returns a pointer to an array of vectors, the value for those vectors are computed elsewhere. What I do is I first calculate the frustum coordinates in view space (relative to the camera). This is done every time the perspective projection parameters are changed:
Then every time the camera moves, the world-space position of the frustum coordinates are calculated:
The "GetFrustumCoords()" method then just returns a const pointer to frustumCoordsWS.
[Edited by - MJP on December 28, 2007 6:15:03 PM]
void AE3_CameraDX9::SetProjectionPerspective (FLOAT aspectRatio, FLOAT fieldOfView, FLOAT nearClip, FLOAT farClip){ D3DXMatrixPerspectiveFovLH( &matProj, fieldOfView, aspectRatio, nearClip, farClip ); aspect = aspectRatio; fov = fieldOfView; nearZ = nearClip; farZ = farClip; //generate coordinates for perspective projection volume nearH = 2 * tanf(fov / 2.0f) * nearClip; nearW = nearH * aspect; farH = 2 * tanf(fov / 2.0f) * farClip; farW = farH * aspect; FLOAT nearX = nearW / 2.0f; FLOAT nearY = nearH / 2.0f; FLOAT farX = farW / 2.0f; FLOAT farY = farH / 2.0f; //near clip plane first, top-left then clockwise frustumCoordsVS[0] = D3DXVECTOR3(-nearX, nearY, nearZ); frustumCoordsVS[1] = D3DXVECTOR3(nearX, nearY, nearZ); frustumCoordsVS[2] = D3DXVECTOR3(nearX, -nearY, nearZ); frustumCoordsVS[3] = D3DXVECTOR3(-nearX, -nearY, nearZ); //now far clip plane frustumCoordsVS[4] = D3DXVECTOR3(-farX, farY, farZ); frustumCoordsVS[5] = D3DXVECTOR3(farX, farY, farZ); frustumCoordsVS[6] = D3DXVECTOR3(farX, -farY, farZ); frustumCoordsVS[7] = D3DXVECTOR3(-farX, -farY, farZ); }
Then every time the camera moves, the world-space position of the frustum coordinates are calculated:
void AE3_CameraDX9::Update (){ D3DXMatrixInverse(&matView, NULL, &worldMatrix); matViewProj = matView * matProj; //calculate view frustum coordinates in world space D3DXVec3TransformCoordArray( frustumCoordsWS, sizeof(D3DXVECTOR3), frustumCoordsVS, sizeof(D3DXVECTOR3), &worldMatrix, 8 ); D3DXVECTOR3 nc = positionWS + lookDirection * nearZ; D3DXVECTOR3 fc = positionWS + lookDirection * farZ; frustumCentroid = positionWS + lookDirection * ((nearZ + farZ)/2.0f); ...}
The "GetFrustumCoords()" method then just returns a const pointer to frustumCoordsWS.
[Edited by - MJP on December 28, 2007 6:15:03 PM]
Ok tryed out your way MJP. ( Tryed it you way as well Augi )
Where did I go wrong ? (still getting a blank texture)
Where did I go wrong ? (still getting a blank texture)
// Get Center Center = FCamera.Position + (FCamera.Direction * (FCamera.FarPlane * 0.5));// EyeEye = Center - (sunDirection * (FCamera.FarPlane * 0.5));// ViewMatrixD3DXMatrixLookAtLH( &mView, Eye, Center, FCamera.Up );// Get the GetFrustumCoordinates ( as done in your SetProjectionPerspective )frustumCoordsVS = GetFrustumCoordinates(FCamera.Aspect, FCamera.Fov, FCamera.NearPlane, FCamera.FarPlane);// Transform to world space ( &worldMatrix = Translate Camera's Position ? )D3DXVec3TransformCoordArray(frustumCoordsWS, sizeof(D3DXVECTOR3), frustumCoordsVS, sizeof(D3DXVECTOR3), &worldMatrix, 8 );// Find min/max of frustumCoordsWS thenzf = Max.z;zn = Min.z * 0.5;w = Max.x - Min.x;h = Max.y - Min.y;// ProjectionMatrixD3DXMatrixOrthoLH( &mProj, w, h, zn, zf );// ShadowMatrixmShadow = mView * mProj;// For eatch object rendered via the shadermLightViewProj = (object's)worldMatrix * mShadow;...o.Pos = mul(float4(i.Pos.xyz,1), mLightViewProj);o.depth = o.Pos.z;...
Yeah "worldMatrix" is a matrix that would move the camera from the origin to its actual position, and rotate it from its initial direction of <0,0,1> to whatever direction its actually facing. If you have a view matrix for the camera, then the world matrix for your camera is just the inverse of that.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement