Browse Source

Draw render-to-texture views upside down on OpenGL so that they match the UV coordinates of regular textures.
Fixed possible incorrect viewport after render target change on OpenGL.
Fixed incorrect G-buffer vertical offset coordinates on OpenGL.

Lasse Öörni 14 years ago
parent
commit
dec13dac7a

+ 1 - 1
Engine/Core/WorkQueue.h

@@ -1,6 +1,6 @@
 //
 // Urho3D Engine
-// Copyright (c) 2008-2011 Lasse ��rni
+// Copyright (c) 2008-2011 Lasse Öörni
 //
 // Permission is hereby granted, free of charge, to any person obtaining a copy
 // of this software and associated documentation files (the "Software"), to deal

+ 3 - 2
Engine/Graphics/Batch.cpp

@@ -175,7 +175,8 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
             graphics->SetAlphaTest(false);
         
         graphics->SetBlendMode(pass_->GetBlendMode());
-        graphics->SetCullMode(pass_->GetType() != PASS_SHADOW ? material_->GetCullMode() : material_->GetShadowCullMode());
+        renderer->SetCullMode(pass_->GetType() != PASS_SHADOW ? material_->GetCullMode() : material_->GetShadowCullMode(),
+            camera_);
         graphics->SetDepthTest(pass_->GetDepthTestMode());
         graphics->SetDepthWrite(pass_->GetDepthWrite());
     }
@@ -229,7 +230,7 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         
         #ifdef USE_OPENGL
         Vector4 bufferUVOffset(((float)viewport.left_) / gBufferWidth + widthRange,
-            ((float)viewport.top_) / gBufferHeight + heightRange, widthRange, heightRange);
+            1.0f - (((float)viewport.top_) / gBufferHeight + heightRange), widthRange, heightRange);
         #else
         Vector4 bufferUVOffset((0.5f + (float)viewport.left_) / gBufferWidth + widthRange,
             (0.5f + (float)viewport.top_) / gBufferHeight + heightRange, widthRange, heightRange);

+ 27 - 3
Engine/Graphics/Camera.cpp

@@ -37,6 +37,7 @@ OBJECTTYPESTATIC(Camera);
 
 Camera::Camera(Context* context) :
     Component(context),
+    projectionOffset_(Vector2::ZERO),
     nearClip_(DEFAULT_NEARCLIP),
     farClip_(DEFAULT_FARCLIP),
     fov_(DEFAULT_FOV),
@@ -44,11 +45,11 @@ Camera::Camera(Context* context) :
     aspectRatio_(1.0f),
     zoom_(1.0f),
     lodBias_(1.0f),
-    orthographic_(false),
-    autoAspectRatio_(true),
     viewMask_(DEFAULT_VIEWMASK),
     viewOverrideFlags_(VO_NONE),
-    projectionOffset_(Vector2::ZERO)
+    orthographic_(false),
+    autoAspectRatio_(true),
+    flipVertical_(false)
 {
 }
 
@@ -141,6 +142,11 @@ void Camera::SetProjectionOffset(const Vector2& offset)
     projectionOffset_ = offset;
 }
 
+void Camera::SetFlipVertical(bool enable)
+{
+    flipVertical_ = enable;
+}
+
 float Camera::GetNearClip() const
 {
     // Orthographic camera has always near clip at 0 to avoid trouble with shader depth parameters,
@@ -287,6 +293,18 @@ Matrix4 Camera::GetProjection() const
         ret.m33_ = 1.0f;
     }
     
+    if (flipVertical_)
+    {
+        Matrix4 flip(
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, -1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f
+        );
+        
+        ret = flip * ret;
+    }
+    
     return ret;
 }
 
@@ -309,6 +327,12 @@ void Camera::GetFrustumSize(Vector3& near, Vector3& far) const
         near.y_ = far.y_ = halfViewSize;
         near.x_ = far.x_ = near.y_ * aspectRatio_;
     }
+    
+    if (flipVertical_)
+    {
+        near.y_ = -near.y_;
+        far.y_ = -far.y_;
+    }
 }
 
 float Camera::GetHalfViewSize() const

+ 8 - 2
Engine/Graphics/Camera.h

@@ -72,6 +72,8 @@ public:
     void SetAutoAspectRatio(bool enable);
     /// %Set projection offset. It needs to be calculated as (offset in pixels) / (viewport dimensions.)
     void SetProjectionOffset(const Vector2& offset);
+    /// %Set vertical flipping mode.
+    void SetFlipVertical(bool enable);
     
     /// Return far clip distance.
     float GetFarClip() const { return farClip_; }
@@ -119,6 +121,8 @@ public:
     Vector3 GetUpVector();
     /// Return projection offset.
     const Vector2& GetProjectionOffset() const { return projectionOffset_; }
+    /// Return vertical flipping mode.
+    bool GetFlipVertical() const { return flipVertical_; }
     /// Return distance to position. In orthographic mode uses only Z coordinate.
     float GetDistance(const Vector3& worldPos);
     /// Return squared distance to position. In orthographic mode uses only Z coordinate.
@@ -132,6 +136,8 @@ public:
     Matrix3x4 GetInverseWorldTransform() const { return GetWorldTransform().Inverse(); }
     
 private:
+    /// Projection offset.
+    Vector2 projectionOffset_;
     /// Near clip distance.
     float nearClip_;
     /// Far clip distance.
@@ -154,6 +160,6 @@ private:
     bool orthographic_;
     /// Auto aspect ratio flag.
     bool autoAspectRatio_;
-    /// Projection offset.
-    Vector2 projectionOffset_;
+    /// Flip vertical flag.
+    bool flipVertical_;
 };

+ 3 - 6
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -1363,12 +1363,9 @@ void Graphics::SetViewport(const IntRect& rect)
     rectCopy.right_ = Clamp(rectCopy.right_, 0, rtSize.x_);
     rectCopy.bottom_ = Clamp(rectCopy.bottom_, 0, rtSize.y_);
     
-    if (rectCopy != viewport_)
-    {
-        // Use Direct3D convention with the vertical coordinates ie. 0 is top
-        glViewport(rectCopy.left_, rtSize.y_ - rectCopy.bottom_, rectCopy.right_ - rectCopy.left_, rectCopy.bottom_ - rectCopy.top_);
-        viewport_ = rectCopy;
-    }
+    // Use Direct3D convention with the vertical coordinates ie. 0 is top
+    glViewport(rectCopy.left_, rtSize.y_ - rectCopy.bottom_, rectCopy.right_ - rectCopy.left_, rectCopy.bottom_ - rectCopy.top_);
+    viewport_ = rectCopy;
     
     // Disable scissor test, needs to be re-enabled by the user
     SetScissorTest(false);

+ 14 - 0
Engine/Graphics/Renderer.cpp

@@ -1203,6 +1203,20 @@ void Renderer::SetLightVolumeBatchShaders(Batch& batch)
     batch.pixelShader_ = lightPS_[psi];
 }
 
+void Renderer::SetCullMode(CullMode mode, Camera* camera)
+{
+    // If a camera is specified, check for vertical flipping and reverse culling in that case
+    if (camera && camera->GetFlipVertical())
+    {
+        if (mode == CULL_CW)
+            mode = CULL_CCW;
+        else if (mode == CULL_CCW)
+            mode = CULL_CW;
+    }
+    
+    graphics_->SetCullMode(mode);
+}
+
 bool Renderer::ResizeInstancingBuffer(unsigned numInstances)
 {
     if (!instancingBuffer_ || !dynamicInstancing_)

+ 2 - 0
Engine/Graphics/Renderer.h

@@ -345,6 +345,8 @@ public:
     void SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, bool allowShadows = true);
     /// Choose shaders for a light volume batch.
     void SetLightVolumeBatchShaders(Batch& batch);
+    /// Set cull mode while taking possible projection flipping into account.
+    void SetCullMode(CullMode mode, Camera* camera);
     /// Ensure sufficient size of the instancing vertex buffer. Return true if successful.
     bool ResizeInstancingBuffer(unsigned numInstances);
     /// Reset shadow map allocation counts.

+ 24 - 11
Engine/Graphics/View.cpp

@@ -308,12 +308,30 @@ void View::Render()
     graphics_->SetTexture(TU_FACESELECT, renderer_->GetFaceSelectCubeMap());
     graphics_->SetTexture(TU_INDIRECTION, renderer_->GetIndirectionCubeMap());
     
+    // Set "view texture" to prevent destination texture sampling in case we do not render to the destination directly
+    // ie. when using light pre-pass and/or doing edge filtering
+    if (renderTarget_)
+        graphics_->SetViewTexture(renderTarget_->GetParentTexture());
+    
+    // On OpenGL, flip the projection if rendering to a texture so that the texture can be addressed in the same way
+    // as a render texture produced on Direct3D9
+    #ifdef USE_OPENGL
+    if (renderTarget_)
+        camera_->SetFlipVertical(true);
+    #endif
+    
     // Render
     if (lightPrepass_)
         RenderBatchesLightPrepass();
     else
         RenderBatchesForward();
     
+    #ifdef USE_OPENGL
+    camera_->SetFlipVertical(false);
+    #endif
+    
+    graphics_->SetViewTexture(0);
+    
     graphics_->SetScissorTest(false);
     graphics_->SetStencilTest(false);
     graphics_->ResetStreamFrequencies();
@@ -1045,9 +1063,6 @@ void View::RenderBatchesForward()
 
 void View::RenderBatchesLightPrepass()
 {
-    if (renderTarget_)
-        graphics_->SetViewTexture(renderTarget_->GetParentTexture());
-    
     // If not reusing shadowmaps, render all of them first
     if (!renderer_->GetReuseShadowMaps() && renderer_->GetDrawShadows() && !lightQueues_.Empty())
     {
@@ -1177,8 +1192,6 @@ void View::RenderBatchesLightPrepass()
         
         RenderBatchQueue(postAlphaQueue_);
     }
-    
-    graphics_->SetViewTexture(0);
 }
 
 void View::BlitFramebuffer()
@@ -1207,7 +1220,7 @@ void View::BlitFramebuffer()
         
         #ifdef USE_OPENGL
         Vector4 bufferUVOffset(((float)screenRect_.left_) / gBufferWidth + widthRange,
-            ((float)screenRect_.top_) / gBufferHeight + heightRange, widthRange, heightRange);
+            1.0f - (((float)screenRect_.top_) / gBufferHeight + heightRange), widthRange, heightRange);
         #else
         Vector4 bufferUVOffset((0.5f + (float)screenRect_.left_) / gBufferWidth + widthRange,
             (0.5f + (float)screenRect_.top_) / gBufferHeight + heightRange, widthRange, heightRange);
@@ -1598,15 +1611,15 @@ void View::OptimizeLightByStencil(Light* light)
         }
         
         // If possible, render the stencil volume front faces. However, close to the near clip plane render back faces instead
-        // to avoid clipping the front faces.
+        // to avoid clipping.
         if (lightDist < camera_->GetNearClip() * 2.0f)
         {
-            graphics_->SetCullMode(CULL_CW);
+            renderer_->SetCullMode(CULL_CW, camera_);
             graphics_->SetDepthTest(CMP_GREATER);
         }
         else
         {
-            graphics_->SetCullMode(CULL_CCW);
+            renderer_->SetCullMode(CULL_CCW, camera_);
             graphics_->SetDepthTest(CMP_LESSEQUAL);
         }
         
@@ -2125,12 +2138,12 @@ void View::SetupLightVolumeBatch(Batch& batch)
         // Draw front faces if not inside light volume
         if (lightDist < camera_->GetNearClip() * 2.0f)
         {
-            graphics_->SetCullMode(CULL_CW);
+            renderer_->SetCullMode(CULL_CW, camera_);
             graphics_->SetDepthTest(CMP_GREATER);
         }
         else
         {
-            graphics_->SetCullMode(CULL_CCW);
+            renderer_->SetCullMode(CULL_CCW, camera_);
             graphics_->SetDepthTest(CMP_LESSEQUAL);
         }
     }

+ 7 - 7
Engine/UI/UI.cpp

@@ -235,26 +235,26 @@ void UI::Render()
     
     if (!graphics_ || graphics_->IsDeviceLost() || !quads_.Size())
         return;
-
+    
     // Update quad geometry into the vertex buffer
     unsigned numVertices = quads_.Size() * 6;
     // Resize the vertex buffer if too small or much too large
     if (vertexBuffer_->GetVertexCount() < numVertices || vertexBuffer_->GetVertexCount() > numVertices * 2)
         vertexBuffer_->SetSize(numVertices, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true);
-
+    
     unsigned vertexSize = vertexBuffer_->GetVertexSize();
     void* lockedData = vertexBuffer_->Lock(0, numVertices, LOCK_DISCARD);
     if (!lockedData)
         return;
-
+    
     for (unsigned i = 0; i < batches_.Size(); ++i)
         batches_[i].UpdateGeometry(graphics_, ((unsigned char*)lockedData) + batches_[i].quadStart_ * vertexSize * 6);
-
+    
     vertexBuffer_->Unlock();
-
+    
     Vector2 scale(2.0f, -2.0f);
     Vector2 offset(-1.0f, 1.0f);
-
+    
     Matrix4 projection(Matrix4::IDENTITY);
     projection.m00_ = scale.x_;
     projection.m03_ = offset.x_;
@@ -263,7 +263,7 @@ void UI::Render()
     projection.m22_ = 1.0f;
     projection.m23_ = 0.0f;
     projection.m33_ = 1.0f;
-
+    
     graphics_->ResetRenderTargets();
     graphics_->ResetDepthStencil();
     graphics_->SetViewport(IntRect(0, 0, graphics_->GetWidth(), graphics_->GetHeight()));