Torque3D/Templates/Empty/game/shaders/common/imposter.hlsl
2012-09-19 11:29:55 -04:00

149 lines
5.5 KiB
HLSL

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// 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.
//-----------------------------------------------------------------------------
#include "torque.hlsl"
static float sCornerRight[4] = { -1, 1, 1, -1 };
static float sCornerUp[4] = { -1, -1, 1, 1 };
static float2 sUVCornerExtent[4] =
{
float2( 0, 1 ),
float2( 1, 1 ),
float2( 1, 0 ),
float2( 0, 0 )
};
#define IMPOSTER_MAX_UVS 64
void imposter_v(
// These parameters usually come from the vertex.
float3 center,
int corner,
float halfSize,
float3 imposterUp,
float3 imposterRight,
// These are from the imposter shader constant.
int numEquatorSteps,
int numPolarSteps,
float polarAngle,
bool includePoles,
// Other shader constants.
float3 camPos,
float4 uvs[IMPOSTER_MAX_UVS],
// The outputs of this function.
out float3 outWsPosition,
out float2 outTexCoord,
out float3x3 outWorldToTangent
)
{
// TODO: This could all be calculated on the CPU.
float equatorStepSize = M_2PI_F / numEquatorSteps;
float equatorHalfStep = ( equatorStepSize / 2.0 ) - 0.0001;
float polarStepSize = M_PI_F / numPolarSteps;
float polarHalfStep = ( polarStepSize / 2.0 ) - 0.0001;
// The vector between the camera and the billboard.
float3 lookVec = normalize( camPos - center );
// Generate the camera up and right vectors from
// the object transform and camera forward.
float3 camUp = imposterUp;
float3 camRight = normalize( cross( -lookVec, camUp ) );
// The billboarding is based on the camera directions.
float3 rightVec = camRight * sCornerRight[corner];
float3 upVec = camUp * sCornerUp[corner];
float lookPitch = acos( dot( imposterUp, lookVec ) );
// First check to see if we need to render the top billboard.
int index;
/*
if ( includePoles && ( lookPitch < polarAngle || lookPitch > sPi - polarAngle ) )
{
index = numEquatorSteps * 3;
// When we render the top/bottom billboard we always use
// a fixed vector that matches the rotation of the object.
rightVec = float3( 1, 0, 0 ) * sCornerRight[corner];
upVec = float3( 0, 1, 0 ) * sCornerUp[corner];
if ( lookPitch > sPi - polarAngle )
{
upVec = -upVec;
index++;
}
}
else
*/
{
// Calculate the rotation around the z axis then add the
// equator half step. This gets the images to switch a
// half step before the captured angle is met.
float lookAzimuth = atan2( lookVec.y, lookVec.x );
float azimuth = atan2( imposterRight.y, imposterRight.x );
float rotZ = ( lookAzimuth - azimuth ) + equatorHalfStep;
// The y rotation is calculated from the look vector and
// the object up vector.
float rotY = lookPitch - polarHalfStep;
// TODO: How can we do this without conditionals?
// Normalize the result to 0 to 2PI.
if ( rotZ < 0 )
rotZ += M_2PI_F;
if ( rotZ > M_2PI_F )
rotZ -= M_2PI_F;
if ( rotY < 0 )
rotY += M_2PI_F;
if ( rotY > M_PI_F ) // Not M_2PI_F?
rotY -= M_2PI_F;
float polarIdx = round( abs( rotY ) / polarStepSize );
// Get the index to the start of the right polar
// images for this viewing angle.
int numPolarOffset = numEquatorSteps * polarIdx;
// Calculate the final image index for lookup
// of the texture coords.
index = ( rotZ / equatorStepSize ) + numPolarOffset;
}
// Generate the final world space position.
outWsPosition = center + ( upVec * halfSize ) + ( rightVec * halfSize );
// Grab the uv set and setup the texture coord.
float4 uvSet = uvs[index];
outTexCoord.x = uvSet.x + ( uvSet.z * sUVCornerExtent[corner].x );
outTexCoord.y = uvSet.y + ( uvSet.w * sUVCornerExtent[corner].y );
// Needed for normal mapping and lighting.
outWorldToTangent[0] = float3( 1, 0, 0 );
outWorldToTangent[1] = float3( 0, 1, 0 );
outWorldToTangent[2] = float3( 0, 0, -1 );
}