Hi All!
I would like to know if you get any idea on optimisation of rendering process when rendering a lot of views. My objective is to create a fisheye camera with 180? FOV (or more). I succeeded doing so using process descibed here: http://strlen.com/gfxengine/fisheyequake/. In short, you create 5 cameras instead of one, each 90? FOV and pointing in directions front, left, right, top, bottom (and optionally rear). The cameras originate in single point. Output of these cameras is rendered on sides of TextureCube. Then I sample it from the texture cube in a simple shader and display to output Texture2D. I share the code if anyone finds it useful:
Sample(camera mounted on grill of brown car, 180? FOV):
CubeCamera.h
#pragma once
#include <Urho3D/Container/Str.h>
#include <Urho3D/Core/Context.h>
#include <Urho3D/Graphics/Camera.h>
#include <Urho3D/Graphics/Graphics.h>
#include <Urho3D/Graphics/RenderPath.h>
#include <Urho3D/Graphics/RenderSurface.h>
#include <Urho3D/Graphics/Texture2D.h>
#include <Urho3D/Graphics/TextureCube.h>
#include <Urho3D/Resource/ResourceCache.h>
#include <Urho3D/Resource/XMLFile.h>
#include <Urho3D/Scene/Scene.h>
using namespace Urho3D;
class CubeCamera
{
public:
/// Construct.
CubeCamera(Context * context, Scene * scene, Node * parent_node, String name);
Texture2D * GetOutputTexture();
protected:
private:
Context * context_;
String name_;
Scene * scene_;
SharedPtr<TextureCube> cubeRenderTex_;
SharedPtr<Texture2D> cubeResultRenderTex_;
SharedPtr<Viewport> cubeViewport_;
SharedPtr<Node> parentNode_;
SharedPtr<Node> frontCubeCameraNode_;
SharedPtr<Node> leftCubeCameraNode_;
SharedPtr<Node> rightCubeCameraNode_;
SharedPtr<Node> topCubeCameraNode_;
SharedPtr<Node> bottomCubeCameraNode_;
};
CubeCamera.cpp
#include <Urho3D/Urho3D.h>
#include "CubeCamera.h"
#define CAM_W 1280
#define CAM_H 1280
#define CAM_FAR_CLIP 100.0f
#define CUBE_SIZE 1280
CubeCamera::CubeCamera(Context * context, Scene * scene, Node * parent_node, String name) :
context_(context),
scene_(scene),
parentNode_(parent_node),
name_(name)
{
ResourceCache* cache = context->GetSubsystem<ResourceCache>();
// Create perpendicular cameras with FOV of 90deg
frontCubeCameraNode_ = parent_node->CreateChild(name + "FrontCubeSide");
frontCubeCameraNode_->Rotate(Quaternion(0.0f, Vector3::RIGHT), TS_PARENT);
Camera* frontCubeCamera = frontCubeCameraNode_->CreateComponent<Camera>();
frontCubeCamera->SetFarClip(CAM_FAR_CLIP);
frontCubeCamera->SetFov(90.0f);
leftCubeCameraNode_ = parent_node->CreateChild(name + "LeftCubeSide");
leftCubeCameraNode_->Rotate(Quaternion(-90.0f, Vector3::UP), TS_PARENT);
Camera* leftCubeCamera = leftCubeCameraNode_->CreateComponent<Camera>();
leftCubeCamera->SetFarClip(CAM_FAR_CLIP);
leftCubeCamera->SetFov(90.0f);
rightCubeCameraNode_ = parent_node->CreateChild(name + "RightCubeSide");
rightCubeCameraNode_->Rotate(Quaternion(90.0f, Vector3::UP), TS_PARENT);
Camera* rightCubeCamera = rightCubeCameraNode_->CreateComponent<Camera>();
rightCubeCamera->SetFarClip(CAM_FAR_CLIP);
rightCubeCamera->SetFov(90.0f);
topCubeCameraNode_ = parent_node->CreateChild(name + "TopCubeSide");
topCubeCameraNode_->Rotate(Quaternion(-90.0f, Vector3::RIGHT), TS_PARENT);
topCubeCameraNode_->Rotate(Quaternion(-90.0f, Vector3::FORWARD), TS_LOCAL);
Camera* topCubeCamera = topCubeCameraNode_->CreateComponent<Camera>();
topCubeCamera->SetFarClip(CAM_FAR_CLIP);
topCubeCamera->SetFov(90.0f);
bottomCubeCameraNode_ = parent_node->CreateChild(name + "BottomCubeSide");
bottomCubeCameraNode_->Rotate(Quaternion(90.0f, Vector3::RIGHT), TS_PARENT);
bottomCubeCameraNode_->Rotate(Quaternion(90.0f, Vector3::FORWARD), TS_LOCAL);
Camera* bottomCubeCamera = bottomCubeCameraNode_->CreateComponent<Camera>();
bottomCubeCamera->SetFarClip(CAM_FAR_CLIP);
bottomCubeCamera->SetFov(90.0f);
// Create cube texture (intermediate render target)
cubeRenderTex_ = new TextureCube(context);
cubeRenderTex_->SetSize(CUBE_SIZE, Graphics::GetRGBAFormat(), TEXTURE_RENDERTARGET);
cubeRenderTex_->SetName(name + "CubeTex");
cache->AddManualResource(cubeRenderTex_);
// Create render surfaces on individual sides of the cube texture
RenderSurface* surface = cubeRenderTex_->GetRenderSurface(CubeMapFace::FACE_POSITIVE_X);
SharedPtr<Viewport> cubeFrontViewport(new Viewport(context, scene, frontCubeCamera));
surface->SetViewport(0, cubeFrontViewport);
surface->SetUpdateMode(SURFACE_UPDATEALWAYS);
surface = cubeRenderTex_->GetRenderSurface(CubeMapFace::FACE_POSITIVE_Z);
SharedPtr<Viewport> cubeLeftViewport(new Viewport(context, scene, leftCubeCamera));
surface->SetViewport(0, cubeLeftViewport);
surface->SetUpdateMode(SURFACE_UPDATEALWAYS);
surface = cubeRenderTex_->GetRenderSurface(CubeMapFace::FACE_NEGATIVE_Z);
SharedPtr<Viewport> cubeRightViewport(new Viewport(context, scene, rightCubeCamera));
surface->SetViewport(0, cubeRightViewport);
surface->SetUpdateMode(SURFACE_UPDATEALWAYS);
surface = cubeRenderTex_->GetRenderSurface(CubeMapFace::FACE_POSITIVE_Y);
SharedPtr<Viewport> cubeTopViewport(new Viewport(context, scene, topCubeCamera));
surface->SetViewport(0, cubeTopViewport);
surface->SetUpdateMode(SURFACE_UPDATEALWAYS);
surface = cubeRenderTex_->GetRenderSurface(CubeMapFace::FACE_NEGATIVE_Y);
SharedPtr<Viewport> cubeBottomViewport(new Viewport(context, scene, bottomCubeCamera));
surface->SetViewport(0, cubeBottomViewport);
surface->SetUpdateMode(SURFACE_UPDATEALWAYS);
SharedPtr<RenderPath> cubeRenderPath = cubeFrontViewport->GetRenderPath()->Clone();
cubeRenderPath->Append(cache->GetResource<XMLFile>("PostProcess/FXAA3.xml"));
cubeRenderPath->SetEnabled("FXAA3", true);
// Use RenderPath with FXAA3 enabled
cubeFrontViewport->SetRenderPath(cubeRenderPath);
cubeLeftViewport->SetRenderPath(cubeRenderPath);
cubeRightViewport->SetRenderPath(cubeRenderPath);
cubeTopViewport->SetRenderPath(cubeRenderPath);
cubeBottomViewport->SetRenderPath(cubeRenderPath);
// Render result image to single Texture2D
RenderPathCommand rrpc;
rrpc.type_ = CMD_QUAD;
rrpc.tag_ = "FisheyeCube";
rrpc.vertexShaderName_ = "FisheyeCube";
rrpc.pixelShaderName_ = "FisheyeCube";
rrpc.SetOutput(0, "viewport");
rrpc.SetTextureName(TU_DIFFUSE, name + "CubeTex");
RenderPath * rrp = new RenderPath();
rrp->AddCommand(rrpc);
cubeViewport_ = new Viewport(context_, scene_, frontCubeCameraNode_->GetComponent<Camera>(), rrp);
cubeResultRenderTex_ = new Texture2D(context_);
cubeResultRenderTex_->SetSize(CAM_W, CAM_H, Graphics::GetRGBAFormat(), TEXTURE_RENDERTARGET);
surface = cubeResultRenderTex_->GetRenderSurface();
surface->SetViewport(0, cubeViewport_);
surface->SetUpdateMode(SURFACE_UPDATEALWAYS);
}
Texture2D * CubeCamera::GetOutputTexture()
{
return cubeResultRenderTex_;
}
FisheyeCube.hlsl
#include "Uniforms.hlsl"
#include "Samplers.hlsl"
#include "Transform.hlsl"
#include "ScreenPos.hlsl"
#include "Lighting.hlsl"
#define M_PI 3.141592654
void VS(float4 iPos : POSITION,
out float2 oScreenPos : TEXCOORD0,
out float4 oPos : OUTPOSITION)
{
float4x3 modelMatrix = iModelMatrix;
float3 worldPos = GetWorldPos(modelMatrix);
oPos = GetClipPos(worldPos);
oScreenPos = GetScreenPosPreDiv(oPos);
}
void PS(float2 iScreenPos : TEXCOORD0,
out float4 oColor : OUTCOLOR0)
{
float Z = -2.0*iScreenPos.x + 1.0;
float Y = -2.0*iScreenPos.y + 1.0;
float X = 0.85 * sqrt(1.0 - Y*Y - Z*Z); //Manipulate coeffitient to get different "zoom"
X = X*X; //Manipulate power to get different "zoom progression"
float3 vec = { X, Y, Z };
float3 color;
if (sqrt(Z*Z + Y*Y)<=1.0)
{
oColor = float4(SampleCube(DiffCubeMap, vec).rgb, 1.0);
}
else
{
oColor = float4(0.0, 0.0, 0.0, 0.0);
}
}
Everything works, so far so good. Only issue I have with this is that it is quite demanding on the processing power, as there are many independent viewports that must be rendered. I would like to know wheter there are some ways to optimize the process. I get a huge rise in steps like ExecuteRenderPaths, RenderScenePass, an I would like to know wheter some of these steps could be combined to save time. Especially when the 5 views are sampled from the same point and are only rotated. I tried something to set multiple outputs in RenderCommands but without success. I’d like to know if there is principally anything I could do to improve efficiency.
Thanks for ideas!