Panini projection

This commit is contained in:
Zeno Rogue 2020-11-01 21:20:54 +01:00
parent 2cc06e39ba
commit 6513b3a87e
6 changed files with 104 additions and 17 deletions

View File

@ -713,6 +713,8 @@ EX void initConfig() {
addsaver(camera_speed, "camera-speed", 1); addsaver(camera_speed, "camera-speed", 1);
addsaver(camera_rot_speed, "camera-rot-speed", 1); addsaver(camera_rot_speed, "camera-rot-speed", 1);
addsaver(panini_alpha, "panini_alpha", 0);
callhooks(hooks_configfile); callhooks(hooks_configfile);
#if CAP_CONFIG #if CAP_CONFIG
@ -1551,17 +1553,48 @@ EX void explain_detail() {
)); ));
} }
EX void add_edit_fov(char key IS('f')) { EX ld max_fov_angle() {
dialog::addSelItem(XLAT("field of view"), fts(vid.fov) + "°", key); return acos(-panini_alpha) * 2 / degree;
dialog::add_action([] { }
dialog::editNumber(vid.fov, 1, 170, 1, 45, "field of view",
EX void add_edit_fov(char key IS('f'), bool pop IS(false)) {
string sfov = fts(vid.fov) + "°";
if(panini_alpha) {
sfov += " / " + fts(max_fov_angle()) + "°";
}
dialog::addSelItem(XLAT("field of view"), sfov, key);
dialog::add_action([=] {
if(pop) popScreen();
dialog::editNumber(vid.fov, 1, max_fov_angle(), 1, 45, "field of view",
XLAT( XLAT(
"Horizontal field of view, in angles. " "Horizontal field of view, in angles. "
"This affects the Hypersian Rug mode (even when stereo is OFF) " "This affects the Hypersian Rug mode (even when stereo is OFF) "
"and non-disk models.") "and non-disk models.") + "\n\n" +
XLAT(
"Must be less than %1°. Panini projection can be used to get higher values.",
fts(max_fov_angle())
)
); );
dialog::bound_low(1e-8); dialog::bound_low(1e-8);
dialog::bound_up(179); dialog::bound_up(max_fov_angle() - 0.01);
dialog::extra_options = [] {
dialog::addSelItem(XLAT("Panini projection"), fts(panini_alpha), 'P');
dialog::add_action([] {
popScreen();
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. HyperRogue uses "
"a quick implementation, so parameter values too close to 1 may "
"be buggy; try e.g. 0.9 instead.")
);
dialog::reaction = ray::reset_raycaster;
dialog::extra_options = [] {
add_edit_fov('F', true);
};
});
};
}); });
} }

View File

@ -154,7 +154,7 @@ void display(const glmatrix& m) {
printf("\n"); printf("\n");
} }
glmatrix operator * (glmatrix m1, glmatrix m2) { EX glmatrix operator * (glmatrix m1, glmatrix m2) {
glmatrix res; glmatrix res;
for(int i=0; i<4; i++) for(int i=0; i<4; i++)
for(int j=0; j<4; j++) { for(int j=0; j<4; j++) {

View File

@ -22,6 +22,8 @@ EX bool spatial_graphics;
EX bool wmspatial, wmescher, wmplain, wmblack, wmascii, wmascii3; EX bool wmspatial, wmescher, wmplain, wmblack, wmascii, wmascii3;
EX bool mmspatial, mmhigh, mmmon, mmitem; EX bool mmspatial, mmhigh, mmmon, mmitem;
EX ld panini_alpha = 0;
EX int detaillevel = 0; EX int detaillevel = 0;
EX bool first_cell_to_draw = true; EX bool first_cell_to_draw = true;
@ -4878,7 +4880,8 @@ EX void calcparam() {
cd->xcenter += cd->scrsize * pconf.xposition; cd->xcenter += cd->scrsize * pconf.xposition;
cd->ycenter += cd->scrsize * pconf.yposition; cd->ycenter += cd->scrsize * pconf.yposition;
cd->tanfov = tan(vid.fov * degree / 2); ld fov = vid.fov * degree / 2;
cd->tanfov = sin(fov) / (cos(fov) + panini_alpha);
callhooks(hooks_calcparam); callhooks(hooks_calcparam);
reset_projection(); reset_projection();

View File

@ -208,6 +208,7 @@ EX namespace models {
EX bool has_orientation(eModel m) { EX bool has_orientation(eModel m) {
if(m == mdHorocyclic) if(m == mdHorocyclic)
return hyperbolic; return hyperbolic;
if((m == mdPerspective || m == mdGeodesic) && panini_alpha) return true;
return return
among(m, mdHalfplane, mdPolynomial, mdPolygonal, mdTwoPoint, mdJoukowsky, mdJoukowskyInverted, mdSpiral, mdSimulatedPerspective, mdTwoHybrid, mdHorocyclic, mdAxial, mdAntiAxial, mdQuadrant, among(m, mdHalfplane, mdPolynomial, mdPolygonal, mdTwoPoint, mdJoukowsky, mdJoukowskyInverted, mdSpiral, mdSimulatedPerspective, mdTwoHybrid, mdHorocyclic, mdAxial, mdAntiAxial, mdQuadrant,
mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdWinkelTripel) || mdBandAny(); mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdWinkelTripel) || mdBandAny();
@ -868,6 +869,10 @@ EX namespace models {
PHASEFROM(2); PHASEFROM(2);
shift_arg_formula(vpconf.skiprope); shift_arg_formula(vpconf.skiprope);
} }
else if(argis("-palpha")) {
PHASEFROM(2);
shift_arg_formula(panini_alpha, reset_all_shaders);
}
else if(argis("-zoom")) { else if(argis("-zoom")) {
PHASEFROM(2); shift_arg_formula(vpconf.scale); PHASEFROM(2); shift_arg_formula(vpconf.scale);
} }

View File

@ -370,14 +370,34 @@ void enable_raycaster() {
" mediump mat4 vw = uStart * xzspin(-lambda) * xpush(eye) * yzspin(phi);\n" " mediump mat4 vw = uStart * xzspin(-lambda) * xpush(eye) * yzspin(phi);\n"
" mediump vec4 at0 = vec4(0., 0., 1., 0.);\n"; " mediump vec4 at0 = vec4(0., 0., 1., 0.);\n";
else fmain += else {
" mediump mat4 vw = uStart;\n" fmain +=
" mediump vec4 at0 = at;\n" " mediump mat4 vw = uStart;\n"
" gl_FragColor = vec4(0,0,0,1);\n" " mediump vec4 at0 = at;\n"
" mediump float left = 1.;\n" " gl_FragColor = vec4(0,0,0,1);\n"
" at0.y = -at.y;\n" " mediump float left = 1.;\n"
" at0.w = 0.;\n" " at0.y = -at.y;\n"
" at0.xyz = at0.xyz / length(at0.xyz);\n"; " at0.w = 0.;\n";
if(panini_alpha) fmain +=
"mediump float hr = at0.x*at0.x;\n"
"mediump float alpha = " + to_glsl(panini_alpha) + ";\n"
"mediump float A = 1. + hr;\n"
"mediump float B = -2.*hr*alpha;\n"
"mediump float C = 1. - hr*alpha*alpha;\n"
"B /= A; C /= A;\n"
"mediump float hz = B / 2. + sqrt(C + B*B/4.);\n"
"if(abs(hz) > 1e-3) {"
"at0.xyz *= hz+alpha;\n"
"at0.z = hz;\n}"
" else at0.z = 0.;\n"
"\n"
;
fmain +=
" at0.xyz = at0.xyz / length(at0.xyz);\n";
}
if(hyperbolic) fsh += " mediump float len(mediump vec4 x) { return x[3]; }\n"; if(hyperbolic) fsh += " mediump float len(mediump vec4 x) { return x[3]; }\n";
else if(sphere && rotspace) fsh += " mediump float len(mediump vec4 x) { return 1.+x.x*x.x+x.y*x.y-x.z*x.z-x.w*x.w; }\n"; else if(sphere && rotspace) fsh += " mediump float len(mediump vec4 x) { return 1.+x.x*x.x+x.y*x.y-x.z*x.z-x.w*x.w; }\n";
@ -1091,6 +1111,7 @@ void enable_raycaster() {
} }
#ifndef GLES_ONLY #ifndef GLES_ONLY
/* todo: fix for Panini */
fmain += fmain +=
" gl_FragDepth = (" + to_glsl(-vnear-vfar)+"+w*" + to_glsl(2*vnear*vfar)+"/z)/" + to_glsl(vnear-vfar)+";\n" " gl_FragDepth = (" + to_glsl(-vnear-vfar)+"+w*" + to_glsl(2*vnear*vfar)+"/z)/" + to_glsl(vnear-vfar)+";\n"
" gl_FragDepth = (gl_FragDepth + 1.) / 2.;\n"; " gl_FragDepth = (gl_FragDepth + 1.) / 2.;\n";

View File

@ -60,6 +60,12 @@ glhr::glmatrix model_orientation_gl() {
return s; return s;
} }
EX void reset_all_shaders() {
ray::reset_raycaster();
compiled_programs.clear();
matched_programs.clear();
}
shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) { shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
string varying, vsh, fsh, vmain = "void main() {\n", fmain = "void main() {\n"; string varying, vsh, fsh, vmain = "void main() {\n", fmain = "void main() {\n";
@ -332,6 +338,21 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
} }
if(shader_flags & GF_LEVELS) vmain += "vPos = t;\n"; if(shader_flags & GF_LEVELS) vmain += "vPos = t;\n";
if(treset) vmain += "t[3] = 1.0;\n"; if(treset) vmain += "t[3] = 1.0;\n";
if(WDIM == 3 && panini_alpha) {
vmain += "t = uPP * t;", vsh += "uniform mediump mat4 uPP;";
/* panini */
vmain += "t.w += 1.; t *= 2. / t.w; t.w -= 1.;\n";
vmain += "float s = t.z;";
vmain += "float l = length(t.xyz);";
vmain += "t /= max(length(t.xz), 1e-2);\n";
vmain += "t.z += " + glhr::to_glsl(panini_alpha) + ";\n";
vmain += "t *= l;\n";
vmain += "t.w = 1.;\n";
frustum_culling = false;
shader_flags |= SF_ORIENT;
}
vmain += "gl_Position = uP * t;\n"; vmain += "gl_Position = uP * t;\n";
} }
@ -485,7 +506,8 @@ void display_data::set_projection(int ed, ld shift) {
for(int i=0; i<3; i++) NLP[3][i] = NLP[i][3] = 0; for(int i=0; i<3; i++) NLP[3][i] = NLP[i][3] = 0;
NLP[3][3] = 1; NLP[3][3] = 1;
} }
glhr::projection_multiply(glhr::tmtogl_transpose(NLP)); if(!(shader_flags & SF_ORIENT))
glhr::projection_multiply(glhr::tmtogl_transpose(NLP));
} }
if(ed) { if(ed) {
glhr::using_eyeshift = true; glhr::using_eyeshift = true;
@ -520,6 +542,9 @@ void display_data::set_projection(int ed, ld shift) {
if(get_shader_flags() & SF_USE_ALPHA) if(get_shader_flags() & SF_USE_ALPHA)
pp[3][2] = GLfloat(pconf.alpha); pp[3][2] = GLfloat(pconf.alpha);
if(nisot::local_perspective_used())
pp = glhr::tmtogl_transpose(NLP) * pp;
if(get_shader_flags() & SF_ORIENT) { if(get_shader_flags() & SF_ORIENT) {
if(GDIM == 3) for(int a=0; a<4; a++) if(GDIM == 3) for(int a=0; a<4; a++)
models::apply_orientation_yz(pp[a][1], pp[a][2]); models::apply_orientation_yz(pp[a][1], pp[a][2]);