1
0
mirror of https://github.com/zenorogue/hyperrogue.git synced 2024-12-24 17:10:36 +00:00

vr:: correctly rendered 2D sphere

This commit is contained in:
Zeno Rogue 2020-12-29 02:51:43 +01:00
parent 6217ec4702
commit 2e0ddd5a48
4 changed files with 95 additions and 20 deletions

View File

@ -995,7 +995,7 @@ enum eModel : int {
/** list of available models (i.e., projections) */
EX vector<modelinfo> mdinf = {
{"disk/Gans", "general perspective", "general perspective", mf::azimuthal | mf::conformal, DEFAULTS},
{"half-plane", "inversion", "half-plane", mf::conformal, DEFAULTS},
{"half-plane", "inversion", "stereographic projection [VR]", mf::conformal, DEFAULTS},
{"band", "band", "Mercator", mf::band | mf::conformal, DEFAULTS},
{X3("polygonal"), mf::conformal, DEFAULTS},
{X3("formula"), 0, DEFAULTS},

View File

@ -161,6 +161,9 @@ EX unsigned char& part(color_t& col, int i) {
#endif
}
bool in_vr_sphere;
hyperpoint vr_sphere_center;
bool fatborder;
EX color_t poly_outline;
@ -277,6 +280,7 @@ int axial_sign() {
bool is_behind(const hyperpoint& H) {
if(pmodel == mdAxial && sphere) return axial_sign() * H[2] <= BEHIND_LIMIT;
if(in_vr_sphere) return false;
return pmodel == mdDisk && (hyperbolic ? H[2] >= 0 : true) && (nonisotropic ? false : pconf.alpha + H[2] <= BEHIND_LIMIT);
}
@ -304,6 +308,7 @@ EX bool two_sided_model() {
constexpr bool in_vr = false;
#endif
if(GDIM == 3) return false;
if(in_vr_sphere) return true;
if(pmodel == mdHyperboloid) return !euclid && !in_vr;
// if(pmodel == mdHemisphere) return true;
if(pmodel == mdDisk) return sphere;
@ -316,6 +321,16 @@ EX bool two_sided_model() {
}
EX int get_side(const hyperpoint& H) {
if(in_vr_sphere) {
hyperpoint Hscr;
applymodel(shiftless(H), Hscr);
Hscr[3] = 1;
E4;
hyperpoint actual = vrhr::hmd_mv * Hscr;
ld val = 0;
for(int i=0; i<3; i++) val += (vr_sphere_center[i] - actual[i]) * actual[i];
return val > 0 ? -1 : 1;
}
if(pmodel == mdDisk && sphere) {
double curnorm = H[0]*H[0]+H[1]*H[1]+H[2]*H[2];
double horizon = curnorm / pconf.alpha;
@ -951,7 +966,10 @@ void compute_side_by_centerin(dqi_poly *p, bool& nofill) {
else
nofill = true;
}
applymodel(h1, hscr); hscr[0] *= current_display->radius; hscr[1] *= current_display->radius * pconf.stretch;
applymodel(h1, hscr);
if(vrhr::state != 2) {
hscr[0] *= current_display->radius; hscr[1] *= current_display->radius * pconf.stretch;
}
for(int i=0; i<isize(glcoords)-1; i++) {
double x1 = glcoords[i][0] - hscr[0];
double y1 = glcoords[i][1] - hscr[1];
@ -1836,6 +1854,7 @@ void dqi_poly::draw() {
bool can_have_inverse = false;
if(sphere && pmodel == mdDisk && (spherespecial > 0 || equi)) can_have_inverse = true;
if(vrhr::state == 2) can_have_inverse = false;
if(sphere && among(pmodel, mdEquidistant, mdEquiarea)) can_have_inverse = true;
if(pmodel == mdJoukowsky) can_have_inverse = true;
if(pmodel == mdJoukowskyInverted && pconf.skiprope) can_have_inverse = true;
@ -2234,6 +2253,21 @@ EX void reverse_transparent_walls() {
EX void draw_main() {
DEBBI(DF_GRAPH, ("draw_main"));
in_vr_sphere = false;
#if CAP_VR
in_vr_sphere = vrhr::state == 2 && among(pmodel, mdDisk, mdBall, mdHyperboloid, mdHalfplane, mdHemisphere);
if(in_vr_sphere) {
hyperpoint a, b;
applymodel(shiftless(point3(0, 0, 1)), a);
applymodel(shiftless(point3(0, 0, -1)), b);
vr_sphere_center = (a + b) / 2;
vr_sphere_center[3] = 1;
E4;
vr_sphere_center = vrhr::hmd_mv * vr_sphere_center;
}
#endif
if(sphere && GDIM == 3 && pmodel == mdPerspective && !stretch::in() && !ray::in_use) {
if(ray::in_use && !ray::comparison_mode) {

View File

@ -376,6 +376,49 @@ EX void applymodel(shiftpoint H_orig, hyperpoint& ret) {
apply_other_model(H_orig, ret, pmodel);
}
EX void vr_sphere(hyperpoint& ret, hyperpoint& H, eModel md) {
ret = H;
int flip = 1;
if(md == mdHalfplane) flip = -flip;
if(pconf.alpha < 1) flip = -flip;
ret *= pow(sqhypot_d(3, H), (flip * pconf.depth_scaling-1) / 2);
ret[2] += pconf.alpha;
if(md == mdHalfplane) {
ld d = sqhypot_d(3, ret);
ret /= abs(d);
}
models::apply_vr(ret[2], ret[1]);
}
void vr_disk(hyperpoint& ret, hyperpoint& H) {
if(euclid) {
ret = H;
ret[2] = vid.depth * (1 - (ret[2] - 1) * pconf.depth_scaling) + pconf.alpha + vid.camera;
}
else if(sphere) {
vr_sphere(ret, H, mdDisk);
return;
}
else {
ld zlev = find_zlev(H);
ld zl = vid.depth-geom3::factor_to_lev(zlev) * pconf.depth_scaling;
ld d = hdist0(H);
ld dd = hypot_d(2, H);
hyperpoint H1 = ypush(vid.camera) * xpush(d) * ypush0(zl);
ld tzh = pconf.alpha + H1[2];
ld ax = H1[0] / tzh;
ld ay = H1[1] / tzh;
ret[0] = ax * H[0] / dd;
ret[1] = ax * H[1] / dd;
ret[2] = ay;
}
models::apply_vr(ret[2], ret[1]);
}
EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
hyperpoint H = H_orig.h;
@ -409,6 +452,10 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
return;
case mdBall: {
if(vrhr::state == 2) {
vr_disk(ret, H);
return;
}
ld zlev = find_zlev(H);
ld zl = vid.depth-geom3::factor_to_lev(zlev) * pconf.depth_scaling;
@ -435,22 +482,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
break;
}
if(vrhr::state == 2) {
ld zlev = find_zlev(H);
ld zl = vid.depth-geom3::factor_to_lev(zlev) * pconf.depth_scaling;
ld d = hdist0(H);
ld dd = hypot_d(2, H);
hyperpoint H1 = ypush(vid.camera) * xpush(d) * ypush0(zl);
ld tzh = pconf.alpha + H1[2];
ld ax = H1[0] / tzh;
ld ay = H1[1] / tzh;
ret[0] = ax * H[0] / dd;
ret[1] = ax * H[1] / dd;
ret[2] = ay;
models::apply_vr(ret[2], ret[1]);
vr_disk(ret, H);
return;
}
ld tz = get_tz(H);
@ -486,6 +518,10 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
}
case mdHalfplane: {
if(sphere && vrhr::state == 2) {
vr_sphere(ret, H, md);
return;
}
// Poincare to half-plane
ld zlev = find_zlev(H);
@ -661,6 +697,7 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
}
case gcSphere: {
if(vrhr::state == 2) { vr_sphere(ret, H, md); return; }
ret = H;
if(pconf.depth_scaling != 1) {
ld v = intval(H, Hypc);
@ -699,12 +736,13 @@ EX void apply_other_model(shiftpoint H_orig, hyperpoint& ret, eModel md) {
#if CAP_VR
if(vrhr::state == 2) {
if(sphere) { vr_sphere(ret, H, md); return; }
ret[0] = H[0] * pconf.hyperboloid_scaling;
ret[1] = H[1] * pconf.hyperboloid_scaling;
ret[2] = (pconf.alpha + H[2]);
if(pconf.depth_scaling != 1) {
ld v = intval(H, Hypc);
ret *= pow(v, (pconf.depth_scaling*(sphere?-1:1)-1) / 2);
ret *= pow(v, (pconf.depth_scaling-1) / 2);
}
models::apply_vr(ret[2], ret[1]);
break;

5
vr.cpp
View File

@ -143,8 +143,10 @@ EX string error_msg;
/** 0 = not loaded, 1 = loaded but not currently rendering, 2 = currently rendering the VR screen, 3 = currently rendering the computer screen */
EX int state = 0;
#if HDR
// use E4 when working with real-world matrices to ensure that inverses, multiplications, etc. are computed correctly
#define E4 dynamicval<eGeometry> g(geometry, gCubeTiling)
#endif
#define IN_E4(x) [&]{ E4; return x; }()
@ -198,7 +200,7 @@ EX bool first = true;
EX transmatrix hmd_at = Id;
EX transmatrix hmd_ref_at = Id;
EX transmatrix hmd_mvp, hmd_pre;
EX transmatrix hmd_mvp, hmd_pre, hmd_mv;
EX transmatrix sm;
@ -794,6 +796,7 @@ EX void render() {
if(eyes == eEyes::equidistant) {
hmd_mvp = inverse(vrdata.eyepos[i]) * hmd_mvp;
}
hmd_mv = hmd_mvp;
hmd_mvp = vrdata.proj[i] * hmd_mvp;
}
eyeproj = vrdata.iproj[i];