GPU-лучевое литье (однопроходное) с трехмерными текстурами в сферических координатах - PullRequest
2 голосов
/ 05 апреля 2019

Я реализую алгоритм объемного рендеринга "GPU лучевая передача за один проход".Для этого я использовал массив значений интенсивности с плавающей точкой в ​​качестве 3d-текстур (эти 3d-текстуры описывают регулярную 3d-сетку в сферических координатах).

Здесь приведен пример значений массива:

   75.839354473071637,     
   64.083049468866022,    
   65.253933716444365,     
   79.992431196592577,     
   84.411485976957096,     
   0.0000000000000000,     
   82.020319431382831,     
   76.808403454586994,     
   79.974774618246158,     
   0.0000000000000000,     
   91.127273013466336,     
   84.009956557448433,     
   90.221356094672814,     
   87.567422484025627,     
   71.940263118478072,     
   0.0000000000000000,     
   0.0000000000000000,     
   74.487058398181944,
   ..................,
   ..................

(Вот полные данные: [ссылка] (https://drive.google.com/file/d/1lbXzRucUseF-ITzFgxqeLTd0WglJJOoz/view?usp=sharing))

размеры сферической сетки: (r, theta, phi) = (384,15,768), и это формат ввода для загрузки текстур:

glTexImage3D(GL_TEXTURE_3D, 0, GL_R16F, 384, 15, 768, 0, GL_RED, GL_FLOAT, dataArray)

И это изображение моей визуализации:

image

Проблема в том, что визуализация должна быть диском,или, по крайней мере, похожую форму.

Я думаю, что проблема в том, что я неправильно указываю координаты для текстур (в сферических координатах).

это код вершинного шейдера:

  #version 330 core

layout(location = 0) in vec3 vVertex; //object space vertex position

//uniform
 uniform mat4 MVP;   //combined modelview projection matrix

 smooth out vec3 vUV; //3D texture coordinates for texture lookup in   the fragment shader

void main()
{  
    //get the clipspace position 
     gl_Position = MVP*vec4(vVertex.xyz,1);

    //get the 3D texture coordinates by adding (0.5,0.5,0.5) to the object space 
    //vertex position. Since the unit cube is at origin (min: (-0.5,-0.5,-0.5) and max: (0.5,0.5,0.5))
    //adding (0.5,0.5,0.5) to the unit cube object space position gives us values from (0,0,0) to 
    //(1,1,1)
    vUV = vVertex + vec3(0.5);
}

и это код шейдера фрагмента:

  #version 330 core

layout(location = 0) out vec4 vFragColor;   //fragment shader output

smooth in vec3 vUV;             //3D texture coordinates  form vertex shader 
                                 //interpolated by rasterizer

//uniforms
uniform sampler3D   volume;     //volume dataset
uniform vec3        camPos;     //camera position
uniform vec3        step_size;  //ray step size 




//constants
const int MAX_SAMPLES = 300;    //total samples for each ray march step
const vec3 texMin = vec3(0);    //minimum texture access coordinate
const vec3 texMax = vec3(1);    //maximum texture access coordinate





    vec4 colour_transfer(float intensity)
{

    vec3 high = vec3(100.0, 20.0, 10.0);
   // vec3 low = vec3(0.0, 0.0, 0.0);
   float alpha = (exp(intensity) - 1.0) / (exp(1.0) - 1.0);
   return vec4(intensity * high, alpha);

}



void main()
{ 
//get the 3D texture coordinates for lookup into the volume dataset
vec3 dataPos = vUV;


//Getting the ray marching direction:
//get the object space position by subracting 0.5 from the
//3D texture coordinates. Then subtraact it from camera position
//and normalize to get the ray marching direction
vec3 geomDir = normalize((vUV-vec3(0.5)) - camPos); 

//multiply the raymarching direction with the step size to get the
//sub-step size we need to take at each raymarching step
vec3 dirStep = geomDir * step_size; 

//flag to indicate if the raymarch loop should terminate
bool stop = false; 

//for all samples along the ray
for (int i = 0; i < MAX_SAMPLES; i++) {
    // advance ray by dirstep
    dataPos = dataPos + dirStep;



    stop = dot(sign(dataPos-texMin),sign(texMax-dataPos)) < 3.0;

    //if the stopping condition is true we brek out of the ray marching loop
    if (stop) 
        break;
    // data fetching from the red channel of volume texture
    float sample = texture(volume, dataPos).r;  

     vec4 c = colour_transfer(sample);

    vFragColor.rgb = c.a * c.rgb + (1 - c.a) * vFragColor.a * vFragColor.rgb;
    vFragColor.a = c.a + (1 - c.a) * vFragColor.a;

    //early ray termination
    //if the currently composited colour alpha is already fully saturated
    //we terminated the loop
    if( vFragColor.a>0.99)
        break;
} 


}

Как мне указать координаты, для которых я буду визуализировать информацию в 3D-текстурах, в сферических кординатах?

ОБНОВЛЕНИЕ:

Вершинный шейдер:

#version 330 core

layout(location = 0) in vec3 vVertex; //object space vertex position

//uniform
uniform mat4 MVP;   //combined modelview projection matrix

smooth out vec3 vUV; //3D texture coordinates for texture lookup in the             fragment shader



void main()
{  
    //get the clipspace position 
    gl_Position = MVP*vec4(vVertex.xyz,1);

     //get the 3D texture coordinates by adding (0.5,0.5,0.5) to the object     space 
    //vertex position. Since the unit cube is at origin (min: (-0.5,-   0.5,-0.5) and max: (0.5,0.5,0.5))
    //adding (0.5,0.5,0.5) to the unit cube object space position gives    us values from (0,0,0) to 
//(1,1,1)
vUV = vVertex + vec3(0.5);
}

И фрагментt shader:

#version 330 core
#define Pi 3.1415926535897932384626433832795

layout(location = 0) out vec4 vFragColor;   //fragment shader output

smooth in vec3 vUV;             //3D texture coordinates form vertex shader 
                            //interpolated by rasterizer

//uniforms
uniform sampler3D   volume;     //volume dataset
uniform vec3        camPos;     //camera position
uniform vec3        step_size;  //ray step size 




//constants
const int MAX_SAMPLES = 200;    //total samples for each ray march step
const vec3 texMin = vec3(0);    //minimum texture access coordinate
const vec3 texMax = vec3(1);    //maximum texture access coordinate

// transfer function that asigned a color and alpha from sample    intensity
vec4 colour_transfer(float intensity)
{

    vec3 high = vec3(100.0, 20.0, 10.0);
    // vec3 low = vec3(0.0, 0.0, 0.0);
    float alpha = (exp(intensity) - 1.0) / (exp(1.0) - 1.0);

    return vec4(intensity * high, alpha);

}


// this function transform vector in spherical coordinates from cartesian
vec3 cart2Sphe(vec3 cart){
    vec3 sphe;
    sphe.x = sqrt(cart.x*cart.x+cart.y*cart.y+cart.z*cart.z);
    sphe.z = atan(cart.y/cart.x);
    sphe.y = atan(sqrt(cart.x*cart.x+cart.y*cart.y)/cart.z);
    return sphe;
}


void main()
{ 
    //get the 3D texture coordinates for lookup into the volume dataset
    vec3 dataPos = vUV;


    //Getting the ray marching direction:
    //get the object space position by subracting 0.5 from the
    //3D texture coordinates. Then subtraact it from camera position
    //and normalize to get the ray marching direction
    vec3 vec=(vUV-vec3(0.5)); 
    vec3 spheVec=cart2Sphe(vec); // transform position to spherical
    vec3 sphePos=cart2Sphe(camPos); //transform camPos to spherical
    vec3 geomDir= normalize(spheVec-sphePos); // ray direction


    //multiply the raymarching direction with the step size to get the
    //sub-step size we need to take at each raymarching step
    vec3 dirStep = geomDir * step_size ; 
    //flag to indicate if the raymarch loop should terminate

    //for all samples along the ray
    for (int i = 0; i < MAX_SAMPLES; i++) {
        // advance ray by dirstep
        dataPos = dataPos + dirStep;


        float sample;

        convert texture coordinates 
        vec3 spPos;
        spPos.x=dataPos.x/384;
        spPos.y=(dataPos.y+(Pi/2))/Pi;
        spPos.z=dataPos.z/(2*Pi);

        // get value from texture
         sample = texture(volume,dataPos).r;
         vec4 c = colour_transfer(sample)



        // alpha blending  function
         vFragColor.rgb = c.a * c.rgb + (1 - c.a) * vFragColor.a *      vFragColor.rgb;
        vFragColor.a = c.a + (1 - c.a) * vFragColor.a;


        if( vFragColor.a>1.0)
        break;
    } 

    // vFragColor.rgba = texture(volume,dataPos);
}

это точки, которые генерируют граничный куб:

 glm::vec3 vertices[8] = {glm::vec3(-0.5f, -0.5f, -0.5f),
                                                 glm::vec3(0.5f, -0.5f,   -0.5f),
                                                 glm::vec3(0.5f, 0.5f, -0.5f),
                                                 glm::vec3(-0.5f, 0.5f, -0.5f),
                                                 glm::vec3(-0.5f, -0.5f, 0.5f),
                                                 glm::vec3(0.5f, -0.5f, 0.5f),
                                                 glm::vec3(0.5f, 0.5f, 0.5f),
                                                 glm::vec3(-0.5f, 0.5f, 0.5f)};



    //unit cube indices
    GLushort cubeIndices[36] = {0, 5, 4,
                                                        5, 0, 1,
                                                        3, 7, 6,
                                                        3, 6, 2,
                                                        7, 4, 6,
                                                        6, 4, 5,
                                                        2, 1, 3,
                                                        3, 1, 0,
                                                        3, 0, 7,
                                                        7, 0, 4,
                                                        6, 5, 2,
                                                        2, 5, 1};

это визуализация, которую он генерирует:

Imgur Imgur1

1 Ответ

2 голосов
/ 08 апреля 2019

Я не знаю, что и как вы делаете.Есть много методов и конфигураций, которые могут их достичь.Я обычно использую однопроходный рендер, покрывающий экран / представление, в то время как геометрия / сцена передается как текстура.Поскольку у вас есть ваш объект в 3D текстуре, то я думаю, что вы должны пойти по этому пути.Вот как это делается (Предполагается, что перспектива, однородная сферическая воксельная сетка как трехмерная текстура):

  1. Код стороны процессора

    просто визуализировать один QUAD охватывающий сцену / вид.Чтобы сделать это более простым и точным, я рекомендую вам использовать вашу локальную систему координат сферы для матрицы камеры, которая передается шейдерам (это значительно облегчит вычисления пересечения луча / сферы).

  2. Вершина

    здесь вы должны привести / вычислить положение и направление луча для каждой вершины и передать его фрагменту, чтобы он интерполировался для каждого пикселя на экране / виде.

    Таким образом, камера описывается своим положением (фокус) и направлением обзора (обычно ось Z в перспективе OpenGL ).Луч направляется из фокальной точки (0,0,0) в локальных координатах камеры в плоскость znear (x,y,-znear) также в локальных координатах камеры.Где x,y - это положение пикселя на экране с коррекцией соотношения сторон, если экран / вид не квадратный.

    Таким образом, вы просто конвертируете эти две точки в локальные координаты сферы (все еще декартовы).

    Направление луча - это просто вычитание двух точек ...

  3. Фрагмент

    сначала нормализовать направление луча, пройденное от вершины (в связи синтерполяция не будет единичным вектором).После этого просто проверьте пересечение луча / сферы для каждого радиуса сетки вокселей сферы от внешнего к внутреннему, чтобы проверить сферы от rmax до rmax/n, где rmax - максимальный радиус, который может иметь ваша 3D-текстура, а n - идентификаторразрешение по оси, соответствующей радиусу r.

    . При каждом попадании конвертировать декартово положение пересечения в Сферические координаты .Преобразуйте их в координаты текстуры s,t,p, извлеките интенсивность Вокселя и примените ее к цвету (как зависит от того, что и как вы визуализируете).

    Так что, если ваши координаты текстуры (r,theta,phi) при условии phiэто долгота и углы нормализованы до <-Pi,Pi> и <0,2*Pi>, а rmax - это максимальный радиус 3D-текстуры:

    s = r/rmax
    t = (theta+(Pi/2))/Pi
    p = phi/(2*PI)
    

    Если ваша сфера не прозрачна, остановитесь на первом ударе синтенсивность пустого вокселя.В противном случае обновите начальную позицию луча и делайте всю эту пулю снова, пока луч не выйдет из сцены BBOX или не произойдет пересечение.

    Вы также можете добавить закон Снелла (добавить рефракцию отражения), разделив луч на попадания границы объекта..

Вот некоторые связанные QA s, использующие эту технику или имеющие действительную информацию, которая поможет вам достичь этого:

[Edit1] пример (после окончательной публикации входной 3D-текстуры

Поэтому, когда я помещаю всеВсе вышеперечисленное (и в комментариях) вместе с этим я придумываю.

Код стороны процессора:

//---------------------------------------------------------------------------
//--- GLSL Raytrace system ver: 1.000 ---------------------------------------
//---------------------------------------------------------------------------
#ifndef _raytrace_spherical_volume_h
#define _raytrace_spherical_volume_h
//---------------------------------------------------------------------------
class SphericalVolume3D
    {
public:
    bool _init;         // has been initiated ?
    GLuint txrvol;      // SphericalVolume3D texture at GPU side
    int xs,ys,zs;

    float eye[16];      // direct camera matrix
    float aspect,focal_length;

    SphericalVolume3D()    { _init=false; txrvol=-1; xs=0; ys=0; zs=0; aspect=1.0; focal_length=1.0; }
    SphericalVolume3D(SphericalVolume3D& a)   { *this=a; }
    ~SphericalVolume3D()   { gl_exit(); }
    SphericalVolume3D* operator = (const SphericalVolume3D *a) { *this=*a; return this; }
    //SphericalVolume3D* operator = (const SphericalVolume3D &a) { ...copy... return this; }

    // init/exit
    void gl_init();
    void gl_exit();

    // render
    void glsl_draw(GLint prog_id);
    };
//---------------------------------------------------------------------------
void SphericalVolume3D::gl_init()
    {
    if (_init) return; _init=true;
    // load 3D texture from file into CPU side memory
    int hnd,siz; BYTE *dat;
    hnd=FileOpen("Texture3D_F32.dat",fmOpenRead);
    siz=FileSeek(hnd,0,2);
        FileSeek(hnd,0,0);
    dat=new BYTE[siz];
        FileRead(hnd,dat,siz);
        FileClose(hnd);
    if (0)
        {
        int i,n=siz/sizeof(GLfloat);
        GLfloat *p=(GLfloat*)dat;
        for (i=0;i<n;i++) p[i]=100.5;
        }

    // copy it to GPU as 3D texture
//  glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE);
//  glClampColorARB(GL_CLAMP_READ_COLOR_ARB, GL_FALSE);
//  glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE);
    glGenTextures(1,&txrvol);
    glEnable(GL_TEXTURE_3D);
    glBindTexture(GL_TEXTURE_3D,txrvol);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER,GL_NEAREST);
    glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE);
    xs=384;
    ys= 15;
    zs=768;
    glTexImage3D(GL_TEXTURE_3D, 0, GL_R16F, xs,ys,zs, 0, GL_RED, GL_FLOAT, dat);
    glBindTexture(GL_TEXTURE_3D,0);
    glDisable(GL_TEXTURE_3D);
    delete[] dat;
    }
//---------------------------------------------------------------------------
void SphericalVolume3D::gl_exit()
    {
    if (!_init) return; _init=false;
    glDeleteTextures(1,&txrvol);
    }
//---------------------------------------------------------------------------
void SphericalVolume3D::glsl_draw(GLint prog_id)
    {
    GLint ix;
    const int txru_vol=0;
    glUseProgram(prog_id);
    // uniforms
    ix=glGetUniformLocation(prog_id,"zoom"        ); glUniform1f(ix,1.0);
    ix=glGetUniformLocation(prog_id,"aspect"      ); glUniform1f(ix,aspect);
    ix=glGetUniformLocation(prog_id,"focal_length"); glUniform1f(ix,focal_length);
    ix=glGetUniformLocation(prog_id,"vol_xs"      ); glUniform1i(ix,xs);
    ix=glGetUniformLocation(prog_id,"vol_ys"      ); glUniform1i(ix,ys);
    ix=glGetUniformLocation(prog_id,"vol_zs"      ); glUniform1i(ix,zs);
    ix=glGetUniformLocation(prog_id,"vol_txr"     ); glUniform1i(ix,txru_vol);
    ix=glGetUniformLocation(prog_id,"tm_eye"      ); glUniformMatrix4fv(ix,1,false,eye);

    glActiveTexture(GL_TEXTURE0+txru_vol);
    glEnable(GL_TEXTURE_3D);
    glBindTexture(GL_TEXTURE_3D,txrvol);

    // this should be a VAO/VBO
    glColor4f(1.0,1.0,1.0,1.0);
    glBegin(GL_QUADS);
    glVertex2f(-1.0,-1.0);
    glVertex2f(-1.0,+1.0);
    glVertex2f(+1.0,+1.0);
    glVertex2f(+1.0,-1.0);
    glEnd();

    glActiveTexture(GL_TEXTURE0+txru_vol);
    glBindTexture(GL_TEXTURE_3D,0);
    glDisable(GL_TEXTURE_3D);
    glUseProgram(0);
    }
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------

вызовите init при запуске приложения, когда GL ужеинициализируется, завершается до выхода из приложения, пока GL все еще работает, и рисует при необходимости ... Код основан на C ++ / VCL , поэтому перенос в вашу среду (доступ к файлам, строки и т. д.) Я также использую 3DТекстура в двоичном виде при загрузке 85-мегабайтного ASCII-файла - это слишком много, на мой вкус.

Vertex:

//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
uniform float aspect;
uniform float focal_length;
uniform float zoom;
uniform mat4x4 tm_eye;
layout(location=0) in vec2 pos;

out smooth vec3 ray_pos;    // ray start position
out smooth vec3 ray_dir;    // ray start direction
//------------------------------------------------------------------
void main(void)
    {
    vec4 p;
    // perspective projection
    p=tm_eye*vec4(pos.x/(zoom*aspect),pos.y/zoom,0.0,1.0);
    ray_pos=p.xyz;
    p-=tm_eye*vec4(0.0,0.0,-focal_length,1.0);
    ray_dir=normalize(p.xyz);
    gl_Position=vec4(pos,0.0,1.0);
    }
//------------------------------------------------------------------

это более или менее копия ссылки объемного трассировщика лучей.

Фрагмент:

//------------------------------------------------------------------
#version 420 core
//------------------------------------------------------------------
// Ray tracer ver: 1.000
//------------------------------------------------------------------
in smooth vec3      ray_pos;    // ray start position
in smooth vec3      ray_dir;    // ray start direction
uniform int         vol_xs,     // texture resolution
                    vol_ys,
                    vol_zs;
uniform sampler3D   vol_txr;    // scene mesh data texture
out layout(location=0) vec4 frag_col;
//---------------------------------------------------------------------------
// compute length of ray(p0,dp) to intersection with ellipsoid((0,0,0),r) -> view_depth_l0,1
// where r.x is elipsoid rx^-2, r.y = ry^-2 and r.z=rz^-2
float view_depth_l0=-1.0,view_depth_l1=-1.0;
bool _view_depth(vec3 _p0,vec3 _dp,vec3 _r)
    {
    double a,b,c,d,l0,l1;
    dvec3 p0,dp,r;
    p0=dvec3(_p0);
    dp=dvec3(_dp);
    r =dvec3(_r );
    view_depth_l0=-1.0;
    view_depth_l1=-1.0;
    a=(dp.x*dp.x*r.x)
     +(dp.y*dp.y*r.y)
     +(dp.z*dp.z*r.z); a*=2.0;
    b=(p0.x*dp.x*r.x)
     +(p0.y*dp.y*r.y)
     +(p0.z*dp.z*r.z); b*=2.0;
    c=(p0.x*p0.x*r.x)
     +(p0.y*p0.y*r.y)
     +(p0.z*p0.z*r.z)-1.0;
    d=((b*b)-(2.0*a*c));
    if (d<0.0) return false;
    d=sqrt(d);
    l0=(-b+d)/a;
    l1=(-b-d)/a;
    if (abs(l0)>abs(l1)) { a=l0; l0=l1; l1=a; }
    if (l0<0.0)          { a=l0; l0=l1; l1=a; }
    if (l0<0.0) return false;
    view_depth_l0=float(l0);
    view_depth_l1=float(l1);
    return true;
    }
//---------------------------------------------------------------------------
const float pi =3.1415926535897932384626433832795;
const float pi2=6.2831853071795864769252867665590;
float atanxy(float x,float y) // atan2 return < 0 , 2.0*M_PI >
        {
        int sx,sy;
        float a;
        const float _zero=1.0e-30;
        sx=0; if (x<-_zero) sx=-1; if (x>+_zero) sx=+1;
        sy=0; if (y<-_zero) sy=-1; if (y>+_zero) sy=+1;
        if ((sy==0)&&(sx==0)) return 0;
        if ((sx==0)&&(sy> 0)) return 0.5*pi;
        if ((sx==0)&&(sy< 0)) return 1.5*pi;
        if ((sy==0)&&(sx> 0)) return 0;
        if ((sy==0)&&(sx< 0)) return pi;
        a=y/x; if (a<0) a=-a;
        a=atan(a);
        if ((x>0)&&(y>0)) a=a;
        if ((x<0)&&(y>0)) a=pi-a;
        if ((x<0)&&(y<0)) a=pi+a;
        if ((x>0)&&(y<0)) a=pi2-a;
        return a;
        }
//---------------------------------------------------------------------------
void main(void)
    {
    float a,b,r,_rr,c;
    const float dr=1.0/float(vol_ys);       // r step
    const float saturation=1000.0;          // color saturation voxel value
    vec3  rr,p=ray_pos,dp=normalize(ray_dir);
    for (c=0.0,r=1.0;r>1e-10;r-=dr)         // check all radiuses inwards
        {
        _rr=1.0/(r*r); rr=vec3(_rr,_rr,_rr);
        if (_view_depth(p,dp,rr))           // if ray hits sphere
            {
            p+=view_depth_l0*dp;            // shift ray start position to the hit
            a=atanxy(p.x,p.y);              // comvert to spherical a,b,r
            b=asin(p.z/r);
            if (a<0.0) a+=pi2;              // correct ranges...
            b+=0.5*pi;
            a/=pi2;
            b/=pi;
            // here do your stuff
            c=texture(vol_txr,vec3(b,r,a)).r;// fetch voxel
            if (c>saturation){ c=saturation; break; }
            break;
            }
        }
    c/=saturation;

    frag_col=vec4(c,c,c,1.0);
    }
//--------------------------------------------------------------------------- 

это небольшая модификация ссылки объемного трассировщика лучей.

Обратите внимание, что я предполагаю, что оси внутри текстуры:

latitude,r,longitude

, подразумеваемые разрешениями (долгота должна быть двойным разрешением широты), поэтому еслине совпадает с вашими данными, просто переупорядочьте оси во фрагменте ... Я понятия не имею, что означают значения ячейки Вокселя, поэтому я суммирую их как интенсивность / плотность для окончательного цвета, и как только сумма насыщенности будет достигнута, остановите трассировку лучей, но вместо этого вы должнываши вычисления вы намереваетесь.

Вот предварительный просмотр:

preview

Я использовал эту матрицу камеры eyeдля этого:

// globals
SphericalVolume3D vol;
// init (GL must be already working)
vol.gl_init();

// render
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_CULL_FACE);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-2.5);
glGetFloatv(GL_MODELVIEW_MATRIX,vol.eye);
vol.glsl_draw(prog_id);

glFlush();
SwapBuffers(hdc);

// exit (GL must be still working)
vol.gl_init();

Попадание луча / сферы работает правильно, позиция удара в сферических координатах работает так, как должно, поэтому остается только порядок осей и цветовая арифметика ...

...