View Single Post
Old 06-29-2016, 03:50 PM   #30
Justin
Administrator
 
Justin's Avatar
 
Join Date: Jan 2005
Location: NYC
Posts: 15,721
Default

Here's a video processor that is cleaned up and has fewer stitching artifacts:
Code:
//equirectangular 360 panner
//@param1:fov_ang 'fov' 90 20 170 90 1
//@param2:x_ang 'yaw' 0 -180 180 0 1
//@param3:y_ang 'pitch' 0 -90 90 0 1
//@param4:z_ang 'roll' 0 -180 180 0 1

project_w=1920;
project_h=1080;
xdiv=ydiv=100; // subdivision (quality) 10-200 is usable
filter=1; // bilinear filtering?
xscale=1; // -1 to flip yaw
yscale=1; // -1 to flip pitch
zscale=1; // -1 to flip roll

function matrix_make_rotate(matrix, m, d) global() local(m2) (
  memset(matrix,0,16);
  matrix[m*5-5] = matrix[15] = 1.0;
  m2 = ((m%=3)+1)%3;
  matrix[m2*5]=matrix[m*5]=cos(d);
  matrix[m2*4+m]=-(matrix[m*4+m2]=sin(d));
);

function matrix_make_xlate(matrix, x, y, z) global() (
  memset(matrix,0,16);
  matrix[0]=matrix[5]=matrix[10]=matrix[15]=1;
  matrix[3]=x; matrix[7]=y; matrix[11]=z;
);

function matrix_multiply(dest,src) global() local(s0,s1,s2,s3) (
  loop(4,
    s0=dest[0]; s1=dest[1]; s2=dest[2]; s3=dest[3];
    loop(4, dest[0] = s0*src[0]+s1*src[4]+s2*src[8]+s3*src[12]; dest+=1; src+=1; );
    src -= 4;
  );
);

function matrix_apply(x,y,z, m, vec*) global() (
  vec.x = x*m[0] + y*m[1] + z*m[2] + m[3];
  vec.y = x*m[4] + y*m[5] + z*m[6] + m[7];
  vec.z = x*m[8] + y*m[9] + z*m[10] + m[11];
);

function vector_project(vv*, s*) global(srcw,srch) (
  s.y = srch * (0.5 + asin(vv.y / sqrt(vv.x*vv.x+vv.y*vv.y+vv.z*vv.z)) * (1/$pi));
  s.x = srcw * (0.5 + atan2(vv.x,vv.z) * (1 / (2*$pi)));
);

function centerx(sm*, v*) global(srcw) (
  v.x < sm.x-srcw*.5 ? ( v.x += srcw; 2; ) : v.x > sm.x+srcw*.5 ? ( v.x -= srcw; 1; );
);

gfx_img_resize(-1,project_w,project_h);
input_info(0,srcw,srch);

gfx_mode=filter ? 0x100 : 0;

screen_z = project_w/tan(fov_ang * 0.5 * $pi / 180);
dxpos=project_w/(xdiv-1);
dypos=project_h/(ydiv-1);
ypos = 0;

matrix1 = 0; matrix2 = matrix1 + 16;
matrix_make_rotate(matrix1,2,xscale * x_ang * -$pi / 180);
matrix_make_rotate(matrix2,1,yscale * y_ang * $pi / 180); matrix_multiply(matrix1,matrix2); 
matrix_make_rotate(matrix2,3,z_ang * -$pi / 180);         matrix_multiply(matrix1,matrix2);
matrix_make_xlate(matrix2,project_w*-.5,project_h*-.5,0); matrix_multiply(matrix1,matrix2);

loop(ydiv,
  y1=(ypos)&0xffffe;
  y2=(ypos+=dypos)&0xffffe;
  idy = 1/(y2-y1);
  xpos = 0;

  loop(xdiv,
    x1=(xpos)&0xffffe;
    x2=(xpos+=dxpos)&0xffffe;
    idx = 1/(x2-x1);

    matrix_apply(x1,y1,screen_z,matrix1,vv); vector_project(vv, s1);
    matrix_apply(x2,y1,screen_z,matrix1,vv); vector_project(vv, s2);
    matrix_apply(x1,y2,screen_z,matrix1,vv); vector_project(vv, s3);
    matrix_apply(x2,y2,screen_z,matrix1,vv); vector_project(vv, s4);

    a=centerx(s1,s2)|centerx(s1,s3)|centerx(s1,s4);

    dsdx = (s2.x-s1.x) * idx;
    dtdx = (s2.y-s1.y) * idx;
    dsdy = (s3.x-s1.x) * idy;
    dtdy = (s3.y-s1.y) * idy;
    dsdx2 = (s4.x-s3.x) * idx;
    dtdx2 = (s4.y-s3.y) * idx;
    dsdxdy = (dsdx2-dsdx) * idy;
    dtdxdy =  (dtdx2-dtdx) * idy;

    gfx_deltablit(0, x1,y1, x2-x1,y2-y1, s1.x,s1.y, dsdx, dtdx, dsdy, dtdy, dsdxdy, dtdxdy);
    (a&1) ? gfx_deltablit(0, x1,y1, x2-x1,y2-y1, s1.x+srcw,s1.y, dsdx, dtdx, dsdy, dtdy, dsdxdy, dtdxdy);
    (a&2) ? gfx_deltablit(0, x1,y1, x2-x1,y2-y1, s1.x-srcw,s1.y, dsdx, dtdx, dsdy, dtdy, dsdxdy, dtdxdy);
  );
);
(edited with simplifications -- you can now configure the output dimensions in the code easily, and flip the x/y axes, etc)
(edited: added roll support)

Last edited by Justin; 06-29-2016 at 09:10 PM.
Justin is offline   Reply With Quote