new projections mostly for Solv: Lie perspective and Lie orthogonal

This commit is contained in:
Zeno Rogue 2022-05-17 09:40:33 +02:00
parent 69a82a8ce1
commit a6dc4b9314
7 changed files with 162 additions and 14 deletions

View File

@ -1748,7 +1748,7 @@ void celldrawer::draw_features_and_walls_3d() {
for(int a=0; a<c->type; a++) {
bool b = true;
if(c->move(a) && (among(pmodel, mdPerspective, mdGeodesic) || gmatrix0.count(c->move(a))))
if(c->move(a) && (in_perspective() || gmatrix0.count(c->move(a))))
b = (patterns::innerwalls && (tC0(V)[2] < tC0(V * currentmap->adj(c, a))[2])) || fake::split() || !isWall3(c->move(a), dummy);
if(b) {
#if CAP_WRL

View File

@ -1007,8 +1007,8 @@ enum eModel : int {
// 32..38
mdWerner, mdAitoff, mdHammer, mdLoximuthal, mdMiller, mdGallStereographic, mdWinkelTripel,
// 39..
mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint,
// 45..
mdPoorMan, mdPanini, mdRetroCraig, mdRetroLittrow, mdRetroHammer, mdThreePoint, mdLiePerspective, mdLieOrthogonal,
// 47..
mdGUARD, mdPixel, mdHyperboloidFlat, mdPolynomial, mdManual
};
#endif
@ -1066,6 +1066,8 @@ EX vector<modelinfo> mdinf = {
{X3("Littrow retroazimuthal"), mf::euc_boring | mf::broken, DEFAULTS}, // retroazimuthal conformal
{X3("Hammer retroazimuthal"), mf::euc_boring, DEFAULTS}, // retroazimuthal equidistant
{X3("three-point equidistant"), mf::euc_boring, DEFAULTS},
{X3("Lie perspective"), mf::euc_boring, DEFAULTS},
{X3("Lie orthogonal"), mf::euc_boring, DEFAULTS},
{X3("guard"), mf::technical, DEFAULTS},
{X3("pixel"), mf::technical, DEFAULTS},
{X3("hypflat"), mf::technical, DEFAULTS},

View File

@ -480,6 +480,8 @@ void coords_to_poly() {
bool behind3(shiftpoint h) {
if(pmodel == mdGeodesic)
return lp_apply(inverse_exp(h))[2] < 0;
if(pmodel == mdLiePerspective)
return lp_apply(lie_log(unshift(h)))[2] < 0;
return h[2] < 0;
}
@ -496,7 +498,7 @@ void addpoly(const shiftmatrix& V, const vector<glvertex> &tab, int ofs, int cnt
return;
}
tofix.clear(); knowgood = false;
if(among(pmodel, mdPerspective, mdGeodesic)) {
if(in_perspective()) {
if(poly_flags & POLY_TRIANGLES) {
for(int i=ofs; i<ofs+cnt; i+=3) {
shiftpoint h0 = V * glhr::gltopoint(tab[i]);

View File

@ -30,11 +30,11 @@ EX int detaillevel = 0;
EX bool first_cell_to_draw = true;
EX bool in_perspective() {
return among(pconf.model, mdPerspective, mdGeodesic);
return models::is_perspective(pconf.model);
}
EX bool in_perspective_v() {
return among(vpconf.model, mdPerspective, mdGeodesic);
return models::is_perspective(vpconf.model);
}
EX bool hide_player() {

View File

@ -527,6 +527,30 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
return;
}
case mdLiePerspective: {
if(false) {
hyperpoint h = point31(0, 0, 1);
hyperpoint a = point31(0, 0, 0);
hyperpoint b = point31(0.1, 0, 0);
println(hlog, rgpushxto0(h) * a);
println(hlog, rgpushxto0(h) * b);
exit(1);
/* x wanes as z grows! */
}
if(hyperbolic) {
models::apply_orientation_yz(H[1], H[2]);
models::apply_orientation(H[0], H[1]);
}
auto S = lie_log(H); S[3] = 1;
S = lp_apply(S);
if(hyperbolic) {
models::apply_orientation(ret[1], ret[0]);
models::apply_orientation_yz(ret[2], ret[1]);
}
apply_perspective(S, ret);
return;
}
case mdPixel:
ret = H / current_display->radius;
return;
@ -742,7 +766,29 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
break;
}
case mdLieOrthogonal: {
find_zlev(H);
if(hyperbolic) {
models::apply_orientation_yz(H[1], H[2]);
models::apply_orientation(H[0], H[1]);
}
ret = lie_log(H);
ret *= .5;
ret[LDIM] = 1;
if(hyperbolic) {
models::apply_orientation(ret[1], ret[0]);
models::apply_orientation_yz(ret[2], ret[1]);
}
if(nonisotropic && !vrhr::rendering()) ret = lp_apply(ret);
break;
}
case mdHemisphere: {
#if CAP_VR
@ -2995,6 +3041,51 @@ EX hyperpoint lie_exp(hyperpoint h) {
return h;
}
EX hyperpoint lie_log(hyperpoint h) {
if(nil) {
h[3] = 0;
h[2] -= h[0] * h[1] / 2;
}
else if(sol && !nih) {
h[3] = 0;
if(abs(h[2] > 1e-6)) {
h[0] *= -h[2] / (exp(-h[2]) - 1);
h[1] *= h[2] / (exp(+h[2]) - 1);
}
}
else if(sol && nih) {
h[3] = 0;
if(abs(h[2] > 1e-6)) {
ld z = h[2] * log(2);
h[0] *= -z / (exp(-z) - 1);
z = h[2] * log(3);
h[1] *= z / (exp(+z) - 1);
}
}
else if(nih) {
h[3] = 1;
if(abs(h[2] > 1e-6)) {
ld z = h[2] * log(2);
h[0] *= z / (exp(+z) - 1);
z = h[2] * log(3);
h[1] *= z / (exp(+z) - 1);
}
}
else if(euclid) {
h[LDIM] = 0;
}
else if(hyperbolic) {
h = deparabolic13(h);
if(abs(h[0]) > 1e-6)
for(int i=1; i<LDIM; i++)
h[i] *= h[0] / (exp(h[0])-1);
}
else {
/* not implemented */
}
return h;
}
/** shift the view according to the given tangent vector */
EX transmatrix get_shift_view_of(const hyperpoint H, const transmatrix V) {
if(!nonisotropic && !stretch::in()) {

View File

@ -193,11 +193,13 @@ EX namespace models {
return PIU(model_available(pm));
}
if(sl2) return pm == mdGeodesic;
if(nonisotropic) return among(pm, mdDisk, mdPerspective, mdHorocyclic, mdGeodesic, mdEquidistant, mdFisheye);
if(pm == mdGeodesic && !sol) return false;
if(nonisotropic) return among(pm, mdDisk, mdPerspective, mdHorocyclic, mdGeodesic, mdEquidistant, mdFisheye, mdLiePerspective, mdLieOrthogonal);
if(sphere && (pm == mdHalfplane || pm == mdBall))
return false;
if(GDIM == 2 && pm == mdPerspective) return false;
if(GDIM == 2 && is_perspective(pm)) return false;
if(pm == mdGeodesic && !nonisotropic) return false;
if(pm == mdLiePerspective && sphere) return false;
if(pm == mdLieOrthogonal && sphere) return false;
if(GDIM == 2 && pm == mdEquivolume) return false;
if(pm == mdThreePoint && !(GDIM == 3 && !nonisotropic && !prod)) return false;
if(GDIM == 3 && among(pm, mdBall, mdHyperboloid, mdFormula, mdPolygonal, mdRotatedHyperboles, mdSpiral, mdHemisphere)) return false;
@ -208,8 +210,8 @@ EX namespace models {
}
EX bool has_orientation(eModel m) {
if(m == mdHorocyclic)
return hyperbolic;
if(among(m, mdHorocyclic, mdLieOrthogonal, mdLiePerspective))
return hyperbolic || in_h2xe();
if((m == mdPerspective || m == mdGeodesic) && panini_alpha) return true;
return
among(m, mdHalfplane, mdPolynomial, mdPolygonal, mdTwoPoint, mdJoukowsky, mdJoukowskyInverted, mdSpiral, mdSimulatedPerspective, mdTwoHybrid, mdHorocyclic, mdAxial, mdAntiAxial, mdQuadrant,
@ -228,7 +230,7 @@ EX namespace models {
}
EX bool is_perspective(eModel m) {
return among(m, mdPerspective, mdGeodesic);
return among(m, mdPerspective, mdGeodesic, mdLiePerspective);
}
EX bool is_3d(const projection_configuration& p) {
@ -256,7 +258,7 @@ EX namespace models {
if(m == mdHorocyclic && !sol) return XLAT("simple model: projection");
if(m == mdPerspective) return XLAT("simple model: perspective");
if(m == mdGeodesic) return XLAT("native perspective");
if(among(m, mdEquidistant, mdFisheye, mdHorocyclic)) return XLAT(mdinf[m].name_hyperbolic);
if(among(m, mdEquidistant, mdFisheye, mdHorocyclic, mdLiePerspective, mdLieOrthogonal)) return XLAT(mdinf[m].name_hyperbolic);
}
if(m == mdDisk && GDIM == 3) return XLAT("perspective in 4D");
if(m == mdHalfplane && GDIM == 3 && hyperbolic) return XLAT("half-space");
@ -542,6 +544,12 @@ EX namespace models {
dialog::addBoolItem_action(XLAT("use atan to make it finite"), vpconf.use_atan, 'x');
}
if(among(vpmodel, mdLieOrthogonal, mdLiePerspective)) {
if(in_s2xe() || (sphere && GDIM == 2)) dialog::addInfo(XLAT("this is not a Lie group"), 0xC00000);
else if(!hyperbolic && !sol && !nih && !nil && !euclid && !in_h2xe() && !in_e2xe())
dialog::addInfo(XLAT("not implemented"));
}
if(vpmodel == mdBall && !vr_settings) {
dialog::addSelItem(XLAT("projection in ball model"), fts(vpconf.ballproj), 'x');
dialog::add_action([] () {

View File

@ -88,6 +88,27 @@ EX string stereo_shader() {
"t.w = 1.;\n";
}
EX string shader_lie_log() {
if(nil) {
return "vec4 lie_log(vec4 v) { v[2] += v[0] * v[1] / 2.; return v; }\n";
}
else if(sol && !nih) {
return "vec4 lie_log(vec4 v) { if(abs(v[2]) > 1e-6) { v[0] *= -v[2] / (exp(-v[2])-1.); v[1] *= v[2] / (exp(v[2])-1.); } return v; }\n";
}
else if(sol && nih) {
return "vec4 lie_log(vec4 v) { if(abs(v[2]) > 1e-6) { float z = v[2] * log(2); v[0] *= -z / (exp(-z)-1.); z = v[2] * log(3); v[1] *= z / (exp(z)-1.); } return v; }\n";
}
else if(nih) {
return "vec4 lie_log(vec4 v) { if(abs(v[2]) > 1e-6) { float z = v[2] * log(2); v[0] *= z / (exp(z)-1.); z = v[2] * log(3); v[1] *= z / (exp(z)-1.); } return v; }\n";
}
else if(hyperbolic) {
return "vec4 lie_log(vec4 v) { v = deparabolic13(v); v[3] = 1.; /* if(abs(v[0]) > 1e-6) { float m = v[0] / (exp(v[0]) - 1.); v[1] *= m; v[2] *= m; } */ return v; }\n";
}
else {
return "vec4 lie_log(vec4 v) { return v; }\n";
}
}
shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
string varying, vsh, fsh, vmain = "void main() {\n", fmain = "void main() {\n";
@ -238,6 +259,16 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
"t.xyz /= -rads; t[3] = 1.0;\n";
if(dim3) shader_flags |= SF_ZFOG;
}
else if(pmodel == mdLiePerspective) {
shader_flags |= SF_PERS3 | SF_DIRECT;
if(hyperbolic) {
shader_flags |= SF_ORIENT;
coordinator += "t = uPP * t;", vsh += "uniform mediump mat4 uPP;";
}
coordinator += "t = lie_log(t);\n";
distfun = "length(t.xyz)";
vsh += shader_lie_log();
}
else if(pmodel == mdGeodesic) {
shader_flags |= SF_PERS3 | SF_DIRECT;
coordinator += "t = inverse_exp(t);\n";
@ -769,6 +800,20 @@ EX void add_fixed_functions(string& shader) {
"if(y < 0.) return atan(y / x) - PI;\n"
"}\n");
add_if(shader, "deparabolic13",
"mediump vec4 deparabolic13(mediump vec4 h) {\n"
" h /= (1. + h[3]);\n"
" h[0] -= 1.;\n"
" h /= h.x*h.x + h.y*h.y + h.z * h.z;\n"
" h[0] += .5;\n"
" mediump vec4 res;\n"
" res.x = (log(2.) + log(-h.x));\n"
" res.y = h.y * 2.;\n"
" res.z = h.z * 2.;\n"
" res.w = 1.;\n"
" return res;\n"
" }\n\n");
add_if(shader, "PI", "#define PI 3.14159265358979324\n");
#ifndef GLES_ONLY
add_if(shader, "mediump", "#define mediump\n");