Кастинг лучей GPU (однопроходный) с 3D-текстурами в сферических координатах

Я реализую алгоритм объемного рендеринга «GPU ray casting single pass». Для этого я использовал плавающий массив значений интенсивности в качестве 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, тета, фи) = (384,15,768), и это входной формат для загрузки текстур:

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

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

изображение

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

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

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

  #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);
}

И фрагментный шейдер:

#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 Имгур1


person sebastian pinto    schedule 05.04.2019    source источник
comment
Вам нужно преобразовать декартовы координаты в полярные координаты. Как это сделать, зависит от положения и размера вашего мяча.   -  person Nico Schertler    schedule 05.04.2019
comment
Я вижу некоторые конфликты/несоответствия в вашем тексте: объемный рендеринг предполагает объект с объемом либо граничным представлением, либо сеткой, полярные координаты описывают плоскость !!! и (r,theta,phi) предлагают сферические координаты ... так что это за 3D-текстура? и что такое оси ... как будто они где r,theta,phi это не имело бы смысла, поскольку радиус должен быть значением ячейки, а не осью доступа ... Как организованы данные? Как/что вы рендерите защитный экран Quad или что-то еще? какие лучи и отбрасываются откуда как? вывести все из чужого неработающего кода сложно   -  person Spektre    schedule 05.04.2019
comment
во-вторых, если текстура покрывает весь объем, а не только поверхность, тогда она может быть r,theta,phi, но все же не полярной ... но эта организация будет иметь очень разную плотность вокселей на каждый r, что тратит много памяти. Как только вы поймете, какую систему координат вы получили, преобразуйте положение потенциального попадания каждого луча в целевые координаты, извлеките текстуру и визуализируйте ... поэтому итерируйте луч в декартовой системе, но извлекайте в полярной/цилиндрической/сферической/???. См. Изогнутый шейдер матового стекла?   -  person Spektre    schedule 05.04.2019
comment
Координаты в сферической системе координат, я собираюсь отредактировать это в своем вопросе.   -  person sebastian pinto    schedule 05.04.2019
comment
Трехмерные текстуры описывают объект в форме диска в сферических координатах, я намерен визуализировать этот диск в граничном кубе, возможно ли это?   -  person sebastian pinto    schedule 05.04.2019
comment
@sebastianpinto 1. чтобы уведомить пользователя nick, вам нужно добавить @nick к вашему комментарию (работает только для 1 пользователя на комментарий, присутствующий в текущей ветке). 2. да возможно сделает ответ с некоторыми намеками на то, как этого добиться (в комментарии было бы нечитабельно)   -  person Spektre    schedule 08.04.2019


Ответы (1)


Я не знаю, что и как вы рендерите. Есть много методов и конфигураций, которые могут их достичь. Обычно я использую однопроходный однократный четырехъядерный рендеринг, покрывающий экран/вид, в то время как геометрия/сцена передается как текстура. Поскольку у вас есть объект в 3D-текстуре, я думаю, вам тоже следует пойти по этому пути. Вот как это делается (предполагая перспективу, равномерную сферическую воксельную сетку в качестве 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, использующие этот метод или имеющие достоверную информацию, которые помогут вам достичь этого:

Пример [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-файла, на мой взгляд, слишком много.

Вершина:

//------------------------------------------------------------------
#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

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

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

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

Я использовал эту матрицу камеры 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();

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

person Spektre    schedule 08.04.2019
comment
Большое спасибо, я собираюсь проверить это решение, чтобы увидеть, работает ли оно - person sebastian pinto; 10.04.2019
comment
Я пытался выполнить шаги, но это не очень хорошо работает. я собираюсь обновить свой пост с новым результатом, применяя ваши шаги в вершинном и фрагментном шейдере. Есть что-то неправильное в моем коде?. В процессорной части я визуализировал граничную рамку и загружал 3D-текстуры, а также определял camPos и ​​размер шага, которые я устанавливал для юниформ-переменных в шейдеры. в шейдере Fragmen я вычисляю направление луча. - person sebastian pinto; 13.04.2019
comment
@sebastianpinto 1. на стороне процессора вы должны визуализировать только один плоский экран QUAD (4 x 2D-вершины, все комбинации +/-1), а не 3D-блок !!!. 2. В вершине вы вообще не вычисляете направление луча, vUV не имеет смысла, вы не можете вычислить координату текстуры в вершине (если я что-то не упустил) 3. фрагмент: используйте atan2 для вычисления угла долготы, а не atan, и убедитесь, что углы равны в правильных диапазонах, особенно широте, я не вижу никакого кода пересечения луча/сферы. 4. вы так и не поделились входной 3D текстурой, так что никто не может попробовать это закодировать... - person Spektre; 13.04.2019
comment
@sebastianpinto, если у вас нет atan2(y,x) (не уверен, реализовано ли это в GLSL или нет), вы можете использовать мой atanxy(x, y) вместо этого ... это то же самое, только операнды меняются местами. - person Spektre; 13.04.2019
comment
этот файл содержит наборы данных объема, формат для загрузки в буфер текстуры: ://drive.google.com/file/d/1lbXzRucUseF-ITzFgxqeLTd0WglJJOoz/view?usp=sharing" rel="nofollow noreferrer">drive.google.com/file/d/1lbXzRucUseF-ITzFgxqeLTd0WglJJOoz/) - person sebastian pinto; 13.04.2019
comment
@sebastianpinto см. [edit1] ... вы также должны поместить ссылку на 3D-текстуру в свой вопрос ... в исходном коде остался некоторый мертвый код отладки, поэтому игнорируйте его ... (вы знаете if(0) и закомментировали материал) - person Spektre; 13.04.2019
comment
привет спектр, извините за беспокойство еще раз, но я не могу выполнить код. Не могли бы вы прислать мне полный код? Я думаю, что проблема в моих зависимостях. Заранее спасибо и извините за неудобства. - person sebastian pinto; 17.04.2019
comment
@sebastianpinto привет. Единственное, чего не хватает в моем коде, — это Window (например, создание контекста GL, регистрация расширений и т. д., например, GLEW) и загрузка/компиляция/связывание шейдеров (которые у вас уже должны быть, иначе у вас не будет выходного изображения) в любом случае все который вы можете найти здесь: полный пример GL+GLSL+VAO/VBO C++. Я могу опубликовать небольшое демо, но я использую Borland/Embarcadero IDE, что означает, что вы не сможете скомпилировать его в MSVC++ или любой другой IDE без переноса, так что я не вижу смысла. - person Spektre; 17.04.2019
comment
@sebastianpinto Также не забудьте передать правильный prog_id функции отрисовки класса, это должен быть идентификатор скомпилированного/связанного шейдера. Единственный материал, который я использовал для этого, был gl_simple.h из ссылки в предыдущем комментарии, GLEW.h и GLEW.c (без DLL и OBJ), но у меня есть некоторые старые версии, более новые могут быть инициализированы по-другому, не обновлялись годами и GL, GLEXT, WGL заголовки для Win32/OpenGL). Также я смешиваю старый и новый API, поэтому, если у вас есть основной контекст GL, вам нужно переписать QUAD в VBO/VAO. Основной контекст GLSL в порядке... - person Spektre; 17.04.2019
comment
Я понимаю, я компилировал и запускал код для консоли в Linux. Я собираюсь исправить код для своей среды. - person sebastian pinto; 17.04.2019