使用 Delphi GLScene 进行 GLSL 光线投射

发布于 2025-01-09 08:49:34 字数 12421 浏览 1 评论 0原文

我使用 GLScene Texture3D 演示的修改版本,探索如何使用 GLScene 着色器。我可以让着色器工作,但不能让光线投射算法(单通道)工作。 在FormCreate中,指定了一个单位立方体:

//unit cube, for raycasting
  FVertexArray[0] := Vector3fMake(-0.5, -0.5, -0.5);
  FVertexArray[1] := Vector3fMake( 0.5, -0.5, -0.5);
  FVertexArray[2] := Vector3fMake( 0.5,  0.5, -0.5);
  FVertexArray[3] := Vector3fMake(-0.5,  0.5, -0.5);
  FVertexArray[4] := Vector3fMake(-0.5, -0.5,  0.5);
  FVertexArray[5] := Vector3fMake( 0.5, -0.5,  0.5);
  FVertexArray[6] := Vector3fMake( 0.5,  0.5,  0.5);
  FVertexArray[7] := Vector3fMake(-0.5,  0.5,  0.5);

该项目使用GLScene的TGLDirectOpenGL:

procedure TForm1.GLDirectOpenGLRender(Sender: TObject; var rci: TGLRenderContextInfo);

Var
  i : Integer;
  step : Single;
  z : Single;
  mat : TMatrix;
  v : TVector;
  vx, vy, vz : TAffineVector;

begin
  if M_3D_Texture.Handle = 0 then
    begin
      //Assert (GL_EXT_texture3D, 'Graphic card does not support 3D textures.');

      M_3D_Texture.AllocateHandle;

      gl.BindTexture (GL_TEXTURE_3D, M_3D_Texture.Handle);
      gl.TexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      gl.TexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      gl.TexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
      gl.TexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      gl.TexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      gl.TexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //GL_REPLACE);

      gl.TexImage3D (GL_TEXTURE_3D, 0, GL_RGBA8, M_Output_Texture_3D.X_Size, M_Output_Texture_3D.Y_Size, M_Output_Texture_3D.Z_Size, 0, M_Output_Texture_3D.Data_Type, GL_UNSIGNED_BYTE, PChar (M_Output_Texture_3D.Data));
    end;

  If M_Refresh = TRUE Then
    begin { then }
      M_Refresh := FALSE;
      Calculate_Transfer_function;
      gl.TexSubImage3D (GL_TEXTURE_3D, 0, 0, 0, 0, M_Output_Texture_3D.X_Size, M_Output_Texture_3D.Y_Size, M_Output_Texture_3D.Z_Size, M_Output_Texture_3D.Data_Type, GL_UNSIGNED_BYTE, PChar (M_Output_Texture_3D.Data));
    end; { then }

//--- added for glsl test
  if not initDGL then
  begin
    if Assigned(ProgHnd) then
    begin
      ProgHnd.Free;
    end;

    ProgHnd := TGLProgramHandle.CreateAndAllocate;

    ProgHnd.AddShader(TGLVertexShaderHandle,
      LoadAnsiStringFromFile('.\vert.glsl'));

    if not Raycasting_CB.Checked then
      ProgHnd.AddShader(TGLFragmentShaderHandle,
        LoadAnsiStringFromFile('.\slicing.frag.glsl'))
    else
      ProgHnd.AddShader(TGLFragmentShaderHandle,
        LoadAnsiStringFromFile('.\\raycast.frag.glsl'));


    if not ProgHnd.LinkProgram then
      raise Exception.Create(ProgHnd.InfoLog);

    initDGL := True;
  end;
//---

  gl.PushAttrib (GL_ENABLE_BIT);
  gl.PushMatrix;

  gl.Enable (GL_BLEND);
  gl.BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  //  glDisable (GL_CULL_FACE);
  //  glDisable (GL_LIGHTING);

//--- added for glsl test and raycasting
  if initDGL then
  begin
    ProgHnd.UseProgramObject;

    ProgHnd.UniformTextureHandle['avoxels', 0, ttTexture3D] := M_3D_Texture.Handle;

    if Raycasting_CB.Checked then
    begin
      //camera position in cube coordinates
      ProgHnd.Uniform3f['acamera'] := GLCube1.AbsoluteToLocal(GLCamera.AbsoluteAffinePosition);

      with M_Output_Texture_3D do
      begin
        ProgHnd.Uniform3f['astepsize'] := AffineVectorMake(1/X_Size, 1/Y_Size, 1/Z_Size);
      end;
    end;

    if not ProgHnd.ValidateProgram then
      raise Exception.Create(ProgHnd.InfoLog);
  end;

  gl.TexGenf (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  gl.TexGenf (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  gl.TexGenf (GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  SetVector (v, XVector, 0.5);
  gl.TexGenfv (GL_S, GL_OBJECT_PLANE, @v);
  SetVector (v, YVector, 0.5);
  gl.TexGenfv (GL_T, GL_OBJECT_PLANE, @v);
  SetVector (v, ZVector, 0.5);
  gl.TexGenfv (GL_R, GL_OBJECT_PLANE, @v);
  gl.Enable (GL_TEXTURE_GEN_S);
  gl.Enable (GL_TEXTURE_GEN_T);
  gl.Enable (GL_TEXTURE_GEN_R);

  gl.BindTexture (GL_TEXTURE_3D, M_3D_Texture.Handle);
  gl.Enable (GL_TEXTURE_3D);

  gl.GetFloatv (GL_MODELVIEW_MATRIX, @mat);

  if not Raycasting_CB.Checked then
  begin
  //slicing, works ok
    (*
      glClipPlane(GL_CLIP_PLANE0, @clip0);
      glClipPlane(GL_CLIP_PLANE1, @clip1);
      glClipPlane(GL_CLIP_PLANE2, @clip2);
      glClipPlane(GL_CLIP_PLANE3, @clip3);
      glClipPlane(GL_CLIP_PLANE4, @clip4);
      glClipPlane(GL_CLIP_PLANE5, @clip5);

      glEnable(GL_CLIP_PLANE0);
      glEnable(GL_CLIP_PLANE1);
      glEnable(GL_CLIP_PLANE2);
      glEnable(GL_CLIP_PLANE3);
      glEnable(GL_CLIP_PLANE4);
      glEnable(GL_CLIP_PLANE5);
    *)
    vx.X := mat.X.X;
    vy.X := mat.X.Y;
    vz.X := mat.X.Z;
    vx.Y := mat.Y.X;
    vy.Y := mat.Y.Y;
    vz.Y := mat.Y.Z;
    vx.Z := mat.Z.X;
    vy.Z := mat.Z.Y;
    vz.Z := mat.Z.Z;
    ScaleVector (vx, DIAGONAL_LENGTH * 0.5 / VectorLength (vx));
    ScaleVector (vy, DIAGONAL_LENGTH * 0.5 / VectorLength (vy));
    ScaleVector (vz, DIAGONAL_LENGTH * 0.5 / VectorLength (vz));

    step := DIAGONAL_LENGTH / Projection_N_TB.Position;
    z := -DIAGONAL_LENGTH / 2;
    gl.begin_ (GL_QUADS);
    For i := 0 To Projection_N_TB.Position - 1 Do
      begin
        gl.Color4f (1.0, 1.0, 1.0, 1.0);

        gl.Normal3f (-GLCamera.AbsoluteVectorToTarget.X, -GLCamera.AbsoluteVectorToTarget.Y, -GLCamera.AbsoluteVectorToTarget.Z);

        gl.Vertex3f (vx.X + vy.X + vz.X * z, vx.Y + vy.Y + vz.Y * z, vx.Z + vy.Z + vz.Z * z);
        gl.Vertex3f (-vx.X + vy.X + vz.X * z, -vx.Y + vy.Y + vz.Y * z, -vx.Z + vy.Z + vz.Z * z);
        gl.Vertex3f (-vx.X - vy.X + vz.X * z, -vx.Y - vy.Y + vz.Y * z, -vx.Z - vy.Z + vz.Z * z);
        gl.Vertex3f (vx.X - vy.X + vz.X * z, vx.Y - vy.Y + vz.Y * z, vx.Z - vy.Z + vz.Z * z);
        z := z + step;
      end;
    gl.End_;
  end
  else
  begin
//for raycasting, the idea is to draw a cube, and let de fragment shader do its work
    gl.begin_ (GL_QUADS);

      //xy, pos z
      gl.Vertex3f (FVertexArray[4].X, FVertexArray[4].Y, FVertexArray[4].Z);
      gl.Vertex3f (FVertexArray[5].X, FVertexArray[5].Y, FVertexArray[5].Z);
      gl.Vertex3f (FVertexArray[6].X, FVertexArray[6].Y, FVertexArray[6].Z);
      gl.Vertex3f (FVertexArray[7].X, FVertexArray[7].Y, FVertexArray[7].Z);

      //xz, neg y
      gl.Vertex3f (FVertexArray[4].X, FVertexArray[4].Y, FVertexArray[4].Z);
      gl.Vertex3f (FVertexArray[0].X, FVertexArray[0].Y, FVertexArray[0].Z);
      gl.Vertex3f (FVertexArray[1].X, FVertexArray[1].Y, FVertexArray[1].Z);
      gl.Vertex3f (FVertexArray[5].X, FVertexArray[5].Y, FVertexArray[5].Z);

      //xz, pos y
      gl.Vertex3f (FVertexArray[6].X, FVertexArray[6].Y, FVertexArray[6].Z);
      gl.Vertex3f (FVertexArray[2].X, FVertexArray[2].Y, FVertexArray[2].Z);
      gl.Vertex3f (FVertexArray[3].X, FVertexArray[3].Y, FVertexArray[3].Z);
      gl.Vertex3f (FVertexArray[7].X, FVertexArray[7].Y, FVertexArray[7].Z);

      //yz, pos x
      gl.Vertex3f (FVertexArray[5].X, FVertexArray[5].Y, FVertexArray[5].Z);
      gl.Vertex3f (FVertexArray[1].X, FVertexArray[1].Y, FVertexArray[1].Z);
      gl.Vertex3f (FVertexArray[2].X, FVertexArray[2].Y, FVertexArray[2].Z);
      gl.Vertex3f (FVertexArray[6].X, FVertexArray[6].Y, FVertexArray[6].Z);

      //yz, neg x
      gl.Vertex3f (FVertexArray[0].X, FVertexArray[0].Y, FVertexArray[0].Z);
      gl.Vertex3f (FVertexArray[4].X, FVertexArray[4].Y, FVertexArray[4].Z);
      gl.Vertex3f (FVertexArray[7].X, FVertexArray[7].Y, FVertexArray[7].Z);
      gl.Vertex3f (FVertexArray[3].X, FVertexArray[3].Y, FVertexArray[3].Z);

      //xy, neg z
      gl.Vertex3f (FVertexArray[3].X, FVertexArray[3].Y, FVertexArray[3].Z);
      gl.Vertex3f (FVertexArray[2].X, FVertexArray[2].Y, FVertexArray[2].Z);
      gl.Vertex3f (FVertexArray[1].X, FVertexArray[1].Y, FVertexArray[1].Z);
      gl.Vertex3f (FVertexArray[0].X, FVertexArray[0].Y, FVertexArray[0].Z);
    gl.End_;
  end;

  gl.PopMatrix;
  gl.PopAttrib;

//--- added for glsl test
  if initDGL then
  begin
    ProgHnd.EndUseProgramObject;
  end;
//---
end;
  • 从纹理读取颜色并通过着色器应用,工作正常。所以, 将 3D 纹理传递给着色器是可行的。
  • 通过着色器进行光线投射的选项:立方体绘制有效,光线投射不起作用。

顶点着色器,用于切片和光线投射:

#version 130

varying vec3 vertCoord;

void main(void)
{
  vertCoord = vec3(gl_Vertex) + vec3(0.5, 0.5, 0.5);

  gl_Position = ftransform();
  gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
}

用于切片的片段着色器,工作正常:

#version 330 core

uniform sampler3D avoxels;

in vec3 vertCoord;

out vec4 vFragColor;

void main()
{
  vFragColor = texture(avoxels, vertCoord);
}

对于通过片段着色器进行光线投射,我使用了 OpenGl Development Cookbook 中的示例 glsl 代码,如 github

#version 330 core

uniform sampler3D avoxels;

uniform vec3 acamera;
uniform vec3 astepsize;

in vec3 vertCoord;

out vec4 vFragColor;

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

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

    //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((vertCoord-vec3(0.5)) - acamera);

    //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 * astepsize;

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

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

        //The two constants texMin and texMax have a value of vec3(-1,-1,-1)
        //and vec3(1,1,1) respectively. To determine if the data value is
        //outside the volume data, we use the sign function. The sign function
        //return -1 if the value is less than 0, 0 if the value is equal to 0
        //and 1 if value is greater than 0. Hence, the sign function for the
        //calculation (sign(dataPos-texMin) and sign (texMax-dataPos)) will
        //give us vec3(1,1,1) at the possible minimum and maximum position.
        //When we do a dot product between two vec3(1,1,1) we get the answer 3.
        //So to be within the dataset limits, the dot product will return a
        //value less than 3. If it is greater than 3, we are already out of
        //the volume dataset
        stop = dot(sign(dataPos-texMin),sign(texMax-dataPos)) >= 3.0;
        //if the stopping condition is true we break out of the ray marching loop
        if (stop)
            break;

        // data fetching from the red channel of volume texture
        sample = texture(avoxels, dataPos).r;

        //Opacity calculation using compositing:
        //here we use front to back compositing scheme whereby the current sample
        //value is multiplied to the currently accumulated alpha and then this product
        //is subtracted from the sample value to get the alpha from the previous steps.
        //Next, this alpha is multiplied with the current sample colour and accumulated
        //to the composited colour. The alpha value from the previous steps is then
        //accumulated to the composited colour alpha.
        float prev_alpha = sample - (sample * vFragColor.a);
        vFragColor.rgb = prev_alpha * vec3(sample) + vFragColor.rgb;
        vFragColor.a += prev_alpha;
        //early ray termination
        //if the currently composited colour alpha is already fully saturated
        //we terminated the loop
        if (vFragColor.a>= 1.0)
            break;
    }
}

在修改后的GLScene中可以看到Texture3D演示(完整的Delphi项目可以下载此处),切片有效,光线投射无效。 由于切片确实工作正常,我预计问题出在着色器代码中,或者发送到着色器的制服中。

我尝试了几种选择(主要是相机定位),但没有任何效果。

欢迎提出想法/建议。

问候,罗纳德

I use a modified version of GLScene Texture3D demo, exploring the use shaders with GLScene. I can get shaders to work, but not raycasting algorithm (single pass).
In FormCreate, a unit cube is specified:

//unit cube, for raycasting
  FVertexArray[0] := Vector3fMake(-0.5, -0.5, -0.5);
  FVertexArray[1] := Vector3fMake( 0.5, -0.5, -0.5);
  FVertexArray[2] := Vector3fMake( 0.5,  0.5, -0.5);
  FVertexArray[3] := Vector3fMake(-0.5,  0.5, -0.5);
  FVertexArray[4] := Vector3fMake(-0.5, -0.5,  0.5);
  FVertexArray[5] := Vector3fMake( 0.5, -0.5,  0.5);
  FVertexArray[6] := Vector3fMake( 0.5,  0.5,  0.5);
  FVertexArray[7] := Vector3fMake(-0.5,  0.5,  0.5);

The project uses GLScene's TGLDirectOpenGL:

procedure TForm1.GLDirectOpenGLRender(Sender: TObject; var rci: TGLRenderContextInfo);

Var
  i : Integer;
  step : Single;
  z : Single;
  mat : TMatrix;
  v : TVector;
  vx, vy, vz : TAffineVector;

begin
  if M_3D_Texture.Handle = 0 then
    begin
      //Assert (GL_EXT_texture3D, 'Graphic card does not support 3D textures.');

      M_3D_Texture.AllocateHandle;

      gl.BindTexture (GL_TEXTURE_3D, M_3D_Texture.Handle);
      gl.TexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
      gl.TexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
      gl.TexParameterf (GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
      gl.TexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      gl.TexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      gl.TexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); //GL_REPLACE);

      gl.TexImage3D (GL_TEXTURE_3D, 0, GL_RGBA8, M_Output_Texture_3D.X_Size, M_Output_Texture_3D.Y_Size, M_Output_Texture_3D.Z_Size, 0, M_Output_Texture_3D.Data_Type, GL_UNSIGNED_BYTE, PChar (M_Output_Texture_3D.Data));
    end;

  If M_Refresh = TRUE Then
    begin { then }
      M_Refresh := FALSE;
      Calculate_Transfer_function;
      gl.TexSubImage3D (GL_TEXTURE_3D, 0, 0, 0, 0, M_Output_Texture_3D.X_Size, M_Output_Texture_3D.Y_Size, M_Output_Texture_3D.Z_Size, M_Output_Texture_3D.Data_Type, GL_UNSIGNED_BYTE, PChar (M_Output_Texture_3D.Data));
    end; { then }

//--- added for glsl test
  if not initDGL then
  begin
    if Assigned(ProgHnd) then
    begin
      ProgHnd.Free;
    end;

    ProgHnd := TGLProgramHandle.CreateAndAllocate;

    ProgHnd.AddShader(TGLVertexShaderHandle,
      LoadAnsiStringFromFile('.\vert.glsl'));

    if not Raycasting_CB.Checked then
      ProgHnd.AddShader(TGLFragmentShaderHandle,
        LoadAnsiStringFromFile('.\slicing.frag.glsl'))
    else
      ProgHnd.AddShader(TGLFragmentShaderHandle,
        LoadAnsiStringFromFile('.\\raycast.frag.glsl'));


    if not ProgHnd.LinkProgram then
      raise Exception.Create(ProgHnd.InfoLog);

    initDGL := True;
  end;
//---

  gl.PushAttrib (GL_ENABLE_BIT);
  gl.PushMatrix;

  gl.Enable (GL_BLEND);
  gl.BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  //  glDisable (GL_CULL_FACE);
  //  glDisable (GL_LIGHTING);

//--- added for glsl test and raycasting
  if initDGL then
  begin
    ProgHnd.UseProgramObject;

    ProgHnd.UniformTextureHandle['avoxels', 0, ttTexture3D] := M_3D_Texture.Handle;

    if Raycasting_CB.Checked then
    begin
      //camera position in cube coordinates
      ProgHnd.Uniform3f['acamera'] := GLCube1.AbsoluteToLocal(GLCamera.AbsoluteAffinePosition);

      with M_Output_Texture_3D do
      begin
        ProgHnd.Uniform3f['astepsize'] := AffineVectorMake(1/X_Size, 1/Y_Size, 1/Z_Size);
      end;
    end;

    if not ProgHnd.ValidateProgram then
      raise Exception.Create(ProgHnd.InfoLog);
  end;

  gl.TexGenf (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  gl.TexGenf (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  gl.TexGenf (GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
  SetVector (v, XVector, 0.5);
  gl.TexGenfv (GL_S, GL_OBJECT_PLANE, @v);
  SetVector (v, YVector, 0.5);
  gl.TexGenfv (GL_T, GL_OBJECT_PLANE, @v);
  SetVector (v, ZVector, 0.5);
  gl.TexGenfv (GL_R, GL_OBJECT_PLANE, @v);
  gl.Enable (GL_TEXTURE_GEN_S);
  gl.Enable (GL_TEXTURE_GEN_T);
  gl.Enable (GL_TEXTURE_GEN_R);

  gl.BindTexture (GL_TEXTURE_3D, M_3D_Texture.Handle);
  gl.Enable (GL_TEXTURE_3D);

  gl.GetFloatv (GL_MODELVIEW_MATRIX, @mat);

  if not Raycasting_CB.Checked then
  begin
  //slicing, works ok
    (*
      glClipPlane(GL_CLIP_PLANE0, @clip0);
      glClipPlane(GL_CLIP_PLANE1, @clip1);
      glClipPlane(GL_CLIP_PLANE2, @clip2);
      glClipPlane(GL_CLIP_PLANE3, @clip3);
      glClipPlane(GL_CLIP_PLANE4, @clip4);
      glClipPlane(GL_CLIP_PLANE5, @clip5);

      glEnable(GL_CLIP_PLANE0);
      glEnable(GL_CLIP_PLANE1);
      glEnable(GL_CLIP_PLANE2);
      glEnable(GL_CLIP_PLANE3);
      glEnable(GL_CLIP_PLANE4);
      glEnable(GL_CLIP_PLANE5);
    *)
    vx.X := mat.X.X;
    vy.X := mat.X.Y;
    vz.X := mat.X.Z;
    vx.Y := mat.Y.X;
    vy.Y := mat.Y.Y;
    vz.Y := mat.Y.Z;
    vx.Z := mat.Z.X;
    vy.Z := mat.Z.Y;
    vz.Z := mat.Z.Z;
    ScaleVector (vx, DIAGONAL_LENGTH * 0.5 / VectorLength (vx));
    ScaleVector (vy, DIAGONAL_LENGTH * 0.5 / VectorLength (vy));
    ScaleVector (vz, DIAGONAL_LENGTH * 0.5 / VectorLength (vz));

    step := DIAGONAL_LENGTH / Projection_N_TB.Position;
    z := -DIAGONAL_LENGTH / 2;
    gl.begin_ (GL_QUADS);
    For i := 0 To Projection_N_TB.Position - 1 Do
      begin
        gl.Color4f (1.0, 1.0, 1.0, 1.0);

        gl.Normal3f (-GLCamera.AbsoluteVectorToTarget.X, -GLCamera.AbsoluteVectorToTarget.Y, -GLCamera.AbsoluteVectorToTarget.Z);

        gl.Vertex3f (vx.X + vy.X + vz.X * z, vx.Y + vy.Y + vz.Y * z, vx.Z + vy.Z + vz.Z * z);
        gl.Vertex3f (-vx.X + vy.X + vz.X * z, -vx.Y + vy.Y + vz.Y * z, -vx.Z + vy.Z + vz.Z * z);
        gl.Vertex3f (-vx.X - vy.X + vz.X * z, -vx.Y - vy.Y + vz.Y * z, -vx.Z - vy.Z + vz.Z * z);
        gl.Vertex3f (vx.X - vy.X + vz.X * z, vx.Y - vy.Y + vz.Y * z, vx.Z - vy.Z + vz.Z * z);
        z := z + step;
      end;
    gl.End_;
  end
  else
  begin
//for raycasting, the idea is to draw a cube, and let de fragment shader do its work
    gl.begin_ (GL_QUADS);

      //xy, pos z
      gl.Vertex3f (FVertexArray[4].X, FVertexArray[4].Y, FVertexArray[4].Z);
      gl.Vertex3f (FVertexArray[5].X, FVertexArray[5].Y, FVertexArray[5].Z);
      gl.Vertex3f (FVertexArray[6].X, FVertexArray[6].Y, FVertexArray[6].Z);
      gl.Vertex3f (FVertexArray[7].X, FVertexArray[7].Y, FVertexArray[7].Z);

      //xz, neg y
      gl.Vertex3f (FVertexArray[4].X, FVertexArray[4].Y, FVertexArray[4].Z);
      gl.Vertex3f (FVertexArray[0].X, FVertexArray[0].Y, FVertexArray[0].Z);
      gl.Vertex3f (FVertexArray[1].X, FVertexArray[1].Y, FVertexArray[1].Z);
      gl.Vertex3f (FVertexArray[5].X, FVertexArray[5].Y, FVertexArray[5].Z);

      //xz, pos y
      gl.Vertex3f (FVertexArray[6].X, FVertexArray[6].Y, FVertexArray[6].Z);
      gl.Vertex3f (FVertexArray[2].X, FVertexArray[2].Y, FVertexArray[2].Z);
      gl.Vertex3f (FVertexArray[3].X, FVertexArray[3].Y, FVertexArray[3].Z);
      gl.Vertex3f (FVertexArray[7].X, FVertexArray[7].Y, FVertexArray[7].Z);

      //yz, pos x
      gl.Vertex3f (FVertexArray[5].X, FVertexArray[5].Y, FVertexArray[5].Z);
      gl.Vertex3f (FVertexArray[1].X, FVertexArray[1].Y, FVertexArray[1].Z);
      gl.Vertex3f (FVertexArray[2].X, FVertexArray[2].Y, FVertexArray[2].Z);
      gl.Vertex3f (FVertexArray[6].X, FVertexArray[6].Y, FVertexArray[6].Z);

      //yz, neg x
      gl.Vertex3f (FVertexArray[0].X, FVertexArray[0].Y, FVertexArray[0].Z);
      gl.Vertex3f (FVertexArray[4].X, FVertexArray[4].Y, FVertexArray[4].Z);
      gl.Vertex3f (FVertexArray[7].X, FVertexArray[7].Y, FVertexArray[7].Z);
      gl.Vertex3f (FVertexArray[3].X, FVertexArray[3].Y, FVertexArray[3].Z);

      //xy, neg z
      gl.Vertex3f (FVertexArray[3].X, FVertexArray[3].Y, FVertexArray[3].Z);
      gl.Vertex3f (FVertexArray[2].X, FVertexArray[2].Y, FVertexArray[2].Z);
      gl.Vertex3f (FVertexArray[1].X, FVertexArray[1].Y, FVertexArray[1].Z);
      gl.Vertex3f (FVertexArray[0].X, FVertexArray[0].Y, FVertexArray[0].Z);
    gl.End_;
  end;

  gl.PopMatrix;
  gl.PopAttrib;

//--- added for glsl test
  if initDGL then
  begin
    ProgHnd.EndUseProgramObject;
  end;
//---
end;
  • color is read from texture and applied via shaders, works ok. So,
    passing a 3D texture to shaders works.
  • option for raycasting via shaders : cube drawing works, raycasting does not does not work.

Vertex shader, used for both slicing and raycasting:

#version 130

varying vec3 vertCoord;

void main(void)
{
  vertCoord = vec3(gl_Vertex) + vec3(0.5, 0.5, 0.5);

  gl_Position = ftransform();
  gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
}

Fragment shader for slicing, works ok:

#version 330 core

uniform sampler3D avoxels;

in vec3 vertCoord;

out vec4 vFragColor;

void main()
{
  vFragColor = texture(avoxels, vertCoord);
}

For the raycasting via the fragment shader, I used the example glsl code from the OpenGl Development Cookbook, as found on github:

#version 330 core

uniform sampler3D avoxels;

uniform vec3 acamera;
uniform vec3 astepsize;

in vec3 vertCoord;

out vec4 vFragColor;

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

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

    //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((vertCoord-vec3(0.5)) - acamera);

    //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 * astepsize;

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

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

        //The two constants texMin and texMax have a value of vec3(-1,-1,-1)
        //and vec3(1,1,1) respectively. To determine if the data value is
        //outside the volume data, we use the sign function. The sign function
        //return -1 if the value is less than 0, 0 if the value is equal to 0
        //and 1 if value is greater than 0. Hence, the sign function for the
        //calculation (sign(dataPos-texMin) and sign (texMax-dataPos)) will
        //give us vec3(1,1,1) at the possible minimum and maximum position.
        //When we do a dot product between two vec3(1,1,1) we get the answer 3.
        //So to be within the dataset limits, the dot product will return a
        //value less than 3. If it is greater than 3, we are already out of
        //the volume dataset
        stop = dot(sign(dataPos-texMin),sign(texMax-dataPos)) >= 3.0;
        //if the stopping condition is true we break out of the ray marching loop
        if (stop)
            break;

        // data fetching from the red channel of volume texture
        sample = texture(avoxels, dataPos).r;

        //Opacity calculation using compositing:
        //here we use front to back compositing scheme whereby the current sample
        //value is multiplied to the currently accumulated alpha and then this product
        //is subtracted from the sample value to get the alpha from the previous steps.
        //Next, this alpha is multiplied with the current sample colour and accumulated
        //to the composited colour. The alpha value from the previous steps is then
        //accumulated to the composited colour alpha.
        float prev_alpha = sample - (sample * vFragColor.a);
        vFragColor.rgb = prev_alpha * vec3(sample) + vFragColor.rgb;
        vFragColor.a += prev_alpha;
        //early ray termination
        //if the currently composited colour alpha is already fully saturated
        //we terminated the loop
        if (vFragColor.a>= 1.0)
            break;
    }
}

As can be seen in the modified GLScene Texture3D demo (complete Delphi project can be downloaded here), slicing works, raycasting does not.
As slicing does work OK, I expect the problem to be in shader code, or in uniforms sent to shader.

I tried several options (mainly camera positioning), but nothing works.

Ideas/suggestions are welcome.

Regards, Ronald

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文