Patch #18462: Fisheye (Dome) and Spherical Panoramic mode in BGE.

User guide:
http://wiki.blender.org/index.php/Dev:Source/GameEngine/Fisheye_Dome_Camera

Fixed two bugs from original patch:
- deleting a text will clear the warp field from Game framing settings
- removed spurious black dots along the edge of the cube map in the gameplayer 

Known limitation:
- resizing of the screen doesn't work in the gameplayer

Known bugs:
- Texture with reflexion are not rendered correctly
- Spurious problems with light
This commit is contained in:
Benoit Bolsee 2009-04-08 15:06:20 +00:00
parent 4b77f9504c
commit 2074128fad
16 changed files with 2227 additions and 9 deletions

@ -513,6 +513,10 @@
RelativePath="..\..\..\source\gameengine\Ketsji\KX_ConvertPhysicsObjects.cpp"
>
</File>
<File
RelativePath="..\..\..\source\gameengine\Ketsji\KX_Dome.cpp"
>
</File>
<File
RelativePath="..\..\..\source\gameengine\Ketsji\KX_EmptyObject.cpp"
>
@ -802,6 +806,10 @@
RelativePath="..\..\..\source\gameengine\Ketsji\KX_ConvertPhysicsObject.h"
>
</File>
<File
RelativePath="..\..\..\source\gameengine\Ketsji\KX_Dome.h"
>
</File>
<File
RelativePath="..\..\..\source\gameengine\Ketsji\KX_EmptyObject.h"
>

@ -41,7 +41,7 @@ struct ListBase;
struct MemFile;
#define BLENDER_VERSION 248
#define BLENDER_SUBVERSION 3
#define BLENDER_SUBVERSION 4
#define BLENDER_MINVERSION 245
#define BLENDER_MINSUBVERSION 15

@ -86,5 +86,7 @@ int get_render_child_particle_number(struct RenderData *r, int num);
int get_render_shadow_samples(struct RenderData *r, int samples);
float get_render_aosss_error(struct RenderData *r, float error);
void free_dome_warp_text(struct Text *txt);
#endif

@ -230,6 +230,11 @@ Scene *add_scene(char *name)
sce->r.threads= 1;
sce->r.stereomode = 1; // no stereo
sce->r.domeangle = 180;
sce->r.domemode = 1;
sce->r.domesize = 1.0f;
sce->r.domeres = 4;
sce->r.domeresbuf = 1.0f;
sce->r.simplify_subsurf= 6;
sce->r.simplify_particles= 1.0f;
@ -775,3 +780,14 @@ float get_render_aosss_error(RenderData *r, float error)
return error;
}
void free_dome_warp_text(struct Text *txt)
{
Scene *scene;
scene = G.main->scene.first;
while(scene) {
if (scene->r.dometext == txt)
scene->r.dometext = NULL;
scene = scene->id.next;
}
}

@ -3531,7 +3531,9 @@ static void lib_link_scene(FileData *fd, Main *main)
srl->mat_override= newlibadr_us(fd, sce->id.lib, srl->mat_override);
srl->light_override= newlibadr_us(fd, sce->id.lib, srl->light_override);
}
/*Game Settings: Dome Warp Text*/
sce->r.dometext= newlibadr_us(fd, sce->id.lib, sce->r.dometext);
sce->id.flag -= LIB_NEEDLINK;
}
@ -8035,6 +8037,24 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
if (main->versionfile < 248 || (main->versionfile == 248 && main->subversionfile < 4)) {
Scene *sce;
World *wrld;
/* Dome (Fisheye) default parameters */
for (sce= main->scene.first; sce; sce= sce->id.next) {
sce->r.domeangle = 180;
sce->r.domemode = 1;
sce->r.domesize = 1.0f;
sce->r.domeres = 4;
sce->r.domeresbuf = 1.0f;
}
/* DBVT culling by default */
for(wrld=main->world.first; wrld; wrld= wrld->id.next) {
wrld->mode |= WO_DBVT_CAMERA_CULLING;
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */
@ -8841,7 +8861,9 @@ static void expand_scene(FileData *fd, Main *mainvar, Scene *sce)
expand_doit(fd, mainvar, srl->mat_override);
expand_doit(fd, mainvar, srl->light_override);
}
if(sce->r.dometext)
expand_doit(fd, mainvar, sce->r.dometext);
}
static void expand_camera(FileData *fd, Main *mainvar, Camera *ca)

@ -45,6 +45,7 @@ struct World;
struct Scene;
struct Image;
struct Group;
struct Text;
struct bNodeTree;
typedef struct Base {
@ -314,6 +315,14 @@ typedef struct RenderData {
/* jpeg2000 */
short jp2_preset, jp2_depth;
int rpad3;
/* Dome variables */
short domeres, domemode;
short domeangle, pad9;
float domesize;
float domeresbuf;
struct Text *dometext;
} RenderData;
/* control render convert and shading engine */

@ -1766,13 +1766,13 @@ static uiBlock *edge_render_menu(void *arg_unused)
static uiBlock *framing_render_menu(void *arg_unused)
{
uiBlock *block;
short yco = 190, xco = 0;
short yco = 267, xco = 0;
int randomcolorindex = 1234;
block= uiNewBlock(&curarea->uiblocks, "framing_options", UI_EMBOSS, UI_HELV, curarea->win);
/* use this for a fake extra empy space around the buttons */
uiDefBut(block, LABEL, 0, "", -5, -10, 295, 224, NULL, 0, 0, 0, 0, "");
uiDefBut(block, LABEL, 0, "", -5, -10, 295, 300, NULL, 0, 0, 0, 0, "");
uiDefBut(block, LABEL, 0, "Framing:", xco, yco, 68,19, 0, 0, 0, 0, 0, "");
uiBlockBeginAlign(block);
@ -1814,6 +1814,7 @@ static uiBlock *framing_render_menu(void *arg_unused)
* RAS_STEREO_ANAGLYPH 5
* RAS_STEREO_SIDEBYSIDE 6
* RAS_STEREO_VINTERLACE 7
* RAS_STEREO_DOME 8
*/
uiBlockBeginAlign(block);
uiDefButS(block, ROW, 0, "No Stereo", xco, yco-=30, 88, 19, &(G.scene->r.stereomode), 7.0, 1.0, 0, 0, "Disables stereo");
@ -1825,6 +1826,18 @@ static uiBlock *framing_render_menu(void *arg_unused)
uiBlockEndAlign(block);
uiBlockBeginAlign(block);
uiDefButS(block, ROW, 0, "Dome", xco-=180, yco-=30, 88, 19, &(G.scene->r.stereomode), 7.0, 8.0, 0, 0, "Enables dome camera");
uiDefButS(block, NUM, 0, "Ang:", xco+=90, yco, 88, 19, &G.scene->r.domeangle, 90.0, 250.0, 0, 0, "Angle (Aperture) of the Dome - it only works in mode 1");
uiDefButS(block, NUM, 0, "Mode:", xco+=90, yco, 88, 19, &G.scene->r.domemode, 1.0, 3.0, 0, 0, "Dome mode - 1 fisheye, 2 truncated, 3 spherical panoramic");
uiDefButF(block, NUM, 0, "Size:", xco-=180, yco-=21, 88, 19, &G.scene->r.domesize, 0.5, 3.5, 0, 0, "Size adjustments");
uiDefButS(block, NUM, 0, "Tes:", xco+=90, yco, 88, 19, &G.scene->r.domeres, 1.0, 8.0, 0, 0, "Tesselation level - 1 to 8");
uiDefButF(block, NUM, 0, "Res:", xco+=90, yco, 88, 19, &G.scene->r.domeresbuf, 0.1, 1.0, 0, 0, "Buffer Resolution - decrease it to increase speed");
uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "Warp Data: ", xco-180,yco-=21,268, 19, &G.scene->r.dometext, "Custom Warp Mesh data file");
uiBlockEndAlign(block);
uiBlockSetDirection(block, UI_TOP);
return block;

@ -173,6 +173,7 @@ void do_text_buttons(unsigned short event)
BPY_clear_bad_scriptlinks(text);
BPY_free_pyconstraint_links(text);
free_text_controllers(text);
free_dome_warp_text(text);
#endif
unlink_text(text);
free_libblock(&G.main->text, text);

@ -373,6 +373,10 @@ extern "C" void StartKetsjiShell(struct ScrArea *area,
initVideoTexture();
#endif
//initialize Dome Settings
if(blscene->r.stereomode == RAS_IRasterizer::RAS_STEREO_DOME)
ketsjiengine->InitDome(blscene->r.domesize, blscene->r.domeres, blscene->r.domemode, blscene->r.domeangle, blscene->r.domeresbuf, blscene->r.dometext);
if (sceneconverter)
{
// convert and add scene

@ -693,6 +693,11 @@ bool GPG_Application::startEngine(void)
#ifdef WITH_FFMPEG
initVideoTexture();
#endif
//initialize Dome Settings
if(m_startScene->r.stereomode == RAS_IRasterizer::RAS_STEREO_DOME)
m_ketsjiengine->InitDome(m_startScene->r.domesize, m_startScene->r.domeres, m_startScene->r.domemode, m_startScene->r.domeangle, m_startScene->r.domeresbuf, m_startScene->r.dometext);
// Set the GameLogic.globalDict from marshal'd data, so we can
// load new blend files and keep data in GameLogic.globalDict
loadGamePythonConfig(m_pyGlobalDictString, m_pyGlobalDictString_Length);

File diff suppressed because it is too large Load Diff

@ -0,0 +1,183 @@
/* $Id$
-----------------------------------------------------------------------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.
Contributor(s): Dalai Felinto
This source uses some of the ideas and code from Paul Bourke.
Developed as part of a Research and Development project for SAT - La Société des arts technologiques.
-----------------------------------------------------------------------------
*/
#if !defined KX_DOME_H
#define KX_DOME_H
#include "KX_Scene.h"
#include "KX_Camera.h"
#include "DNA_screen_types.h"
#include "RAS_ICanvas.h"
#include "RAS_IRasterizer.h"
#include "RAS_IRenderTools.h"
#include "KX_KetsjiEngine.h"
#include <BIF_gl.h>
#include <vector>
#include "MEM_guardedalloc.h"
#include "BKE_text.h"
//#include "BLI_blenlib.h"
//Dome modes: limit hardcoded in buttons_scene.c
#define DOME_FISHEYE 1
#define DOME_TRUNCATED 2
#define DOME_PANORAM_SPH 3
#define DOME_NUM_MODES 4
/// class for render 3d scene
class KX_Dome
{
public:
/// constructor
KX_Dome (
RAS_ICanvas* m_canvas,
/// rasterizer
RAS_IRasterizer* m_rasterizer,
/// render tools
RAS_IRenderTools* m_rendertools,
/// engine
KX_KetsjiEngine* m_engine,
float size,
short res,
short mode,
short angle,
float resbuf,
struct Text* warptext
);
/// destructor
virtual ~KX_Dome (void);
//openGL checks:
bool dlistSupported;
//openGL names:
GLuint domefacesId[7]; // ID of the images -- room for 7 images, using only 4 for 180º x 360º dome, 6 for panoramic and +1 for warp mesh
GLuint dlistId; // ID of the Display Lists of the images (used as an offset)
typedef struct {
double u[3], v[3];
MT_Vector3 verts[3]; //three verts
} DomeFace;
//mesh warp functions
typedef struct {
double x, y, u, v, i;
} WarpMeshNode;
struct {
bool usemesh;
int mode;
int n_width, n_height; //nodes width and height
int imagewidth, imageheight;
int bufferwidth, bufferheight;
vector <vector <WarpMeshNode> > nodes;
} warp;
bool ParseWarpMesh(STR_String text);
vector <DomeFace> cubetop, cubebottom, cuberight, cubeleft, cubefront, cubeback; //for fisheye
vector <DomeFace> cubeleftback, cuberightback; //for panorama
int nfacestop, nfacesbottom, nfacesleft, nfacesright, nfacesfront, nfacesback;
int nfacesleftback, nfacesrightback;
int GetNumberRenders(){return m_numfaces;};
void RenderDome(void);
void RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i);
void BindImages(int i);
void SetViewPort(GLuint viewport[4]);
void CalculateFrustum(KX_Camera* cam);
void RotateCamera(KX_Camera* cam, int i);
//Mesh Creating Functions
void CreateMeshDome180(void);
void CreateMeshDome250(void);
void CreateMeshPanorama(void);
void SplitFace(vector <DomeFace>& face, int *nfaces);
void FlattenDome(MT_Vector3 verts[3]);
void FlattenPanorama(MT_Vector3 verts[3]);
//Draw functions
void GLDrawTriangles(vector <DomeFace>& face, int nfaces);
void GLDrawWarpQuads(void);
void Draw(void);
void DrawDomeFisheye(void);
void DrawPanorama(void);
void DrawDomeWarped(void);
//setting up openGL
void CreateGLImages(void);
void ClearGLImages(void);//called on resize
bool CreateDL(void); //create Display Lists
void ClearDL(void); //remove Display Lists
void CalculateCameraOrientation();
void CalculateImageSize(); //set m_imagesize
int canvaswidth;
int canvasheight;
protected:
int m_drawingmode;
int m_imagesize;
int m_buffersize; // canvas small dimension
int m_numfaces; // 4 to 6 depending on the kind of dome image
int m_numimages; //numfaces +1 if we have warp mesh
float m_size; // size to adjust
short m_resolution; //resolution to tesselate the mesh
short m_mode; // the mode (truncated, warped, panoramic,...)
short m_angle; //the angle of the fisheye
float m_radangle; //the angle of the fisheye in radians
float m_resbuffer; //the resolution of the buffer
RAS_Rect m_viewport;
MT_Matrix4x4 m_projmat;
MT_Matrix3x3 m_locRot [6];// the rotation matrix
/// rendered scene
KX_Scene * m_scene;
/// canvas
RAS_ICanvas* m_canvas;
/// rasterizer
RAS_IRasterizer* m_rasterizer;
/// render tools
RAS_IRenderTools* m_rendertools;
/// engine
KX_KetsjiEngine* m_engine;
};
#endif

@ -55,6 +55,7 @@
#include "KX_Scene.h"
#include "MT_CmMatrix4x4.h"
#include "KX_Camera.h"
#include "KX_Dome.h"
#include "KX_Light.h"
#include "KX_PythonInit.h"
#include "KX_PyConstraintBinding.h"
@ -144,6 +145,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_stereo(false),
m_curreye(0),
m_usedome(false),
m_logger(NULL),
// Set up timing info display variables
@ -179,6 +182,8 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
KX_KetsjiEngine::~KX_KetsjiEngine()
{
delete m_logger;
if(m_usedome)
delete m_dome;
}
@ -256,7 +261,124 @@ void KX_KetsjiEngine::SetSceneConverter(KX_ISceneConverter* sceneconverter)
m_sceneconverter = sceneconverter;
}
void KX_KetsjiEngine::InitDome(float size, short res, short mode, short angle, float resbuf, struct Text* text)
{
m_dome = new KX_Dome(m_canvas, m_rasterizer, m_rendertools,this, size, res, mode, angle, resbuf, text);
m_usedome = true;
}
void KX_KetsjiEngine::RenderDome()
{
GLuint viewport[4]={0};
glGetIntegerv(GL_VIEWPORT,(GLint *)viewport);
// unsigned int m_viewport[4] = {viewport[0], viewport[1], viewport[2], viewport[3]};
m_dome->SetViewPort(viewport);
KX_Scene* firstscene = *m_scenes.begin();
const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
// hiding mouse cursor each frame
// (came back when going out of focus and then back in again)
if (m_hideCursor)
m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
// clear the entire game screen with the border color
// only once per frame
m_canvas->BeginDraw();
// BeginFrame() sets the actual drawing area. You can use a part of the window
if (!BeginFrame())
return;
int n_renders=m_dome->GetNumberRenders();// usually 4 or 6
KX_SceneList::iterator sceneit;
for (int i=0;i<n_renders;i++){
m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER);
for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); sceneit++)
// for each scene, call the proceed functions
{
KX_Scene* scene = *sceneit;
KX_Camera* cam = scene->GetActiveCamera();
m_rendertools->BeginFrame(m_rasterizer);
// pass the scene's worldsettings to the rasterizer
SetWorldSettings(scene->GetWorldInfo());
// shadow buffers
if (i == 0){
RenderShadowBuffers(scene);
scene->UpdateMeshTransformations();//I need to run it somewherelse, otherwise Im overrunning it
}
// Avoid drawing the scene with the active camera twice when it's viewport is enabled
if(cam && !cam->GetViewport())
{
if (scene->IsClearingZBuffer())
m_rasterizer->ClearDepthBuffer();
m_rendertools->SetAuxilaryClientInfo(scene);
// do the rendering
m_dome->RenderDomeFrame(scene,cam, i);
}
list<class KX_Camera*>* cameras = scene->GetCameras();
// Draw the scene once for each camera with an enabled viewport
list<KX_Camera*>::iterator it = cameras->begin();
while(it != cameras->end())
{
if((*it)->GetViewport())
{
if (scene->IsClearingZBuffer())
m_rasterizer->ClearDepthBuffer();
m_rendertools->SetAuxilaryClientInfo(scene);
// do the rendering
m_dome->RenderDomeFrame(scene, (*it),i);
}
it++;
}
}
m_dome->BindImages(i);
}
// m_dome->Dome_PostRender(scene, cam, stereomode);
m_canvas->EndFrame();//XXX do we really need that?
m_canvas->SetViewPort(0, 0, m_canvas->GetWidth(), m_canvas->GetHeight());
if (m_overrideFrameColor) //XXX why do we want
{
// Do not use the framing bar color set in the Blender scenes
m_canvas->ClearColor(
m_overrideFrameColorR,
m_overrideFrameColorG,
m_overrideFrameColorB,
1.0
);
}
else
{
// Use the framing bar color set in the Blender scenes
m_canvas->ClearColor(
framesettings.BarRed(),
framesettings.BarGreen(),
framesettings.BarBlue(),
1.0
);
}
m_dome->Draw();
//run 2dfilters
EndFrame();
}
/**
* Ketsji Init(), Initializes datastructures and converts data from
@ -631,6 +753,10 @@ else
void KX_KetsjiEngine::Render()
{
if(m_usedome){
RenderDome();
return;
}
KX_Scene* firstscene = *m_scenes.begin();
const RAS_FrameSettings &framesettings = firstscene->GetFramingType();
@ -1699,4 +1825,3 @@ void KX_KetsjiEngine::GetOverrideFrameColor(float& r, float& g, float& b) const
}

@ -74,6 +74,7 @@ private:
PyObject* m_pythondictionary;
class SCA_IInputDevice* m_keyboarddevice;
class SCA_IInputDevice* m_mousedevice;
class KX_Dome* m_dome; // dome stereo mode
/** Lists of scenes scheduled to be removed at the end of the frame. */
std::set<STR_String> m_removingScenes;
@ -208,6 +209,12 @@ public:
RAS_ICanvas* GetCanvas(){return m_canvas;};
RAS_IRenderTools* GetRenderTools(){return m_rendertools;};
/// Dome functions
void InitDome(float size, short res, short mode, short angle, float resbuf, struct Text* text);
void EndDome();
void RenderDome();
bool m_usedome;
///returns true if an update happened to indicate -> Render
bool NextFrame();
void Render();
@ -234,6 +241,8 @@ public:
void GetSceneViewport(KX_Scene* scene, KX_Camera* cam, RAS_Rect& area, RAS_Rect& viewport);
void SetDrawType(int drawingtype);
int GetDrawType(){return m_drawingmode;};
void SetCameraZoom(float camzoom);
void EnableCameraOverride(const STR_String& forscene);

@ -113,6 +113,7 @@ public:
RAS_STEREO_ANAGLYPH,
RAS_STEREO_SIDEBYSIDE,
RAS_STEREO_VINTERLACE,
RAS_STEREO_DOME,
RAS_STEREO_MAXSTEREO
};

@ -436,7 +436,7 @@ RAS_IRasterizer::StereoMode RAS_OpenGLRasterizer::GetStereoMode()
bool RAS_OpenGLRasterizer::Stereo()
{
if(m_stereomode == RAS_STEREO_NOSTEREO)
if(m_stereomode == RAS_STEREO_NOSTEREO || m_stereomode == RAS_STEREO_DOME)
return false;
else
return true;
@ -803,7 +803,7 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix(
double mat[16];
// correction for stereo
if(m_stereomode != RAS_STEREO_NOSTEREO)
if(Stereo())
{
float near_div_focallength;
// next 2 params should be specified on command line and in Blender publisher
@ -846,7 +846,7 @@ void RAS_OpenGLRasterizer::SetViewMatrix(const MT_Matrix4x4 &mat, const MT_Vecto
m_viewmatrix = mat;
// correction for stereo
if(m_stereomode != RAS_STEREO_NOSTEREO)
if(Stereo())
{
MT_Matrix3x3 camOrientMat3x3(camOrientQuat);
MT_Vector3 unitViewDir(0.0, -1.0, 0.0); // minus y direction, Blender convention