Hi,
I have a light source with a direction D = (d1, d2, d3) and a point P = (p1, p2, p3) in the standard cartesian coordinate system. I want to construct another coordinate system whose z-axis' direction is D. The origin should lie in the standard coordinate system's origin and it should be a cartesian coordinate system. The direction of the x-axis doesn't matter.
I am a little confused because both coordinate systems are left-handed (because of D3D11).
How can I construct the coordinate system? And how can I compute the position of P in the new coordinate system? Could I simply compute a bounding box which contains some points (edges of a viewing frustum) and compute the position of the light source in the new coordinate system and transform it back to the standard coordinate system?
I already have some code, but it doesn't work as intended (the focus position (in standard coords) lies above the camera, it should lie below the camera because the light's y-direction is negative, the viewing frustum (in standard coords) is correct).
void DirectionalLight::Render(ID3D11DeviceContext* DeviceContext, Camera_t* Camera, DOUBLE3 Direction, RenderFunction_t RenderFunction){
DeviceContext->RSSetViewports(1, &Viewport);
float CameraNear = Camera->GetNear(), CameraFar = Camera->GetFar(), FoV_rad=Camera->GetFoVRadians(), ViewRatio=Camera->GetViewRatio();
double LengthPerUnit = 1.0 / (pow(2, NumTextures) - 1) * (CameraFar-CameraNear);
uint64_t CurrentDistance = 0; //0 to (2^NumTextures)-1
DOUBLE3 CameraUp = Camera->GetUpVector(), CameraRight = Camera->GetRightVector();
DOUBLE3 CameraPosition = Camera->GetPosition();
DOUBLE3 CameraDirection = Camera->GetDirection();
double LightAngleY, LightAngleZ;
double LightLength = Direction.Length();
LightAngleY = acos(Direction.z / Direction.Length());
LightAngleZ =
(Direction.y > 0) ?
atan(Direction.x / Direction.y) + 3*M_PI_2
:
(
(Direction.y < 0) ?
atan(Direction.x / Direction.y) + M_PI_2
:
(Direction.x > 0 ? 0 : M_PI)
);
XMMATRIX RotationMatrix = XMMatrixMultiply(XMMatrixRotationY(LightAngleY), XMMatrixRotationZ(LightAngleZ));
XMMATRIX RotationInverse = XMMatrixMultiply(XMMatrixRotationZ(-LightAngleZ), XMMatrixRotationY(-LightAngleY));
for (unsigned int i = 0; i < NumTextures; ++i){
uint64_t CurrentSize = (uint64_t)pow(2, i);
DeviceContext->ClearDepthStencilView(DepthStencilViews[i], D3D11_CLEAR_DEPTH, 1.0f, 0);
DeviceContext->OMSetRenderTargets(0, 0, DepthStencilViews[i]);
Frustum LightViewFrustum;
double CurrentNear = CurrentDistance*LengthPerUnit + CameraNear;
double CurrentFar = (CurrentDistance + CurrentSize)*LengthPerUnit + CameraNear;
DOUBLE3 NearCenter = CameraPosition + CurrentNear * CameraDirection;
DOUBLE3 FarCenter = CameraPosition + CurrentFar * CameraDirection;
double NearHeight2 = tan(FoV_rad / 2) * CurrentNear;
double FarHeight2 = tan(FoV_rad / 2) * CurrentFar;
double NearWidth2 = NearHeight2 * ViewRatio;
double FarWidth2 = FarHeight2 * ViewRatio;
XMFLOAT3 Edges[8];
Edges[0] = FarCenter + (FarHeight2) * CameraUp - (FarWidth2) * CameraRight;
Edges[1] = FarCenter + (FarHeight2) * CameraUp + (FarWidth2) * CameraRight;
Edges[2] = FarCenter - (FarHeight2) * CameraUp - (FarWidth2) * CameraRight;
Edges[3] = FarCenter - (FarHeight2) * CameraUp + (FarWidth2) * CameraRight;
Edges[4] = NearCenter + (NearHeight2)* CameraUp - (NearWidth2)* CameraRight;
Edges[5] = NearCenter + (NearHeight2)* CameraUp + (NearWidth2)* CameraRight;
Edges[6] = NearCenter - (NearHeight2)* CameraUp - (NearWidth2)* CameraRight;
Edges[7] = NearCenter - (NearHeight2)* CameraUp + (NearWidth2)* CameraRight;
XMFLOAT3 Test;
DOUBLE3 Min(std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity()), Max(-std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity());
for (int j = 0; j < 8; ++j){
XMStoreFloat3(&Test, XMVector3TransformCoord(XMLoadFloat3(&Edges[j]), RotationInverse));
if (Min.x > Test.x){
Min.x = Test.x;
}
if (Max.x < Test.x){
Max.x = Test.x;
}
if (Min.y > Test.y){
Min.y = Test.y;
}
if (Max.y < Test.y){
Max.y = Test.y;
}
if (Min.z > Test.z){
Min.z = Test.z;
}
if (Max.z < Test.z){
Max.z = Test.z;
}
}
XMFLOAT3 FocusPosition((Max.x + Min.x) / 2, (Max.y + Min.y) / 2, Max.z + 0.5f);
XMStoreFloat3(&FocusPosition, XMVector3TransformCoord(XMLoadFloat3(&FocusPosition), RotationMatrix));
XMFLOAT3 LightPosition = DOUBLE3(FocusPosition) - Distance*Direction;
XMFLOAT3 Up(0.0f,1.0f,0.0f);
XMStoreFloat3(&Up, XMVector3TransformCoord(XMLoadFloat3(&Up), RotationMatrix));
XMMATRIX ViewMatrix = XMMatrixLookAtLH(XMLoadFloat3(&LightPosition), XMLoadFloat3(&FocusPosition), XMLoadFloat3(&Up)),
ProjectionMatrix = XMMatrixOrthographicLH((Max.x - Min.x)*1.05, (Max.y - Min.y)*1.05, 0, Distance);
ViewProjectionMatricesT[i] = XMMatrixTranspose(XMMatrixMultiply(ViewMatrix, ProjectionMatrix));
LightViewFrustum.Update(Distance, ViewMatrix, ProjectionMatrix);
RenderFunction(DeviceContext, &LightViewFrustum, ViewProjectionMatricesT[i]);
CurrentDistance += CurrentSize;
}
}