105 lines
4.3 KiB
HLSL
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
|