mirror of
https://github.com/jmarshall23/DoomRTX.git
synced 2026-08-16 16:20:42 +02:00
222 lines
12 KiB
C++
222 lines
12 KiB
C++
/*
|
|
* Copyright (c) 2022-2023 NVIDIA CORPORATION. All rights reserved
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "sl.h"
|
|
#include "sl_consts.h"
|
|
|
|
namespace sl
|
|
{
|
|
|
|
inline void matrixMul(float4x4& result, const float4x4& a, const float4x4& b)
|
|
{
|
|
// Alias raw pointers over the input matrices
|
|
const float* pA = &a[0].x;
|
|
const float* pB = &b[0].x;
|
|
|
|
result[0].x = (float)((pA[0] * pB[0]) + (pA[1] * pB[4]) + (pA[2] * pB[8]) + (pA[3] * pB[12]));
|
|
result[0].y = (float)((pA[0] * pB[1]) + (pA[1] * pB[5]) + (pA[2] * pB[9]) + (pA[3] * pB[13]));
|
|
result[0].z = (float)((pA[0] * pB[2]) + (pA[1] * pB[6]) + (pA[2] * pB[10]) + (pA[3] * pB[14]));
|
|
result[0].w = (float)((pA[0] * pB[3]) + (pA[1] * pB[7]) + (pA[2] * pB[11]) + (pA[3] * pB[15]));
|
|
|
|
result[1].x = (float)((pA[4] * pB[0]) + (pA[5] * pB[4]) + (pA[6] * pB[8]) + (pA[7] * pB[12]));
|
|
result[1].y = (float)((pA[4] * pB[1]) + (pA[5] * pB[5]) + (pA[6] * pB[9]) + (pA[7] * pB[13]));
|
|
result[1].z = (float)((pA[4] * pB[2]) + (pA[5] * pB[6]) + (pA[6] * pB[10]) + (pA[7] * pB[14]));
|
|
result[1].w = (float)((pA[4] * pB[3]) + (pA[5] * pB[7]) + (pA[6] * pB[11]) + (pA[7] * pB[15]));
|
|
|
|
result[2].x = (float)((pA[8] * pB[0]) + (pA[9] * pB[4]) + (pA[10] * pB[8]) + (pA[11] * pB[12]));
|
|
result[2].y = (float)((pA[8] * pB[1]) + (pA[9] * pB[5]) + (pA[10] * pB[9]) + (pA[11] * pB[13]));
|
|
result[2].z = (float)((pA[8] * pB[2]) + (pA[9] * pB[6]) + (pA[10] * pB[10]) + (pA[11] * pB[14]));
|
|
result[2].w = (float)((pA[8] * pB[3]) + (pA[9] * pB[7]) + (pA[10] * pB[11]) + (pA[11] * pB[15]));
|
|
|
|
result[3].x = (float)((pA[12] * pB[0]) + (pA[13] * pB[4]) + (pA[14] * pB[8]) + (pA[15] * pB[12]));
|
|
result[3].y = (float)((pA[12] * pB[1]) + (pA[13] * pB[5]) + (pA[14] * pB[9]) + (pA[15] * pB[13]));
|
|
result[3].z = (float)((pA[12] * pB[2]) + (pA[13] * pB[6]) + (pA[14] * pB[10]) + (pA[15] * pB[14]));
|
|
result[3].w = (float)((pA[12] * pB[3]) + (pA[13] * pB[7]) + (pA[14] * pB[11]) + (pA[15] * pB[15]));
|
|
}
|
|
|
|
inline void matrixFullInvert(float4x4& result, const float4x4& mat)
|
|
{
|
|
// Matrix inversion code from https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix
|
|
// Alias raw pointers over the input matrix and the result
|
|
const float* pMat = &mat[0].x;
|
|
float* pResult = &result[0].x;
|
|
|
|
pResult[0] = pMat[5] * pMat[10] * pMat[15] - pMat[5] * pMat[11] * pMat[14] - pMat[9] * pMat[6] * pMat[15] + pMat[9] * pMat[7] * pMat[14] + pMat[13] * pMat[6] * pMat[11] - pMat[13] * pMat[7] * pMat[10];
|
|
pResult[4] = -pMat[4] * pMat[10] * pMat[15] + pMat[4] * pMat[11] * pMat[14] + pMat[8] * pMat[6] * pMat[15] - pMat[8] * pMat[7] * pMat[14] - pMat[12] * pMat[6] * pMat[11] + pMat[12] * pMat[7] * pMat[10];
|
|
pResult[8] = pMat[4] * pMat[9] * pMat[15] - pMat[4] * pMat[11] * pMat[13] - pMat[8] * pMat[5] * pMat[15] + pMat[8] * pMat[7] * pMat[13] + pMat[12] * pMat[5] * pMat[11] - pMat[12] * pMat[7] * pMat[9];
|
|
pResult[12] = -pMat[4] * pMat[9] * pMat[14] + pMat[4] * pMat[10] * pMat[13] + pMat[8] * pMat[5] * pMat[14] - pMat[8] * pMat[6] * pMat[13] - pMat[12] * pMat[5] * pMat[10] + pMat[12] * pMat[6] * pMat[9];
|
|
pResult[1] = -pMat[1] * pMat[10] * pMat[15] + pMat[1] * pMat[11] * pMat[14] + pMat[9] * pMat[2] * pMat[15] - pMat[9] * pMat[3] * pMat[14] - pMat[13] * pMat[2] * pMat[11] + pMat[13] * pMat[3] * pMat[10];
|
|
pResult[5] = pMat[0] * pMat[10] * pMat[15] - pMat[0] * pMat[11] * pMat[14] - pMat[8] * pMat[2] * pMat[15] + pMat[8] * pMat[3] * pMat[14] + pMat[12] * pMat[2] * pMat[11] - pMat[12] * pMat[3] * pMat[10];
|
|
pResult[9] = -pMat[0] * pMat[9] * pMat[15] + pMat[0] * pMat[11] * pMat[13] + pMat[8] * pMat[1] * pMat[15] - pMat[8] * pMat[3] * pMat[13] - pMat[12] * pMat[1] * pMat[11] + pMat[12] * pMat[3] * pMat[9];
|
|
pResult[13] = pMat[0] * pMat[9] * pMat[14] - pMat[0] * pMat[10] * pMat[13] - pMat[8] * pMat[1] * pMat[14] + pMat[8] * pMat[2] * pMat[13] + pMat[12] * pMat[1] * pMat[10] - pMat[12] * pMat[2] * pMat[9];
|
|
pResult[2] = pMat[1] * pMat[6] * pMat[15] - pMat[1] * pMat[7] * pMat[14] - pMat[5] * pMat[2] * pMat[15] + pMat[5] * pMat[3] * pMat[14] + pMat[13] * pMat[2] * pMat[7] - pMat[13] * pMat[3] * pMat[6];
|
|
pResult[6] = -pMat[0] * pMat[6] * pMat[15] + pMat[0] * pMat[7] * pMat[14] + pMat[4] * pMat[2] * pMat[15] - pMat[4] * pMat[3] * pMat[14] - pMat[12] * pMat[2] * pMat[7] + pMat[12] * pMat[3] * pMat[6];
|
|
pResult[10] = pMat[0] * pMat[5] * pMat[15] - pMat[0] * pMat[7] * pMat[13] - pMat[4] * pMat[1] * pMat[15] + pMat[4] * pMat[3] * pMat[13] + pMat[12] * pMat[1] * pMat[7] - pMat[12] * pMat[3] * pMat[5];
|
|
pResult[14] = -pMat[0] * pMat[5] * pMat[14] + pMat[0] * pMat[6] * pMat[13] + pMat[4] * pMat[1] * pMat[14] - pMat[4] * pMat[2] * pMat[13] - pMat[12] * pMat[1] * pMat[6] + pMat[12] * pMat[2] * pMat[5];
|
|
pResult[3] = -pMat[1] * pMat[6] * pMat[11] + pMat[1] * pMat[7] * pMat[10] + pMat[5] * pMat[2] * pMat[11] - pMat[5] * pMat[3] * pMat[10] - pMat[9] * pMat[2] * pMat[7] + pMat[9] * pMat[3] * pMat[6];
|
|
pResult[7] = pMat[0] * pMat[6] * pMat[11] - pMat[0] * pMat[7] * pMat[10] - pMat[4] * pMat[2] * pMat[11] + pMat[4] * pMat[3] * pMat[10] + pMat[8] * pMat[2] * pMat[7] - pMat[8] * pMat[3] * pMat[6];
|
|
pResult[11] = -pMat[0] * pMat[5] * pMat[11] + pMat[0] * pMat[7] * pMat[9] + pMat[4] * pMat[1] * pMat[11] - pMat[4] * pMat[3] * pMat[9] - pMat[8] * pMat[1] * pMat[7] + pMat[8] * pMat[3] * pMat[5];
|
|
pResult[15] = pMat[0] * pMat[5] * pMat[10] - pMat[0] * pMat[6] * pMat[9] - pMat[4] * pMat[1] * pMat[10] + pMat[4] * pMat[2] * pMat[9] + pMat[8] * pMat[1] * pMat[6] - pMat[8] * pMat[2] * pMat[5];
|
|
|
|
float det = pMat[0] * pResult[0] + pMat[1] * pResult[4] + pMat[2] * pResult[8] + pMat[3] * pResult[12];
|
|
if (det != 0.f)
|
|
{
|
|
det = 1.0f / det;
|
|
|
|
for (int i = 0; i < 16; ++i)
|
|
{
|
|
pResult[i] *= det;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Specialised lightweight matrix invert when the matrix is known to be orthonormal
|
|
inline void matrixOrthoNormalInvert(float4x4& result, const float4x4& mat)
|
|
{
|
|
// Transpose the first 3x3
|
|
result[0].x = mat[0].x;
|
|
result[0].y = mat[1].x;
|
|
result[0].z = mat[2].x;
|
|
result[1].x = mat[0].y;
|
|
result[1].y = mat[1].y;
|
|
result[1].z = mat[2].y;
|
|
result[2].x = mat[0].z;
|
|
result[2].y = mat[1].z;
|
|
result[2].z = mat[2].z;
|
|
|
|
// Invert the translation
|
|
result[3].x = -((mat[3].x * mat[0].x) + (mat[3].y * mat[0].y) + (mat[3].z * mat[0].z));
|
|
result[3].y = -((mat[3].x * mat[1].x) + (mat[3].y * mat[1].y) + (mat[3].z * mat[1].z));
|
|
result[3].z = -((mat[3].x * mat[2].x) + (mat[3].y * mat[2].y) + (mat[3].z * mat[2].z));
|
|
|
|
// Fill in the remaining constants
|
|
result[0].w = 0.0f;
|
|
result[1].w = 0.0f;
|
|
result[2].w = 0.0f;
|
|
result[3].w = 1.0f;
|
|
}
|
|
|
|
inline void vectorNormalize(float3& v)
|
|
{
|
|
float k = 1.f / sqrtf((v.x * v.x) + (v.y * v.y) + (v.z * v.z));
|
|
v.x *= k;
|
|
v.y *= k;
|
|
v.z *= k;
|
|
}
|
|
|
|
inline void vectorCrossProduct(float3& result, const float3& a, const float3& b)
|
|
{
|
|
result.x = a.y * b.z - a.z * b.y;
|
|
result.y = a.z * b.x - a.x * b.z;
|
|
result.z = a.x * b.y - a.y * b.x;
|
|
}
|
|
|
|
// Calculate a cameraToPrevCamera matrix from cameraToWorld and cameraToWorldPrev matrices
|
|
// but do so in such a way as to avoid precision issues.
|
|
//
|
|
// Traditionally, you might go something like this...
|
|
//
|
|
// worldToCameraPrev = invert(cameraToWorldPrev)
|
|
// cameraToPrevCamera = cameraToWorld * worldToCameraPrev
|
|
//
|
|
// But if you do that, you will subject yourself to fp32 precision issues if the camera is
|
|
// any kind of reasonable distance from the origin, because you'll end up adding small
|
|
// numbers to large numbers due to the large translations.
|
|
//
|
|
// But the camera's absolute position in the world doesn't matter at all to the result.
|
|
// What we're interested in is the camera's motion.
|
|
// So if we add the same thing to the translations of cameraToWorld and cameraToWorldPrev
|
|
// then we should get the same result.
|
|
// If we choose to subtract the current camera's translation in world space, then we will
|
|
// change a potentially very large translation value into a very small one - thereby
|
|
// sidestepping the precision issues.
|
|
inline void calcCameraToPrevCamera(float4x4& outCameraToPrevCamera, const float4x4& cameraToWorld, const float4x4& cameraToWorldPrev)
|
|
{
|
|
// Create translated versions of cameraToWorld and cameraToWorldPrev, translated to
|
|
// so that the current camera is effectively at the world origin.
|
|
// CC == 'Camera-Centred'
|
|
float4x4 cameraToCcWorld = cameraToWorld;
|
|
cameraToCcWorld[3] = float4(0, 0, 0, 1);
|
|
float4x4 cameraToCcWorldPrev = cameraToWorldPrev;
|
|
cameraToCcWorldPrev[3].x -= cameraToWorld[3].x;
|
|
cameraToCcWorldPrev[3].y -= cameraToWorld[3].y;
|
|
cameraToCcWorldPrev[3].z -= cameraToWorld[3].z;
|
|
|
|
// We can use an optimised invert if we assume that the camera matrix is orthonormal
|
|
float4x4 ccWorldToCameraPrev;
|
|
matrixOrthoNormalInvert(ccWorldToCameraPrev, cameraToCcWorldPrev);
|
|
matrixMul(outCameraToPrevCamera, cameraToCcWorld, ccWorldToCameraPrev);
|
|
}
|
|
|
|
// Calculate some of the matrix fields in Constants
|
|
// This can be used to validate what the app is providing, or tease out precision issues
|
|
// The matrices that are recalculated are...
|
|
// - clipToCameraView
|
|
// - clipToPrevClip
|
|
// - prevClipToClip
|
|
inline void recalculateCameraMatrices(Constants& values)
|
|
{
|
|
// Form a camera-to-world matrix from the camera fields
|
|
vectorNormalize(values.cameraRight);
|
|
vectorNormalize(values.cameraFwd);
|
|
vectorCrossProduct(values.cameraUp, values.cameraFwd, values.cameraRight);
|
|
vectorNormalize(values.cameraUp);
|
|
float4x4 cameraViewToWorld = {
|
|
float4(values.cameraRight.x, values.cameraRight.y, values.cameraRight.z, 0.f),
|
|
float4(values.cameraUp.x, values.cameraUp.y, values.cameraUp.z, 0.f),
|
|
float4(values.cameraFwd.x, values.cameraFwd.y, values.cameraFwd.z, 0.f),
|
|
float4(values.cameraPos.x, values.cameraPos.y, values.cameraPos.z, 1.f)
|
|
};
|
|
// ********* DO NOT USE THIS IN ANYTHING PROPER *********
|
|
// Crap storage of cameraViewToWorldPrev and cameraViewToClipPrev
|
|
// These should be provided by the app, or stored by association with the view index.
|
|
static float4x4 cameraViewToWorldPrev = {
|
|
float4(1, 0, 0, 0),
|
|
float4(0, 1, 0, 0),
|
|
float4(0, 0, 1, 0),
|
|
float4(0, 0, 0, 1),
|
|
};
|
|
static float4x4 cameraViewToClipPrev = {
|
|
float4(1, 0, 0, 0),
|
|
float4(0, 1, 0, 0),
|
|
float4(0, 0, 1, 0),
|
|
float4(0, 0, 0, 1),
|
|
};
|
|
matrixFullInvert(values.clipToCameraView, values.cameraViewToClip);
|
|
|
|
float4x4 cameraViewToPrevCameraView;
|
|
calcCameraToPrevCamera(cameraViewToPrevCameraView, cameraViewToWorld, cameraViewToWorldPrev);
|
|
|
|
float4x4 clipToPrevCameraView;
|
|
matrixMul(clipToPrevCameraView, values.clipToCameraView, cameraViewToPrevCameraView);
|
|
matrixMul(values.clipToPrevClip, clipToPrevCameraView, cameraViewToClipPrev);
|
|
matrixFullInvert(values.prevClipToClip, values.clipToPrevClip);
|
|
|
|
// ********* DO NOT USE THIS IN ANYTHING PROPER *********
|
|
cameraViewToWorldPrev = cameraViewToWorld;
|
|
cameraViewToClipPrev = values.cameraViewToClip;
|
|
}
|
|
|
|
}
|