#ifndef UNITY_SPACE_TRANSFORMS_INCLUDED #define UNITY_SPACE_TRANSFORMS_INCLUDED #if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3 #pragma warning (disable : 3205) // conversion of larger type to smaller #endif // Caution: For HDRP, adding a function in this file requires adding the appropriate #define in PickingSpaceTransforms.hlsl // Return the PreTranslated ObjectToWorld Matrix (i.e matrix with _WorldSpaceCameraPos apply to it if we use camera relative rendering) float4x4 GetObjectToWorldMatrix() { return UNITY_MATRIX_M; } float4x4 GetWorldToObjectMatrix() { return UNITY_MATRIX_I_M; } float4x4 GetPrevObjectToWorldMatrix() { return UNITY_PREV_MATRIX_M; } float4x4 GetPrevWorldToObjectMatrix() { return UNITY_PREV_MATRIX_I_M; } float4x4 GetWorldToViewMatrix() { return UNITY_MATRIX_V; } // Transform to homogenous clip space float4x4 GetWorldToHClipMatrix() { return UNITY_MATRIX_VP; } // Transform to homogenous clip space float4x4 GetViewToHClipMatrix() { return UNITY_MATRIX_P; } // This function always return the absolute position in WS float3 GetAbsolutePositionWS(float3 positionRWS) { #if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0) positionRWS += _WorldSpaceCameraPos.xyz; #endif return positionRWS; } // This function return the camera relative position in WS float3 GetCameraRelativePositionWS(float3 positionWS) { #if (SHADEROPTIONS_CAMERA_RELATIVE_RENDERING != 0) positionWS -= _WorldSpaceCameraPos.xyz; #endif return positionWS; } real GetOddNegativeScale() { // FIXME: We should be able to just return unity_WorldTransformParams.w, but it is not // properly set at the moment, when doing ray-tracing; once this has been fixed in cpp, // we can revert back to the former implementation. return unity_WorldTransformParams.w >= 0.0 ? 1.0 : -1.0; } float3 TransformObjectToWorld(float3 positionOS) { #if defined(SHADER_STAGE_RAY_TRACING) return mul(ObjectToWorld3x4(), float4(positionOS, 1.0)).xyz; #else return mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0)).xyz; #endif } float3 TransformWorldToObject(float3 positionWS) { #if defined(SHADER_STAGE_RAY_TRACING) return mul(WorldToObject3x4(), float4(positionWS, 1.0)).xyz; #else return mul(GetWorldToObjectMatrix(), float4(positionWS, 1.0)).xyz; #endif } float3 TransformWorldToView(float3 positionWS) { return mul(GetWorldToViewMatrix(), float4(positionWS, 1.0)).xyz; } // Transforms position from object space to homogenous space float4 TransformObjectToHClip(float3 positionOS) { // More efficient than computing M*VP matrix product return mul(GetWorldToHClipMatrix(), mul(GetObjectToWorldMatrix(), float4(positionOS, 1.0))); } // Tranforms position from world space to homogenous space float4 TransformWorldToHClip(float3 positionWS) { return mul(GetWorldToHClipMatrix(), float4(positionWS, 1.0)); } // Tranforms position from view space to homogenous space float4 TransformWViewToHClip(float3 positionVS) { return mul(GetViewToHClipMatrix(), float4(positionVS, 1.0)); } // Normalize to support uniform scaling float3 TransformObjectToWorldDir(float3 dirOS, bool doNormalize = true) { #ifndef SHADER_STAGE_RAY_TRACING float3 dirWS = mul((float3x3)GetObjectToWorldMatrix(), dirOS); #else float3 dirWS = mul((float3x3)ObjectToWorld3x4(), dirOS); #endif if (doNormalize) return SafeNormalize(dirWS); return dirWS; } // Normalize to support uniform scaling float3 TransformWorldToObjectDir(float3 dirWS, bool doNormalize = true) { #ifndef SHADER_STAGE_RAY_TRACING float3 dirOS = mul((float3x3)GetWorldToObjectMatrix(), dirWS); #else float3 dirOS = mul((float3x3)WorldToObject3x4(), dirWS); #endif if (doNormalize) return normalize(dirOS); return dirOS; } // Tranforms vector from world space to view space real3 TransformWorldToViewDir(real3 dirWS, bool doNormalize = false) { float3 dirVS = mul((real3x3)GetWorldToViewMatrix(), dirWS).xyz; if (doNormalize) return normalize(dirVS); return dirVS; } // Tranforms vector from world space to homogenous space real3 TransformWorldToHClipDir(real3 directionWS, bool doNormalize = false) { float3 dirHCS = mul((real3x3)GetWorldToHClipMatrix(), directionWS).xyz; if (doNormalize) return normalize(dirHCS); return dirHCS; } // Transforms normal from object to world space float3 TransformObjectToWorldNormal(float3 normalOS, bool doNormalize = true) { #ifdef UNITY_ASSUME_UNIFORM_SCALING return TransformObjectToWorldDir(normalOS, doNormalize); #else // Normal need to be multiply by inverse transpose float3 normalWS = mul(normalOS, (float3x3)GetWorldToObjectMatrix()); if (doNormalize) return SafeNormalize(normalWS); return normalWS; #endif } // Transforms normal from world to object space float3 TransformWorldToObjectNormal(float3 normalWS, bool doNormalize = true) { #ifdef UNITY_ASSUME_UNIFORM_SCALING return TransformWorldToObjectDir(normalWS, doNormalize); #else // Normal need to be multiply by inverse transpose float3 normalOS = mul(normalWS, (float3x3)GetObjectToWorldMatrix()); if (doNormalize) return SafeNormalize(normalOS); return normalOS; #endif } real3x3 CreateTangentToWorld(real3 normal, real3 tangent, real flipSign) { // For odd-negative scale transforms we need to flip the sign real sgn = flipSign * GetOddNegativeScale(); real3 bitangent = cross(normal, tangent) * sgn; return real3x3(tangent, bitangent, normal); } real3 TransformTangentToWorld(float3 dirTS, real3x3 tangentToWorld) { // Note matrix is in row major convention with left multiplication as it is build on the fly return mul(dirTS, tangentToWorld); } // This function does the exact inverse of TransformTangentToWorld() and is // also decribed within comments in mikktspace.h and it follows implicitly // from the scalar triple product (google it). real3 TransformWorldToTangent(real3 dirWS, real3x3 tangentToWorld) { // Note matrix is in row major convention with left multiplication as it is build on the fly float3 row0 = tangentToWorld[0]; float3 row1 = tangentToWorld[1]; float3 row2 = tangentToWorld[2]; // these are the columns of the inverse matrix but scaled by the determinant float3 col0 = cross(row1, row2); float3 col1 = cross(row2, row0); float3 col2 = cross(row0, row1); float determinant = dot(row0, col0); float sgn = determinant<0.0 ? (-1.0) : 1.0; // inverse transposed but scaled by determinant // Will remove transpose part by using matrix as the first arg in the mul() below // this makes it the exact inverse of what TransformTangentToWorld() does. real3x3 matTBN_I_T = real3x3(col0, col1, col2); return SafeNormalize( sgn * mul(matTBN_I_T, dirWS) ); } real3 TransformTangentToObject(real3 dirTS, real3x3 tangentToWorld) { // Note matrix is in row major convention with left multiplication as it is build on the fly real3 normalWS = TransformTangentToWorld(dirTS, tangentToWorld); return TransformWorldToObjectNormal(normalWS); } real3 TransformObjectToTangent(real3 dirOS, real3x3 tangentToWorld) { // Note matrix is in row major convention with left multiplication as it is build on the fly // don't normalize, as normalWS will be normalized after TransformWorldToTangent float3 normalWS = TransformObjectToWorldNormal(dirOS, false); // transform from world to tangent return TransformWorldToTangent(normalWS, tangentToWorld); } #if SHADER_API_MOBILE || SHADER_API_GLES || SHADER_API_GLES3 #pragma warning (enable : 3205) // conversion of larger type to smaller #endif #endif