cleaned up stereo/high-FOV projections

This commit is contained in:
Zeno Rogue 2023-11-30 12:32:24 +01:00
parent 2add515fbf
commit 34d3d67ace
8 changed files with 69 additions and 80 deletions

View File

@ -1345,11 +1345,13 @@ EX void initConfig() {
addsaver(vid.desaturate, "desaturate", 0);
param_enum(vid.stereo_mode, "stereo_mode", "stereo-mode", vid.stereo_mode)
->editable({{"OFF", ""}, {"anaglyph", ""}, {"side-by-side", ""}
#if CAP_ODS
, {"ODS", ""}
#endif
}, "stereo mode", 'm');
->editable({
{"OFF", "linear perspective"}, {"anaglyph", "for red-cyan glasses"}, {"side-by-side", "for mobile VR"},
{"ODS", "for rendering 360° VR videos (implemented only in raycaster and some other parts)"},
{"Panini", "Projection believed to be used by Italian painters. Allows very high FOV angles while rendering more straight lines as straight than the stereographic projection."},
{"stereographic", "Stereographic projection allows very high FOV angles."},
{"equirectangular", "for rendering 360° videos (implemented only in raycaster)"}
}, "stereo/high-FOV mode", 'm');
param_f(vid.plevel_factor, "plevel_factor", 0.7);
@ -1577,11 +1579,12 @@ EX void initConfig() {
param_f(camera_rot_speed, "camrot", "camera-rot-speed", 1);
param_f(third_person_rotation, "third_person_rotation", 0);
param_f(panini_alpha, "panini_alpha", 0)
param_f(vid.stereo_param, "stereo_param", 0.9)
->editable(-1, 1, 0.9, "stereographic/Panini parameter", "1 for full stereographic/Panini projection. Lower values reduce the effect.\n\n"
"HyperRogue uses "
"a quick implementation, so parameter values too close to 1 may "
"be buggy (outside of raycasting); try e.g. 0.9 instead.", 'd')
->set_reaction(reset_all_shaders);
param_f(stereo_alpha, "stereo_alpha", 0)
->set_reaction(reset_all_shaders);
param_b(equirectangular, "equirectangular");
callhooks(hooks_configfile);
@ -2473,7 +2476,7 @@ EX void explain_detail() {
}
EX ld max_fov_angle() {
auto& p = panini_alpha ? panini_alpha : stereo_alpha;
auto p = get_stereo_param();
if(p >= 1 || p <= -1) return 360;
return acos(-p) * 2 / degree;
}
@ -2481,7 +2484,7 @@ EX ld max_fov_angle() {
EX void add_edit_fov(char key IS('f')) {
string sfov = fts(vid.fov) + "°";
if(panini_alpha || stereo_alpha) {
if(get_stereo_param()) {
sfov += " / " + fts(max_fov_angle()) + "°";
}
dialog::addSelItem(XLAT("field of view"), sfov, key);
@ -2498,37 +2501,11 @@ EX void add_edit_fov(char key IS('f')) {
);
dialog::bound_low(1e-8);
dialog::bound_up(max_fov_angle() - 0.01);
string quick =
XLAT(
"HyperRogue uses "
"a quick implementation, so parameter values too close to 1 may "
"be buggy (outside of raycasting); try e.g. 0.9 instead."
);
dialog::get_di().extra_options = [quick] {
dialog::addSelItem(XLAT("Panini projection"), fts(panini_alpha), 'P');
dialog::add_action([quick] {
dialog::editNumber(panini_alpha, 0, 1, 0.1, 0, "Panini parameter",
XLAT(
"The Panini projection is an alternative perspective projection "
"which allows very wide field-of-view values.\n\n") + quick
);
#if CAP_GL
dialog::get_di().reaction = reset_all_shaders;
#endif
dialog::get_di().extra_options = [] { add_edit_fov('F'); };
});
dialog::addSelItem(XLAT("spherical perspective projection"), fts(stereo_alpha), 'S');
dialog::add_action([quick] {
dialog::editNumber(stereo_alpha, 0, 1, 0.1, 0, "spherical perspective parameter",
XLAT(
"Set to 1 to get stereographic projection, "
"which allows very wide field-of-view values.\n\n") + quick
);
#if CAP_GL
dialog::get_di().reaction = reset_all_shaders;
#endif
dialog::get_di().extra_options = [] { add_edit_fov('F'); };
});
dialog::get_di().extra_options = [] {
add_edit(vid.stereo_mode, 'M');
if(among(vid.stereo_mode, sPanini, sStereographic)) {
add_edit(vid.stereo_param, 'P');
}
};
});
}
@ -2554,6 +2531,9 @@ EX void showStereo() {
case sLR:
dialog::addSelItem(XLAT("distance between images"), fts(vid.lr_eyewidth), 'd');
break;
case sPanini: case sStereographic:
add_edit(vid.stereo_param);
break;
default:
dialog::addBreak(100);
break;

View File

@ -22,10 +22,6 @@ EX bool spatial_graphics;
EX bool wmspatial, wmescher, wmplain, wmblack, wmascii, wmascii3;
EX bool mmspatial, mmhigh, mmmon, mmitem;
EX ld panini_alpha = 0;
EX ld stereo_alpha = 0;
EX bool equirectangular;
EX int detaillevel = 0;
EX bool first_cell_to_draw = true;
@ -4122,10 +4118,14 @@ EX ld threshold, xyz_threshold;
EX bool clip_checked = false;
EX bool other_stereo_mode() {
return among(vid.stereo_mode, sODS, sPanini, sStereographic, sEquirectangular);
}
void make_clipping_planes() {
#if MAXMDIM >= 4
clip_checked = false;
if(!frustum_culling || PIU(sphere) || experimental || vid.stereo_mode == sODS || panini_alpha || stereo_alpha || gproduct || embedded_plane) return;
if(!frustum_culling || PIU(sphere) || experimental || other_stereo_mode() || gproduct || embedded_plane) return;
if(WDIM == 3 && pmodel == mdPerspective && !nonisotropic && !in_s2xe())
threshold = sin_auto(cgi.corner_bonus), xyz_threshold = 0, clip_checked = true;
@ -5496,6 +5496,11 @@ EX ld min_scale = 1e-6;
EX int forced_center_down = ISANDROID ? 2 : ISIOS ? 40 : 40;
EX ld get_stereo_param() {
if(among(vid.stereo_mode, sPanini, sStereographic)) return vid.stereo_param;
return 0;
}
EX void calcparam() {
DEBBI(DF_GRAPH, ("calc param"));
@ -5557,7 +5562,7 @@ EX void calcparam() {
cd->ycenter += cd->scrsize * pconf.yposition;
ld fov = vid.fov * degree / 2;
cd->tanfov = sin(fov) / (cos(fov) + (panini_alpha ? panini_alpha : stereo_alpha));
cd->tanfov = sin(fov) / (cos(fov) + get_stereo_param());
callhooks(hooks_calcparam);
reset_projection();

View File

@ -250,7 +250,7 @@ struct charstyle {
bool lefthanded;
};
enum eStereo { sOFF, sAnaglyph, sLR, sODS };
enum eStereo { sOFF, sAnaglyph, sLR, sODS, sPanini, sStereographic, sEquirectangular };
enum eModel : int;
@ -395,6 +395,7 @@ struct videopar {
int cells_generated_limit; // limit on cells generated per frame
eStereo stereo_mode;
ld stereo_param;
ld ipd;
ld lr_eyewidth, anaglyph_eyewidth;
ld fov;

View File

@ -457,6 +457,24 @@ int read_legacy_args_anim() {
} */
/* skiprope:legacy.cpp pconf.skiprope += skiprope_rotation * t * TAU / period; */
}
else if(argis("-palpha")) {
PHASEFROM(2);
#if CAP_GL
shift_arg_formula(vid.stereo_param, reset_all_shaders);
#else
shift_arg_formula(vid.stereo_param);
#endif
vid.stereo_mode = sPanini;
}
else if(argis("-salpha")) {
PHASEFROM(2);
#if CAP_GL
shift_arg_formula(vid.stereo_param, reset_all_shaders);
#else
shift_arg_formula(vid.stereo_param);
#endif
vid.stereo_mode = sStereographic;
}
else return 1;
return 0;
}

View File

@ -234,7 +234,7 @@ EX namespace models {
}
EX bool has_orientation(eModel m) {
if(is_perspective(m) && panini_alpha) return true;
if(is_perspective(m) && vid.stereo_mode == sPanini) return true;
if(nonisotropic) return false;
return (mdinf[m].flags & mf::orientation);
}
@ -884,22 +884,6 @@ EX namespace models {
PHASEFROM(2);
shift_arg_formula(vpconf.skiprope);
}
else if(argis("-palpha")) {
PHASEFROM(2);
#if CAP_GL
shift_arg_formula(panini_alpha, reset_all_shaders);
#else
shift_arg_formula(panini_alpha);
#endif
}
else if(argis("-salpha")) {
PHASEFROM(2);
#if CAP_GL
shift_arg_formula(stereo_alpha, reset_all_shaders);
#else
shift_arg_formula(stereo_alpha);
#endif
}
else if(argis("-zoom")) {
PHASEFROM(2); shift_arg_formula(vpconf.scale);
}

View File

@ -1434,10 +1434,10 @@ void raygen::emit_iterate(int gid1) {
fsh += "uniform mediump float uLevelLines;\n";
}
if(panini_alpha)
if(vid.stereo_mode == sPanini)
fmain += panini_shader();
else if(stereo_alpha)
else if(vid.stereo_mode == sStereographic)
fmain += stereo_shader();
#ifndef GLES_ONLY
@ -1965,8 +1965,9 @@ void raygen::create() {
" mediump mat4 vw = uStart * xzspin(-lambda) * "+f_xpush()+"(eye) * yzspin(phi);\n"
" mediump vec4 at0 = vec4(0., 0., 1., 0.);\n";
// todo: will not work in product!
*/
else if(equirectangular) fmain +=
else if(vid.stereo_mode == sEquirectangular) fmain +=
" mediump float lambda = at.x * PI;\n" // -PI to PI
" mediump float phi = at.y * PI / 2.0;\n"
" mediump mat4 vw = uStart;\n"
@ -1978,10 +1979,10 @@ void raygen::create() {
" mediump vec4 at0 = at;\n"
" at0.y = -at.y;\n"
" at0.w = 0.;\n";
if(panini_alpha) fmain +=
if(vid.stereo_mode == sPanini) fmain +=
"mediump float hr = at0.x*at0.x;\n"
"mediump float alpha = " + to_glsl(panini_alpha) + ";\n"
"mediump float alpha = " + to_glsl(get_stereo_param()) + ";\n"
"mediump float A = 1. + hr;\n"
"mediump float B = -2.*hr*alpha;\n"
"mediump float C = 1. - hr*alpha*alpha;\n"
@ -1995,9 +1996,9 @@ void raygen::create() {
"\n"
;
else if(stereo_alpha) fmain +=
else if(vid.stereo_mode == sStereographic) fmain +=
"mediump float hr = at0.x*at0.x+at0.y*at0.y;\n"
"mediump float alpha = " + to_glsl(stereo_alpha) + ";\n"
"mediump float alpha = " + to_glsl(get_stereo_param()) + ";\n"
"mediump float A = 1. + hr;\n"
"mediump float B = -2.*hr*alpha;\n"
"mediump float C = 1. - hr*alpha*alpha;\n"
@ -2579,7 +2580,7 @@ EX void cast() {
#else
if(0) ;
#endif
else if(equirectangular) {
else if(among(vid.stereo_mode, sODS, sEquirectangular)) {
glUniformMatrix4fv(o->uProjection, 1, 0, glhr::tmtogl_transpose(Id).as_array());
}
else {

View File

@ -77,7 +77,7 @@ EX string panini_shader() {
"float s = t.z;\n"
"float l = length(t.xyz);\n"
"t /= max(length(t.xz), 1e-2);\n"
"t.z += " + glhr::to_glsl(panini_alpha) + ";\n"
"t.z += " + glhr::to_glsl(get_stereo_param()) + ";\n"
"t *= l;\n"
"t.w = 1.;\n";
}
@ -88,7 +88,7 @@ EX string stereo_shader() {
"float s = t.z;\n"
"float l = length(t.xyz);\n"
"t /= max(l, 1e-2);\n"
"t.z += " + glhr::to_glsl(stereo_alpha) + ";\n"
"t.z += " + glhr::to_glsl(get_stereo_param()) + ";\n"
"t *= l;\n"
"t.w = 1.;\n";
}
@ -515,13 +515,13 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
if(shader_flags & GF_LEVELS) vmain += "vPos = t;\n";
if(treset) vmain += "t[3] = 1.0;\n";
if((shader_flags & SF_PERS3) && panini_alpha && !vrhr::rendering_eye()) {
if((shader_flags & SF_PERS3) && vid.stereo_mode == sPanini && !vrhr::rendering_eye()) {
vmain += "t = uPP * t;", vsh += "uniform mediump mat4 uPP;";
/* panini */
vmain += panini_shader();
shader_flags |= SF_ORIENT;
}
else if((shader_flags & SF_PERS3) && stereo_alpha && !vrhr::rendering_eye()) {
else if((shader_flags & SF_PERS3) && vid.stereo_mode == sStereographic && !vrhr::rendering_eye()) {
vmain += "t = uPP * t;", vsh += "uniform mediump mat4 uPP;";
vmain += stereo_shader();
shader_flags |= SF_ORIENT;

View File

@ -190,7 +190,7 @@
#endif
#ifndef CAP_ODS
#define CAP_ODS 0
#define CAP_ODS 1
#endif
#ifndef CAP_VIDEO