_xiaofang/xiaofang/Assets/Obi/Resources/ObiMaterials/Common/ObiEllipsoidsHDRP.cginc
杨号敬 bcc74f0465 add
2024-12-18 02:18:45 +08:00

105 lines
4.3 KiB
HLSL

#ifndef OBIELLIPSOIDS_INCLUDED
#define OBIELLIPSOIDS_INCLUDED
// Eye ray origin in world space.
// Works both for orthographic and perspective cameras.
float3 WorldEye(float3 worldPos){
if ((UNITY_MATRIX_P[3].x == 0.0) && (UNITY_MATRIX_P[3].y == 0.0) && (UNITY_MATRIX_P[3].z == 0.0)){
return mul(UNITY_MATRIX_I_V,float4(mul(UNITY_MATRIX_V, float4(worldPos,1)).xy,0,1)).xyz;
}else
return _WorldSpaceCameraPos;
}
// Returns visible ellipsoid radius and offset from center, given the eye position in parameter space.
// Works both for orthographic and perspective cameras.
float VisibleEllipsoidCircleRadius(float3 eye, out float3 m){
if ((UNITY_MATRIX_P[3].x == 0.0) && (UNITY_MATRIX_P[3].y == 0.0) && (UNITY_MATRIX_P[3].z == 0.0)){
m = float3(0,0,0);
return 1;
}else{
float t = 1/dot(eye,eye);
m = t * eye;
return sqrt(1-t);
}
}
// Performs accurate raycasting of a spherical impostor.
// Works both for orthographic and perspective cameras.
void IntersectEllipsoid_float(float3 v, float4 mapping, float3 a2, float3 a3, out float3 eyePos, out float3 eyeNormal, out float thickness, out float clipThreshold)
{
float r2 = dot(mapping.xy, mapping.xy);
// clip if the ray does not intersect the sphere.
clipThreshold = r2/mapping.w;
float iq = 1 - clipThreshold;
float sqrtiq = sqrt(iq);
float lambda = 1/(1 + mapping.z * sqrtiq);
eyePos = lambda * v;
eyeNormal = normalize(a2 + lambda * a3);
// return gaussian-falloff thickness.
thickness = 2 * sqrtiq * exp(-r2*2.0f);
}
void BuildVelocityStretchedBasis_float(float3 velocity, float stretchIntensity, float radius, out float4 t0, out float4 t1, out float4 t2)
{
t0 = float4(UNITY_MATRIX_V[0].xyz, radius); // camera right vector
t2 = float4(UNITY_MATRIX_V[2].xyz, radius); // camera forward vector
float3 eyeVel = velocity - dot(velocity, t2.xyz) * t2.xyz;
float velNorm = length(eyeVel);
float stretchAmount = velNorm * stretchIntensity;
// use it to lerp between velocity vector and camera right:
t0 = float4(velNorm > 0.00001 ? eyeVel / velNorm : t0.xyz, radius * (1 + stretchAmount));
t1 = float4(normalize(cross(t0.xyz,t2.xyz)), radius);
}
void BuildParameterSpaceMatrices_float(float4 t0, float4 t1, float4 t2, float radiusScale, out float3x3 P, out float3x3 IP)
{
// build 3x3 orientation matrix and its inverse;
float3x3 IO = float3x3(t0.xyz,t1.xyz,t2.xyz);
float3x3 O = transpose(IO);
// build 3x3 scaling matrix and its inverse:
float3x3 S = float3x3(radiusScale*t0.w,0,0,0,radiusScale*t1.w,0,0,0,radiusScale*t2.w);
float3x3 IS = float3x3(1/(radiusScale*t0.w),0,0,0,1/(radiusScale*t1.w),0,0,0,1/(radiusScale*t2.w));
// build 3x3 transformation matrix and its inverse:
P = mul((float3x3)UNITY_MATRIX_M, mul(O,mul(S,IO)) );
IP = mul(mul(mul(O,IS),IO), (float3x3)UNITY_MATRIX_I_M);
}
void BuildEllipsoidBillboard_float(float3 center, float3 corner, float3x3 P, float3x3 IP, out float3 worldPos, out float3 view, out float3 eye, out float radius)
{
// eye position and quad vectors in parameter space:
eye = mul(IP,WorldEye(center) - center);
float3 u = normalize(cross(-eye,UNITY_MATRIX_V[1].xyz));
float3 k = normalize(cross(-eye,u));
// visible circle radius and offset from center in the direction of the view ray:
float3 m;
radius = VisibleEllipsoidCircleRadius(eye,m);
// world position of the billboard corner, and view vector to it:
worldPos = center + mul(P, m) + radius * (mul(P,u)* corner.x + mul(P,k)* corner.y);
view = worldPos - WorldEye(worldPos);
}
void BuildAuxiliaryNormalVectors_float(float3 center, float3 worldPos, float3 view, float3x3 P, float3x3 IP, out float3 a2, out float3 a3)
{
// calculate T^-2 in object space, then multiply by
// inverse transpose of modelview to rotate normal from object to eye.
// This way the normal calculated in IntersectEllipsoid() is already in view space.
IP = mul((float3x3)UNITY_MATRIX_M,IP);
float3x3 IT_MV = transpose(mul((float3x3)UNITY_MATRIX_I_V, (float3x3)UNITY_MATRIX_I_M));
float3x3 IP2 = mul(IT_MV, mul((float3x3)UNITY_MATRIX_I_M,mul (IP, IP))); // UNITY_MATRIX_IT_MV
a2 = mul(IP2,WorldEye(worldPos) - center); //T^-2 * (eye - center)
a3 = mul(IP2,view); //T^-2 * A[0]
}
#endif