diff options
Diffstat (limited to 'Runtime/Camera/Skybox.cpp')
-rw-r--r-- | Runtime/Camera/Skybox.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/Runtime/Camera/Skybox.cpp b/Runtime/Camera/Skybox.cpp new file mode 100644 index 0000000..528859e --- /dev/null +++ b/Runtime/Camera/Skybox.cpp @@ -0,0 +1,199 @@ +#include "UnityPrefix.h" +#include "Skybox.h" +#include "Runtime/Serialize/TransferFunctions/SerializeTransfer.h" +#include "Camera.h" +#include "CameraUtil.h" +#include "Runtime/Shaders/Material.h" +#include "External/shaderlab/Library/intshader.h" +#include "Runtime/Shaders/Shader.h" +#include "Runtime/GfxDevice/GfxDevice.h" +#include "Runtime/Shaders/VBO.h" +#include "Runtime/Profiler/ExternalGraphicsProfiler.h" + +PROFILER_INFORMATION(gRenderSkyboxProfile, "Camera.RenderSkybox", kProfilerRender); + + +using namespace ShaderLab; + +enum +{ + kSkyboxVertexChannels = (1<<kShaderChannelVertex) | (1<<kShaderChannelTexCoord0) +}; + +struct SkyboxVertex { + float x, y, z; + float tu, tv; +}; + +const int kSkyboxVertexCount = 6*4; +static const SkyboxVertex kSkyboxVB[kSkyboxVertexCount] = { + { -1, 1, 1, 0,1 }, { 1, 1, 1, 1,1 }, { 1, -1, 1, 1,0 }, { -1, -1, 1, 0,0 }, + { 1, 1, -1, 0,1 }, { -1, 1, -1, 1,1 }, { -1, -1, -1, 1,0 }, { 1, -1, -1, 0,0 }, + { 1, 1, 1, 0,1 }, { 1, 1, -1, 1,1 }, { 1, -1, -1, 1,0 }, { 1, -1, 1, 0,0 }, + { -1, 1, -1, 0,1 }, { -1, 1, 1, 1,1 }, { -1, -1, 1, 1,0 }, { -1, -1, -1, 0,0 }, + { -1, 1, -1, 0,1 }, { 1, 1, -1, 1,1 }, { 1, 1, 1, 1,0 }, { -1, 1, 1, 0,0 }, + { -1, -1, 1, 0,1 }, { 1, -1, 1, 1,1 }, { 1, -1, -1, 1,0 }, { -1, -1, -1, 0,0 }, +}; + +const int kSkyplaneVertexCount = 4; +static const SkyboxVertex kSkyplaneVB[kSkyplaneVertexCount] = { + { 1, 1, -1, 0,1 }, { -1, 1, -1, 1,1 }, { -1, -1, -1, 1,0 }, { 1, -1, -1, 0,0 }, +}; + +Skybox::Skybox (MemLabelId label, ObjectCreationMode mode) +: Super(label, mode) +{ +} + +Skybox::~Skybox () +{ +} + +void Skybox::AddToManager () +{ + +} + +void Skybox::RemoveFromManager () +{ + +} + +void Skybox::RenderSkybox (Material* mat, const Camera& camera) +{ + if( !mat ) + return; + + PROFILER_AUTO_GFX(gRenderSkyboxProfile, &camera) + + Shader* shader = mat->GetShader(); + Assert (shader); + + GfxDevice& device = GetGfxDevice(); + + DeviceMVPMatricesState preserveMVP; + + #if UNITY_WP8 + void RotateScreenIfNeeded(Matrix4x4f& mat); + #endif + + if (camera.GetOrthographic()) + { + const float epsilon = 1e-6f; + const float nearPlane = camera.GetNear () * 0.01f; + const float dist = camera.GetFar() * 10.0f; + + // Make Ortho matrix which passes W to Z + Matrix4x4f projection = Matrix4x4f::identity; + //camera.GetImplicitProjectionMatrix( nearPlane, projection ); + projection.Get(2, 2) = -1.0f + epsilon; + projection.Get(2, 3) = (-2.0f + epsilon) * nearPlane; + projection.Get(3, 2) = -1.0f; + + #if UNITY_WP8 + if (!RenderTexture::GetActive()) { + RotateScreenIfNeeded(projection); + } + #endif + + Matrix4x4f matrix = Matrix4x4f::identity; + //device.SetViewMatrix(matrix.GetPtr()); + matrix.SetScale(Vector3f(dist,dist,dist)); + matrix.SetPosition( camera.GetPosition() ); + device.SetWorldMatrix(matrix.GetPtr()); + device.SetProjectionMatrix(projection); + } + else + { + // Modify Projection matrix to make Infinite Projection Matrix (which passes W into Z) + // perspective divide will lend ZBuffer value to always be 1.0 (all points on far plane) + // NOTE: However we need to compensate on floating point precision errors + // by bringing Z slightly closer to viewer by adding Epsilon + // See "Projection Matrix Tricks" by Eric Lengyel GDC2007 + // http://www.terathon.com/gdc07_lengyel.ppt + + // In order to avoid clipping of skybox polys we increase skybox size and pull NearPlane as close as possible + // Higher epsilon values that Z/W < 1.0, but drastically reduces zBuffer precision close to FarPlane + // Epsilon 1e-6 gives good results as long as NearPlane >= 0.05 + const float epsilon = 1e-6f; + const float nearPlane = camera.GetNear () * 0.01f; + const float dist = camera.GetFar() * 10.0f; + + Matrix4x4f projection; + camera.GetImplicitProjectionMatrix( nearPlane, projection ); + projection.Get(2, 2) = -1.0f + epsilon; + projection.Get(2, 3) = (-2.0f + epsilon) * nearPlane; + projection.Get(3, 2) = -1.0f; + + #if UNITY_WP8 + if (!RenderTexture::GetActive()) { + RotateScreenIfNeeded(projection); + } + #endif + + Matrix4x4f matrix = Matrix4x4f::identity; + matrix.SetScale( Vector3f(dist,dist,dist) ); + matrix.SetPosition( camera.GetPosition() ); + device.SetWorldMatrix( matrix.GetPtr() ); + device.SetProjectionMatrix(projection); + } + + ShaderLab::IntShader* slshader = shader->GetShaderLabShader(); + const int passCount = slshader->GetActiveSubShader().GetValidPassCount(); + if( passCount == 6 ) + { + // regular skybox with 6 separate textures per face + DynamicVBO& vbo = device.GetDynamicVBO(); + for( int j = 0; j < 6; j++ ) + { + SkyboxVertex* vbPtr = 0; + if(vbo.GetChunk(kSkyboxVertexChannels, 4, 0, DynamicVBO::kDrawQuads, (void**)&vbPtr, NULL)) + { + vbPtr[0] = kSkyboxVB[4*j+0]; + vbPtr[1] = kSkyboxVB[4*j+1]; + vbPtr[2] = kSkyboxVB[4*j+2]; + vbPtr[3] = kSkyboxVB[4*j+3]; + + vbo.ReleaseChunk(4, 0); + + const ChannelAssigns* channels = mat->SetPassWithShader( j, shader, 0 ); + vbo.DrawChunk (*channels); + GPU_TIMESTAMP(); + } + } + } + else + { + // cube mapped skybox + for (int pass = 0; pass < passCount; pass++) + { + mat->SetPassWithShader( pass, shader, 0 ); + device.ImmediateBegin( kPrimitiveQuads ); + const SkyboxVertex* verts = kSkyboxVB; + for ( int i = 0; i < kSkyboxVertexCount; i++ ) { + device.ImmediateTexCoordAll( verts->x, verts->y, verts->z ); + device.ImmediateVertex( verts->x, verts->y, verts->z ); + ++verts; + } + device.ImmediateEnd(); + GPU_TIMESTAMP(); + } + } +} + +void Skybox::SetMaterial (Material* material) { + m_CustomSkybox = material; +} + +Material* Skybox::GetMaterial ()const { + return m_CustomSkybox; +} + +template<class TransferFunction> +void Skybox::Transfer (TransferFunction& transfer) { + Super::Transfer (transfer); + TRANSFER_SIMPLE (m_CustomSkybox); +} + +IMPLEMENT_CLASS (Skybox) +IMPLEMENT_OBJECT_SERIALIZE (Skybox) |