Skip to content

Instantly share code, notes, and snippets.

@native-m
Created January 8, 2020 19:01
Show Gist options
  • Save native-m/ddc11bef1e48b3b597b65055e4f7acb4 to your computer and use it in GitHub Desktop.
Save native-m/ddc11bef1e48b3b597b65055e4f7acb4 to your computer and use it in GitHub Desktop.
GTA: SA Stuff
void
UpdateShadowMatrix()
{
DirectX::XMMATRIX camInv;
DirectX::XMMATRIX shadowView;
RwCamera* rwcam = Scene.camera;
float minDist = RwCameraGetNearClipPlane(rwcam);
float maxDist = RwCameraGetFarClipPlane(rwcam);
CVector sunPos;
CVector camPos;
camInv = DirectX::XMMatrixInverse(nullptr, *(DirectX::XMMATRIX*)&viewTransform);
GetSunPos(&sunPos, *(float*)0xB7C4F0);
camPos = TheCamera.GetPosition();
DirectX::XMVECTOR p = DirectX::XMVectorSet(camPos.x - sunPos.x, camPos.y - sunPos.y, camPos.z - sunPos.z, 0.0f);
DirectX::XMVECTOR d = DirectX::XMVectorSet(camPos.x, camPos.y, camPos.z, 0.0f);
shadowView = DirectX::XMMatrixLookAtLH(p, d, DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 1.0f));
float aspectRatio = (float)rwcam->frameBuffer->width / (float)rwcam->frameBuffer->height;
float fov = atanf(1.f / projTransform.m[1][1]) * 2.f * (180.0 / M_PI);
float tanHalfHFov = tanf(DirectX::XMConvertToRadians(fov / 2.0f));
float tanHalfVFov = tanf(DirectX::XMConvertToRadians((fov * aspectRatio) / 2.0f));
for (int i = 0; i < MAX_SHADOW_MAP; i++)
{
float xNear = shadowSplit[i] * tanHalfHFov;
float xFar = shadowSplit[i + 1] * tanHalfHFov;
float yNear = shadowSplit[i] * tanHalfVFov;
float yFar = shadowSplit[i + 1] * tanHalfVFov;
DirectX::XMVECTOR frustum[8] = {
{ xNear, yNear, shadowSplit[i], 1.0f },
{ -xNear, yNear, shadowSplit[i], 1.0f },
{ xNear, -yNear, shadowSplit[i], 1.0f },
{ -xNear, -yNear, shadowSplit[i], 1.0f },
{ xFar, yFar, shadowSplit[i + 1], 1.0f },
{ -xFar, yFar, shadowSplit[i + 1], 1.0f },
{ xFar, -yFar, shadowSplit[i + 1], 1.0f },
{ -xFar, -yFar, shadowSplit[i + 1], 1.0f },
};
DirectX::XMVECTOR frustumLight[8];
float minX = FLT_MAX;
float maxX = FLT_MIN;
float minY = FLT_MAX;
float maxY = FLT_MIN;
float minZ = FLT_MAX;
float maxZ = FLT_MIN;
DirectX::XMVECTOR frustumCenter = DirectX::g_XMZero;
for (int j = 0; j < 8; j++)
{
DirectX::XMVECTOR vw = DirectX::XMVector4Transform(frustum[j], camInv);
frustum[j] = vw;
frustumCenter = DirectX::XMVectorAdd(frustumCenter, vw);
}
frustumCenter = DirectX::XMVectorScale(frustumCenter, 1.f / 8.f);
DirectX::XMMATRIX lView = DirectX::XMMatrixLookAtLH(
DirectX::XMVectorSet(frustumCenter.m128_f32[0] - sunPos.x, frustumCenter.m128_f32[1] - sunPos.y, frustumCenter.m128_f32[2] - sunPos.z, 0.0f),
frustumCenter,
DirectX::XMVectorSet(0.0f, 0.0f, 1.0f, 1.0f));
for (int j = 0; j < 8; j++)
{
frustumLight[j] = DirectX::XMVector4Transform(frustum[j], lView);
minX = min(frustumLight[j].m128_f32[0], minX);
maxX = max(frustumLight[j].m128_f32[0], maxX);
minY = min(frustumLight[j].m128_f32[1], minY);
maxY = max(frustumLight[j].m128_f32[1], maxY);
minZ = min(frustumLight[j].m128_f32[2], minZ);
maxZ = max(frustumLight[j].m128_f32[2], maxZ);
}
DirectX::XMVECTOR vmin = DirectX::XMVectorSet(minX, minY, 1.0f, 1.0f);
DirectX::XMVECTOR vmax = DirectX::XMVectorSet(maxX, maxY, 1.0f, 1.0f);
DirectX::XMVECTOR longestDiagonal = DirectX::XMVectorSet(
frustumLight[0].m128_f32[0] - frustumLight[6].m128_f32[0],
frustumLight[0].m128_f32[1] - frustumLight[6].m128_f32[1],
frustumLight[0].m128_f32[2] - frustumLight[6].m128_f32[2],
1.0f
);
float diagonalLength = DirectX::XMVector3Length(longestDiagonal).m128_f32[0];
longestDiagonal = DirectX::XMVectorReplicate(diagonalLength);
DirectX::XMVECTOR borderOffset = DirectX::XMVectorScale(DirectX::XMVectorSubtract(longestDiagonal, DirectX::XMVectorSubtract(vmax, vmin)), 0.5f);
borderOffset.m128_f32[2] = 0.0f;
borderOffset.m128_f32[3] = 0.0f;
vmin = DirectX::XMVectorSubtract(vmin, borderOffset);
vmax = DirectX::XMVectorAdd(vmax, borderOffset);
DirectX::XMVECTOR worldUnitsPerTexel = DirectX::XMVectorReplicate(diagonalLength / (float)SHADOW_MAP_SIZE);
worldUnitsPerTexel.m128_f32[2] = 1.0f;
worldUnitsPerTexel.m128_f32[3] = 1.0f;
vmin = DirectX::XMVectorDivide(vmin, worldUnitsPerTexel);
vmin = DirectX::XMVectorFloor(vmin);
vmin = DirectX::XMVectorMultiply(vmin, worldUnitsPerTexel);
vmax = DirectX::XMVectorDivide(vmax, worldUnitsPerTexel);
vmax = DirectX::XMVectorFloor(vmax);
vmax = DirectX::XMVectorMultiply(vmax, worldUnitsPerTexel);
DirectX::XMMATRIX lOrtho = DirectX::XMMatrixOrthographicOffCenterLH(
vmin.m128_f32[0],
vmax.m128_f32[0],
vmin.m128_f32[1],
vmax.m128_f32[1],
minZ,
maxZ + SHADOW_MAX_DIST);
DirectX::XMMATRIX shadowMatrix = DirectX::XMMatrixMultiply(lOrtho, shadowView);
DirectX::XMVECTOR origin = { 0.0f, 0.0f, 0.0f, 1.0f };
origin = DirectX::XMVector3Transform(origin, shadowMatrix);
origin = DirectX::XMVectorScale(origin, (float)SHADOW_MAP_SIZE / 2.0f);
DirectX::XMVECTOR roundedOrigin = DirectX::XMVectorRound(origin);
DirectX::XMVECTOR roundOffset = DirectX::XMVectorSubtract(roundedOrigin, origin);
roundOffset = DirectX::XMVectorScale(roundOffset, 2.0f / (float)SHADOW_MAP_SIZE);
roundOffset.m128_f32[2] = 0.f;
roundOffset.m128_f32[3] = 0.f;
lOrtho.r[3] = DirectX::XMVectorAdd(lOrtho.r[3], roundOffset);
shadowZInfo[i].x = minZ;
shadowZInfo[i].y = maxZ;
shadowMat[i] = DirectX::XMMatrixMultiply(
DirectX::XMMatrixTranspose(lOrtho),
DirectX::XMMatrixTranspose(lView));
DirectX::XMVECTOR v = { 0.0f, 0.0f, shadowSplit[i + 1], 1.0f };
v = DirectX::XMVector4Transform(v, *(DirectX::XMMATRIX*)&projTransform);
shadowZInfo[i].z = v.m128_f32[2];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment