private void _generateCurvedIllusionPlaneVertexData( HardwareVertexBuffer vertexBuffer, int ySegments, int xSegments, float xSpace, float halfWidth, float ySpace, float halfHeight, Matrix4 xform, bool firstTime, bool normals, Quaternion orientation, float curvature, float uTiles, float vTiles, int numberOfTexCoordSets, ref Vector3 min, ref Vector3 max, ref float maxSquaredLength )
{
// Imagine a large sphere with the camera located near the top
// The lower the curvature, the larger the sphere
// Use the angle from viewer to the points on the plane
// Credit to Aftershock for the general approach
Real cameraPosition; // Camera position relative to sphere center
// Derive sphere radius
//Vector3 vertPos; // position relative to camera
//Real sphDist; // Distance from camera to sphere along box vertex vector
// Vector3 camToSph; // camera position to sphere
Real sphereRadius;// Sphere radius
// Actual values irrelevant, it's the relation between sphere radius and camera position that's important
Real sphRadius = 100.0f;
Real camDistance = 5.0f;
sphereRadius = sphRadius - curvature;
cameraPosition = sphereRadius - camDistance;
Vector3 vec;
Vector3 norm;
float sphereDistance;
unsafe
{
// lock the vertex buffer
IntPtr data = vertexBuffer.Lock( BufferLocking.Discard );
float* pData = (float*)data.ToPointer();
for ( int y = 0; y < ySegments + 1; ++y )
{
for ( int x = 0; x < xSegments + 1; ++x )
{
// centered on origin
vec.x = ( x * xSpace ) - halfWidth;
vec.y = ( y * ySpace ) - halfHeight;
vec.z = 0.0f;
// transform by orientation and distance
vec = xform * vec;
// assign to geometry
*pData++ = vec.x;
*pData++ = vec.y;
*pData++ = vec.z;
// build bounds as we go
if ( firstTime )
{
min = vec;
max = vec;
maxSquaredLength = vec.LengthSquared;
firstTime = false;
}
else
{
min.Floor( vec );
max.Ceil( vec );
maxSquaredLength = Utility.Max( maxSquaredLength, vec.LengthSquared );
}
if ( normals )
{
norm = Vector3.UnitZ;
norm = orientation * norm;
*pData++ = vec.x;
*pData++ = vec.y;
*pData++ = vec.z;
}
// generate texture coordinates, normalize position, modify by orientation to return +y up
vec = orientation.Inverse() * vec;
vec.Normalize();
// find distance to sphere
sphereDistance = Utility.Sqrt( cameraPosition * cameraPosition * ( vec.y * vec.y - 1.0f ) + sphereRadius * sphereRadius ) - cameraPosition * vec.y;
vec.x *= sphereDistance;
vec.z *= sphereDistance;
// use x and y on sphere as texture coordinates, tiled
float s = vec.x * ( 0.01f * uTiles );
float t = vec.z * ( 0.01f * vTiles );
for ( int i = 0; i < numberOfTexCoordSets; i++ )
{
*pData++ = s;
*pData++ = ( 1 - t );
}
} // x
} // y
// unlock the buffer
vertexBuffer.Unlock();
} // unsafe
}