BGE: stereoscopic settings changes: (1) eye separation is the UI (2) focallength uses camera focallength

Now the default eye separation value is 0.10 (reasonable for games with 1 meter == 1 B.U.
The focallength used is the camera focal length (DOF settings). It allow you to even use different focal lengths for different scenes (good for UI)

In order to change it you can change the camera focal length or use Rasterizer.setFocalLength.
If you use the Rasterizer method it will use this value for all the cameras.

ToDo:
- Blenderplayer settings
- Update wiki documentation (any volunteer)?

* Note to stereo fans:
I don't have a real stereo environment to test it (other than cheap cyan-red glasses). If you can give it a try in a more robust system and report bugs or problems with BGE current system please let me know. I would be glad to help to make it work 100% by the time Blender 2.5 is out.

For the record, BGE is using the method known as 'parallel axis asymmetric frustum perspective projection'. This method is well documented here:
http://local.wasp.uwa.edu.au/~pbourke/miscellaneous/stereographics/stereorender/
This commit is contained in:
Dalai Felinto 2009-12-29 15:47:20 +00:00
parent 1cfb5ffb5d
commit e37e3845a1
10 changed files with 33 additions and 19 deletions

@ -274,8 +274,7 @@ class RENDER_PT_game_stereo(RenderButtonsPanel):
# stereo: # stereo:
if stereo_mode == 'STEREO': if stereo_mode == 'STEREO':
layout.prop(gs, "stereo_mode") layout.prop(gs, "stereo_mode")
# layout.label(text="To do: Focal Length") # to be done after 2.5alpha0 is out layout.prop(gs, "eye_separation")
# layout.label(text="To do: Eye Separation") # to be done after 2.5alpha0 is out
# dome: # dome:
elif stereo_mode == 'DOME': elif stereo_mode == 'DOME':

@ -450,6 +450,8 @@ Scene *add_scene(char *name)
/* game data */ /* game data */
sce->gm.stereoflag = STEREO_NOSTEREO; sce->gm.stereoflag = STEREO_NOSTEREO;
sce->gm.stereomode = STEREO_ANAGLYPH; sce->gm.stereomode = STEREO_ANAGLYPH;
sce->gm.eyeseparation = 0.10;
sce->gm.dome.angle = 180; sce->gm.dome.angle = 180;
sce->gm.dome.mode = DOME_FISHEYE; sce->gm.dome.mode = DOME_FISHEYE;
sce->gm.dome.res = 4; sce->gm.dome.res = 4;

@ -10304,6 +10304,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* put 2.50 compatibility code here until next subversion bump */ /* put 2.50 compatibility code here until next subversion bump */
if (1) {
Scene *sce;
for(sce = main->scene.first; sce; sce = sce->id.next) {
sce->gm.eyeseparation = 0.10;
}
}
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */ /* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */ /* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */

@ -444,6 +444,7 @@ typedef struct GameData {
/* stereo/dome mode */ /* stereo/dome mode */
struct GameDome dome; struct GameDome dome;
short stereoflag, stereomode, xsch, ysch; //xsch and ysch can be deleted !!! short stereoflag, stereomode, xsch, ysch; //xsch and ysch can be deleted !!!
float eyeseparation, pad1;
} GameData; } GameData;
#define STEREO_NOSTEREO 1 #define STEREO_NOSTEREO 1

@ -1215,6 +1215,12 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stereo Mode", "Stereographic techniques"); RNA_def_property_ui_text(prop, "Stereo Mode", "Stereographic techniques");
RNA_def_property_update(prop, NC_SCENE, NULL); RNA_def_property_update(prop, NC_SCENE, NULL);
prop= RNA_def_property(srna, "eye_separation", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "eyeseparation");
RNA_def_property_range(prop, 0.01, 5.0);
RNA_def_property_ui_text(prop, "Eye Separation", "Set the distance between the eyes");
RNA_def_property_update(prop, NC_SCENE, NULL);
/* Dome */ /* Dome */
prop= RNA_def_property(srna, "dome_mode", PROP_ENUM, PROP_NONE); prop= RNA_def_property(srna, "dome_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "dome.mode"); RNA_def_property_enum_sdna(prop, NULL, "dome.mode");

@ -342,6 +342,8 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
if(blscene->gm.stereoflag == STEREO_ENABLED){ if(blscene->gm.stereoflag == STEREO_ENABLED){
if (blscene->gm.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) if (blscene->gm.stereomode != RAS_IRasterizer::RAS_STEREO_QUADBUFFERED)
rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->gm.stereomode); rasterizer->SetStereoMode((RAS_IRasterizer::StereoMode) blscene->gm.stereomode);
rasterizer->SetEyeSeparation(blscene->gm.eyeseparation);
} }
rasterizer->SetBackColor(blscene->gm.framing.col[0], blscene->gm.framing.col[1], blscene->gm.framing.col[2], 0.0f); rasterizer->SetBackColor(blscene->gm.framing.col[0], blscene->gm.framing.col[1], blscene->gm.framing.col[2], 0.0f);

@ -1658,7 +1658,7 @@ static KX_LightObject *gamelight_from_blamp(Object *ob, Lamp *la, unsigned int l
static KX_Camera *gamecamera_from_bcamera(Object *ob, KX_Scene *kxscene, KX_BlenderSceneConverter *converter) { static KX_Camera *gamecamera_from_bcamera(Object *ob, KX_Scene *kxscene, KX_BlenderSceneConverter *converter) {
Camera* ca = static_cast<Camera*>(ob->data); Camera* ca = static_cast<Camera*>(ob->data);
RAS_CameraData camdata(ca->lens, ca->ortho_scale, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, dof_camera(ob)); RAS_CameraData camdata(ca->lens, ca->ortho_scale, ca->clipsta, ca->clipend, ca->type == CAM_PERSP, ca->YF_dofdist);
KX_Camera *gamecamera; KX_Camera *gamecamera;
gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata); gamecamera= new KX_Camera(kxscene, KX_Scene::m_callbacks, camdata);

@ -44,19 +44,19 @@ struct RAS_CameraData
float m_focallength; float m_focallength;
RAS_CameraData(float lens = 35.0, float scale = 6.0, float clipstart = 0.1, float clipend = 5000.0, bool perspective = true, RAS_CameraData(float lens = 35.0, float scale = 6.0, float clipstart = 0.1, float clipend = 5000.0, bool perspective = true,
float focallength = 0.0f, bool viewport = false, int viewportleft = 0, int viewportbottom = 0, float focallength = 3.0, bool viewport = false, int viewportleft = 0, int viewportbottom = 0,
int viewportright = 0, int viewporttop = 0) : int viewportright = 0, int viewporttop = 0) :
m_lens(lens), m_lens(lens),
m_scale(scale), m_scale(scale),
m_clipstart(clipstart), m_clipstart(clipstart),
m_clipend(clipend), m_clipend(clipend),
m_perspective(perspective), m_perspective(perspective),
m_focallength(focallength),
m_viewport(viewport), m_viewport(viewport),
m_viewportleft(viewportleft), m_viewportleft(viewportleft),
m_viewportbottom(viewportbottom), m_viewportbottom(viewportbottom),
m_viewportright(viewportright), m_viewportright(viewportright),
m_viewporttop(viewporttop), m_viewporttop(viewporttop)
m_focallength(focallength)
{ {
} }
}; };

@ -73,7 +73,6 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas)
m_stereomode(RAS_STEREO_NOSTEREO), m_stereomode(RAS_STEREO_NOSTEREO),
m_curreye(RAS_STEREO_LEFTEYE), m_curreye(RAS_STEREO_LEFTEYE),
m_eyeseparation(0.0), m_eyeseparation(0.0),
m_seteyesep(false),
m_focallength(0.0), m_focallength(0.0),
m_setfocallength(false), m_setfocallength(false),
m_noOfScanlines(32), m_noOfScanlines(32),
@ -518,7 +517,6 @@ RAS_IRasterizer::StereoEye RAS_OpenGLRasterizer::GetEye()
void RAS_OpenGLRasterizer::SetEyeSeparation(const float eyeseparation) void RAS_OpenGLRasterizer::SetEyeSeparation(const float eyeseparation)
{ {
m_eyeseparation = eyeseparation; m_eyeseparation = eyeseparation;
m_seteyesep = true;
} }
float RAS_OpenGLRasterizer::GetEyeSeparation() float RAS_OpenGLRasterizer::GetEyeSeparation()
@ -902,26 +900,26 @@ MT_Matrix4x4 RAS_OpenGLRasterizer::GetFrustumMatrix(
if(Stereo()) if(Stereo())
{ {
float near_div_focallength; float near_div_focallength;
// next 2 params should be specified on command line and in Blender publisher float offset;
// if Rasterizer.setFocalLength is not called we use the camera focallength
if (!m_setfocallength) if (!m_setfocallength)
m_focallength = (focallength == 0.f) ? 1.5 * right // derived from example m_focallength = focallength;
: focallength;
if (!m_seteyesep)
m_eyeseparation = m_focallength/30; // reasonable value...
near_div_focallength = frustnear / m_focallength; near_div_focallength = frustnear / m_focallength;
offset = 0.5 * m_eyeseparation * near_div_focallength;
switch(m_curreye) switch(m_curreye)
{ {
case RAS_STEREO_LEFTEYE: case RAS_STEREO_LEFTEYE:
left += 0.5 * m_eyeseparation * near_div_focallength; left += offset;
right += 0.5 * m_eyeseparation * near_div_focallength; right += offset;
break; break;
case RAS_STEREO_RIGHTEYE: case RAS_STEREO_RIGHTEYE:
left -= 0.5 * m_eyeseparation * near_div_focallength; left -= offset;
right -= 0.5 * m_eyeseparation * near_div_focallength; right -= offset;
break; break;
} }
// leave bottom, top, bottom and top untouched // leave bottom and top untouched
} }
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);

@ -85,7 +85,6 @@ class RAS_OpenGLRasterizer : public RAS_IRasterizer
StereoMode m_stereomode; StereoMode m_stereomode;
StereoEye m_curreye; StereoEye m_curreye;
float m_eyeseparation; float m_eyeseparation;
bool m_seteyesep;
float m_focallength; float m_focallength;
bool m_setfocallength; bool m_setfocallength;
int m_noOfScanlines; int m_noOfScanlines;