primitive-based rendering of the Berger sphere (very poor)

This commit is contained in:
Zeno Rogue 2020-07-24 23:39:30 +02:00
parent 2dff2df4fe
commit 94cac21716
5 changed files with 221 additions and 7 deletions

View File

@ -673,6 +673,8 @@ EX void initConfig() {
addsaver(bright, "bright");
addsaver(cblind, "cblind");
addsaver(berger_limit, "berger_limit");
addsaverenum(centering, "centering");
callhooks(hooks_configfile);
@ -1729,6 +1731,16 @@ EX void show3D() {
});
}
if(WDIM == 3 && sphere && stretch::factor) {
dialog::addItem(XLAT("Berger sphere limit"), berger_limit);
dialog::add_action([] () {
dialog::editNumber(berger_limit, 0, 10, 1, 2, "",
XLAT("Primitive-based rendering of Berger sphere is currently very slow and low quality. "
"Here you can choose how many images to draw.")
);
});
}
#if CAP_RAY
if(GDIM == 3) {
dialog::addItem(XLAT("configure raycasting"), 'A');

View File

@ -1255,6 +1255,80 @@ void draw_s2xe0(dqi_poly *p) {
#endif
EX }
EX int berger_limit = 2;
void draw_stretch(dqi_poly *p) {
if(!(p->flags & POLY_TRIANGLES)) return;
dqi_poly npoly = *p;
npoly.offset = 0;
npoly.tab = &glcoords;
npoly.V = Id;
npoly.flags &= ~(POLY_INVERSE | POLY_FORCE_INVERTED);
transmatrix T2 = stretch::translate( tC0(inverse(View)) );
transmatrix U = View * T2;
transmatrix iUV = inverse(U) * p->V;
vector<hyperpoint> hs;
vector<hyperpoint> ths;
hs.resize(p->cnt);
ths.resize(p->cnt);
for(int i=0; i<p->cnt; i++)
hs[i] = iUV * glhr::gltopoint( (*p->tab)[p->offset+i] );
vector<vector<hyperpoint> > results;
results.resize(p->cnt);
auto& stinf = s2xe::stinf;
if(p->tinf) {
npoly.tinf = &stinf;
npoly.offset_texture = 0;
stinf.texture_id = p->tinf->texture_id;
stinf.tvertices.clear();
}
else {
npoly.tinf = NULL;
}
npoly.V = Id;
set_width(1);
glcoords.clear();
for(int i=0; i<p->cnt; i++) results[i] = stretch::inverse_exp_all(hs[i], berger_limit);
for(int i=0; i<p->cnt; i+=3) {
auto &la = results[i];
auto &lb = results[i+1];
auto &lc = results[i+2];
int ia = 0, ib = 0, ic = 0;
auto test = [] (hyperpoint a, hyperpoint b) -> bool {
return sqhypot_d(3, a-b) < 2;
};
for(auto& ha: la) for(auto& hb: lb) if(test(ha, hb))
for(auto& hc: lc) if(test(ha, hc) && test(hb, hc)) {
glcoords.push_back(glhr::pointtogl(U * ha));
glcoords.push_back(glhr::pointtogl(U * hb));
glcoords.push_back(glhr::pointtogl(U * hc));
if(p->tinf)
for(int j=0; j<3; j++)
stinf.tvertices.push_back(p->tinf->tvertices[p->offset_texture+i+j]);
ia++; ib++; ic++;
}
}
npoly.cnt = isize(glcoords);
npoly.gldraw();
}
EX namespace ods {
#if CAP_ODS
@ -1522,6 +1596,11 @@ void dqi_poly::draw() {
return;
} */
if(vid.usingGL && (current_display->set_all(global_projection), get_shader_flags() & SF_DIRECT) && sphere && (stretch::factor || ray::in_use)) {
draw_stretch(this);
return;
}
#if CAP_GL
if(vid.usingGL && (current_display->set_all(global_projection), get_shader_flags() & SF_DIRECT)) {
if(sl2 && pmodel == mdGeodesic && hybrid::csteps) {
@ -1997,14 +2076,11 @@ EX void reverse_transparent_walls() {
EX void draw_main() {
DEBBI(DF_GRAPH, ("draw_main"));
if(sphere && GDIM == 3 && pmodel == mdPerspective) {
if(sphere && GDIM == 3 && pmodel == mdPerspective && !stretch::in() && !ray::in_use) {
if(ray::in_use && !ray::comparison_mode) {
ray::cast();
reset_projection();
/* currently incompatible with primitive-based renderer */
/* also not implemented in stretch */
if(stretch::factor) return;
}
#if CAP_GL

View File

@ -1573,10 +1573,13 @@ EX void enable_flat_model() {
#if HDR
/** \brief enable the 'flat' model for drawing HUD. Use RAII so it will be switched back later */
namespace stretch { extern ld factor; }
struct flat_model_enabler {
projection_configuration bak;
flat_model_enabler() { bak = pconf; enable_flat_model(); }
~flat_model_enabler() { pconf = bak; calcparam(); }
ld sf;
flat_model_enabler() { bak = pconf; sf = stretch::factor; stretch::factor = 0; enable_flat_model(); }
~flat_model_enabler() { pconf = bak; stretch::factor = sf; calcparam(); }
};
#endif

View File

@ -2404,6 +2404,129 @@ EX namespace stretch {
h = itranslate(at) * h;
return h[0] * h[0] + h[1] * h[1] + h[2] * h[2];
}
EX vector<hyperpoint> inverse_exp_all(hyperpoint h, int generations) {
vector<hyperpoint> res;
if(stretch::factor == 0) {
ld d = hypot_d(3, h);
if(h[3] >= 1 || h[3] <= -1|| d == 0) return res;
ld a = acos(h[3]);
res.push_back(point31(h[0] * a / d, h[1] * a / d, h[2] * a / d));
a = a - 2 * M_PI;
res.push_back(point31(h[0] * a / d, h[1] * a / d, h[2] * a / d));
return res;
}
ld xy = hypot_d(2, h);
ld SV = stretch::not_squared();
ld base_min_a = asin(xy);
ld base_max_a = M_PI - base_min_a;
ld seek = M_PI/2-atan2(h[3], h[2]);
auto ang = [&] (ld a) {
ld rp = xy / sin(a);
ld co = abs(rp) >= 1 ? 0 : sqrt(1-rp*rp);
return atan2(co * sin(a), cos(a)) - co * (1 - 1/SV/SV) * a;
// while(a0 > M_PI) a0 -= 2 * M_PI;
// while(a0 < -M_PI) a0 += 2 * M_PI;
};
for(int shift=-generations; shift<generations; shift++) {
ld min_a = base_min_a + M_PI * shift;
ld max_a = base_max_a + M_PI * shift;
ld ang_min = ang(min_a);
ld ang_max = ang(max_a);
for(int mi=0; mi<2; mi++) {
// 0 : minimum, 1 : maximum
ld tl = min_a, tr = max_a;
for(int it=0; it<20; it++) {
ld t1 = tl * .51 + tr * .49;
ld t2 = tl * .49 + tr * .51;
if((ang(t1) < ang(t2)) == mi)
tr = t1;
else
tl = t2;
}
ld extreme = (tl + tr) / 2;
ld ang_extreme = ang(extreme);
for(int t=0; t<2; t++) {
ld mmin = t == 0 ? min_a : extreme;
ld mmax = t == 0 ? extreme : max_a;
ld vmin = t == 0 ? ang_min : ang_extreme;
ld vmax = t == 0 ? ang_extreme : ang_max;
// make it increasing
if(t != mi) swap(mmin, mmax), swap(vmin, vmax);
// println(hlog, "*** ", mi, t, " ** ", tie(min_a, ang_min), tie(extreme, ang_extreme), tie(max_a, ang_max), " -> ", vmin, " to ", vmax);
int cmin = ceil((vmin - seek) / 2 / M_PI);
int cmax = floor((vmax - seek) / 2 / M_PI);
for(int c = cmin; c <= cmax; c++) {
ld cseek = seek + c * 2 * M_PI;
for(int it=0; it<40; it++) {
ld a = (mmin + mmax) / 2;
ld cros = ang(a);
if(cros > cseek) mmax = a; else mmin = a;
}
ld a = (mmin + mmax) / 2;
ld r = asin_clamp( xy / sin(a) );
ld z_part = 1;
ld x_part = SV * tan(r);
ld db = hypot(x_part, z_part);
x_part /= db;
z_part /= db;
ld alpha = atan2(-h[1], h[0]);
ld z = cos(r) * (1 - 1/SV/SV);
ld u = z * a;
ld r_angle = alpha + u;
ld len = a * hypot(sin_auto(r), cos_auto(r)/SV);
auto answer = point3(cos(r_angle) * x_part * len, -sin(r_angle) * x_part * len, z_part * len);
// int id = (shift << 10) + (mi << 9) + (t << 8) + c;
/*
auto f = formula_exp(answer);
ld err = sqhypot_d(4, f - h);
println(hlog, "************************* ", answer, ": error = ", err, " id = ", id, " params = ", tie(shift, mi, t, c));
*/
res.emplace_back(answer);
}
}
}
}
return res;
}
EX }
EX namespace nisot {

View File

@ -248,7 +248,7 @@ shared_ptr<glhr::GLprogram> write_shader(flagtype shader_flags) {
shader_flags |= SF_PERS3 | SF_DIRECT;
if(hyperbolic)
distfun = "acosh(t[3])", treset = true;
else if(euclid || nonisotropic)
else if(euclid || nonisotropic || stretch::in() || (sphere && ray::in_use))
distfun = "length(t.xyz)", treset = true;
else {
if(spherephase & 4) coordinator += "t = -t;\n";