在 CG 和 openGL 中使用统一的 1D 纹理参数时出错

Posted

技术标签:

【中文标题】在 CG 和 openGL 中使用统一的 1D 纹理参数时出错【英文标题】:Getting an error using a uniform 1D texture parameter with CG and openGL 【发布时间】:2011-03-25 07:07:18 【问题描述】:

我正在尝试编写一个基本的体积渲染器,它使用 opengl 和 cg 来编写着色器。我将我的传递函数放在一维纹理中,并在片段着色器的相关纹理查找中使用它。我的问题是当我尝试启用与该 1D 纹理对应的参数时遇到 openGL 错误。

我的代码很乱;现在它基本上是从“Real-Time Volume Rendering”和“The CG User's Manual”中提取的代码的混搭。

c 文件:

#include <stdio.h>
#include <stdlib.h>
#include <GL/glut.h>
#include <Cg/cg.h>
#include <Cg/cgGL.h>

static CGcontext   myCgContext;
static CGprofile   myCgVertexProfile,
                   myCgFragmentProfile;
static CGprogram   myCgVertexProgram,
                   myCgFragmentProgram;

static const char *myProgramName = "first_volumetric_renderer",
                  *myVertexProgramFileName = "fvr_vertex.cg",
                  *myVertexProgramName = "fvr_vertex",
                  *myFragmentProgramFileName = "fvr_fragment.cg",
                  *myFragmentProgramName = "fvr_fragment";

static CGparameter first_texture, second_texture, transfer_function;

#define XDIM 256
#define YDIM 256
#define ZDIM 256
#define TRANSFER_RESOLUTION 256
static GLubyte raw_data[XDIM][YDIM][ZDIM];
static GLubyte transfer[TRANSFER_RESOLUTION][4];
static GLuint transfer_name;
static GLuint x_textures[XDIM], y_textures[YDIM], z_textures[ZDIM];


static void checkForCgError(const char *situation);

/* print any errors if we get them */
void check_gl_error(const char * where)  
  GLenum error = glGetError();
  if(error != GL_NO_ERROR)
    printf("openGL Error : %s : %s\n", where, gluErrorString(error));
    exit(1);
  


long int file_length(FILE *f)
  long int pos = ftell(f);
  fseek(f, 0, SEEK_END);
  long int result = ftell(f);
  fseek(f, pos, SEEK_SET);
  return result;


void get_volume_data(const char *filename)
  FILE *in = fopen(filename, "r");
  if(in == NULL) 
    printf("opening '%s' to get volume data failed, exiting...\n", filename);
    exit(1);
  
  long int length = file_length(in);
  if(length != XDIM*YDIM*ZDIM)
    printf("the file does not contain a volume of the correct dimensions\n");
    exit(1);
  
  size_t res = fread((char *)raw_data, 1, length, in);
  if(res < length) printf("error reading in file\n");

  fclose(in);



void create_textures()
  glEnable(GL_TEXTURE_2D);

  // reserve texture identifiers
  glGenTextures(XDIM, x_textures);
  glGenTextures(YDIM, y_textures);
  glGenTextures(ZDIM, z_textures);

  // set texture properties
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  // generate slices in X
  
    int x,y,z;
    GLubyte x_slice[ZDIM][YDIM];
    for(x=0;x < XDIM; x++)
      for(y=0;y < YDIM; y++)
    for(z=0;z < ZDIM; z++)
      x_slice[z][y] = raw_data[x][y][z];
    
      
      GLuint texname = x_textures[x];
      glBindTexture(GL_TEXTURE_2D, texname);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, ZDIM, YDIM, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, x_slice);
    
  

  // generate slices in Y
  
    int x,y,z;
    GLubyte y_slice[XDIM][ZDIM];
    for(y=0;y < YDIM; y++)
      for(x=0;x < XDIM; x++)
    for(z=0;z < ZDIM; z++)
      y_slice[x][z] = raw_data[x][y][z];
    
      
      GLuint texname = y_textures[y];
      glBindTexture(GL_TEXTURE_2D, texname);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, XDIM, ZDIM, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, y_slice);
    
  

  // generate slices in Z
  
    int x,y,z;
    GLubyte z_slice[XDIM][YDIM];
    for(z=0;z < ZDIM; z++)
      for(y=0;y < YDIM; y++)
    for(x=0;x < XDIM; x++)
      z_slice[x][y] = raw_data[x][y][z];
    
      
      GLuint texname = z_textures[z];
      glBindTexture(GL_TEXTURE_2D, texname);
      glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, XDIM, YDIM, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, z_slice);
    
  


void DrawSliceStack_NegativeZ(int numSlices)
  double dZPos = -1.0;
  double dZStep = 2.0/((double)numSlices);

  int slice;
  for(slice = 0;slice < numSlices;slice++)
    double dZPosTex = (ZDIM * (dZPos + 1.0)/2.0);
    int nTexIdx = (int)dZPosTex;
    double dAlpha = dZPosTex - (double)nTexIdx;

    check_gl_error("in slice-drawing function, before cg-stuff");

    cgGLSetTextureParameter(first_texture, z_textures[nTexIdx]);
    checkForCgError("setting first texture");
    check_gl_error("1");
    cgGLEnableTextureParameter(first_texture);
    checkForCgError("enabling first texture");
    check_gl_error("2");
    cgGLSetTextureParameter(second_texture, z_textures[nTexIdx + 1]);
    checkForCgError("setting second texture");
    check_gl_error("3");
    cgGLEnableTextureParameter(second_texture);
    checkForCgError("enabling second texture");
    check_gl_error("4");
    cgGLSetTextureParameter(transfer_function, transfer_name);
    checkForCgError("setting transfer function");
    check_gl_error("5");
    cgGLEnableTextureParameter(transfer_function);
    checkForCgError("enabling transfer function");
    check_gl_error("before updating parameters");
    cgUpdateProgramParameters(myCgFragmentProgram);
    checkForCgError("updating parameters");

    check_gl_error("before drawing a slice");
    glBegin(GL_QUADS);
    glTexCoord3d(0.0, 0.0, dAlpha);
    glVertex3d(-1.0, -1.0, dZPos);
    glTexCoord3d(0.0, 1.0, dAlpha);
    glVertex3d(-1.0, 1.0, dZPos);
    glTexCoord3d(1.0, 1.0, dAlpha);
    glVertex3d(1.0, 1.0, dZPos);
    glTexCoord3d(1.0, 0.0, dAlpha);
    glVertex3d(1.0, -1.0, dZPos);
    glEnd();
    check_gl_error("after drawing a slice");

    dZPos += dZStep;

    cgGLDisableTextureParameter(first_texture);
    checkForCgError("disabling first texture");
    cgGLDisableTextureParameter(second_texture);
    checkForCgError("disabling second texture");
    cgGLDisableTextureParameter(transfer_function);
    checkForCgError("disabling transfer function");

  


void create_transfer_texture()
  glEnable(GL_TEXTURE_1D);

  // create the raw data
  int i;
  for(i = 0; i < TRANSFER_RESOLUTION; i++)
    if(i < 50) 
      transfer[i][0] = (GLubyte)0;
      transfer[i][1] = (GLubyte)0;
      transfer[i][2] = (GLubyte)0;
      transfer[i][3] = (GLubyte)0;
    
    else 
      transfer[i][0] = (GLubyte)255;
      transfer[i][1] = (GLubyte)255;
      transfer[i][2] = (GLubyte)255;
      transfer[i][3] = (GLubyte)i;
    
  

  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  glGenTextures(1, &transfer_name);
  glBindTexture(GL_TEXTURE_3D, transfer_name);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, TRANSFER_RESOLUTION, 0, GL_RGBA, GL_UNSIGNED_BYTE, transfer);
  check_gl_error("creating transfer texture");


static void checkForCgError(const char *situation)

  CGerror error;
  const char *string = cgGetLastErrorString(&error);

  if (error != CG_NO_ERROR) 
    printf("%s: %s: %s\n",
      myProgramName, situation, string);
    if (error == CG_COMPILER_ERROR) 
      printf("%s\n", cgGetLastListing(myCgContext));
    
    exit(1);
  


void init_CG()
  // copy-pasted straight from one of the CG examples
  myCgContext = cgCreateContext();
  checkForCgError("creating context");
  cgGLSetDebugMode(CG_FALSE);
  cgSetParameterSettingMode(myCgContext, CG_DEFERRED_PARAMETER_SETTING);


  myCgFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
  cgGLSetOptimalOptions(myCgFragmentProfile);
  checkForCgError("selecting fragment profile");

  myCgFragmentProgram =
    cgCreateProgramFromFile(
      myCgContext,                /* Cg runtime context */
      CG_SOURCE,                  /* Program in human-readable form */
      myFragmentProgramFileName,  /* Name of file containing program */
      myCgFragmentProfile,        /* Profile: OpenGL ARB vertex program */
      myFragmentProgramName,      /* Entry function name */
      NULL);                      /* No extra compiler options */
  checkForCgError("creating fragment program from file");
  cgGLLoadProgram(myCgFragmentProgram);
  checkForCgError("loading fragment program");

  first_texture = cgGetNamedParameter(myCgFragmentProgram, "text0");
  checkForCgError("could not get 'texture0'");
  second_texture = cgGetNamedParameter(myCgFragmentProgram, "text1");
  checkForCgError("could not get 'texture1'");
  transfer_function = cgGetNamedParameter(myCgFragmentProgram, "transfer_function");
  checkForCgError("could not get 'transfer_function'");

  check_gl_error("initializing CG");


void reshape(int w, int h)

  if (h == 0) h = 1;
  glViewport(0, 0,w,h);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glOrtho(-2, 2, -2, 2, -2, 2); // use orthographic projection
  glMatrixMode(GL_MODELVIEW);


void display()
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);


  /* cgGLBindProgram(myCgVertexProgram);
  checkForCgError("binding vertex program");

  cgGLEnableProfile(myCgVertexProfile);
  checkForCgError("enabling vertex profile");*/

  cgGLBindProgram(myCgFragmentProgram);
  checkForCgError("binding fragment program");

  cgGLEnableProfile(myCgFragmentProfile);
  checkForCgError("enabling fragment profile");

  check_gl_error("before entering slice-drawing function");
  DrawSliceStack_NegativeZ(ZDIM * 2);

  /*cgGLDisableProfile(myCgVertexProfile);
    checkForCgError("disabling vertex profile");*/

  cgGLDisableProfile(myCgFragmentProfile);
  checkForCgError("disabling fragment profile");

  glutSwapBuffers();

  check_gl_error("Finishing 'display()'");


void keyboard(unsigned char c, int x, int y)


void init_glut(int argc, char** argv)
  glutInitWindowSize(400, 400);
  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  glutInit(&argc, argv);

  glutCreateWindow(myProgramName);
  glutDisplayFunc(display);
  glutKeyboardFunc(keyboard);
  glutReshapeFunc(reshape);

  glClearColor(1.0, 0.0, 0.0, 0.0);  /* Black background */


int main(int argc, char **argv)
  init_glut(argc, argv);
  init_CG();
  get_volume_data("aneurism.raw");
  create_textures();
  create_transfer_texture();

  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glutMainLoop();
  return 0;

片段着色器(fvr_fragment.cg):

 float4 fvr_fragment(half3 texUV : TEXCOORD0,
                uniform sampler2D text0,
                uniform sampler2D text1,
                uniform sampler1D transfer_function) : COLOR
    
      half tex0 = tex2D(text0, texUV.xy);
      half tex1 = tex2D(text1, texUV.xy);

      half interp = lerp(tex0, tex1, texUV.z);
      float4 result = tex1D(transfer_function, interp); 

      return result; 
    

the volume data

运行时,程序输出:

openGL Error : before updating parameters : invalid operation

由于我的临时打印调试,我发现导致错误的行是:

cgGLEnableTextureParameter(transfer_function); 

有什么想法吗?

【问题讨论】:

【参考方案1】:

你的错误在这里

glBindTexture(GL_TEXTURE_3D, transfer_name);

它应该是

glBindTexture(GL_TEXTURE_1D, transfer_name);

【讨论】:

以上是关于在 CG 和 openGL 中使用统一的 1D 纹理参数时出错的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL之Mipmap、压缩纹理

OpenGL中的多个渲染目标与Cg

在 iOS 上的 OpenGL ES 着色器中混合多个纹理会导致反向行为

Cg 和 OpenGL 3

贴图问题,opengl,linux,windows,消除锯齿,摩尔纹,yuv 还是 rgb

找不到使用 C# 在 openGL 中将纹理应用于 3d 对象的方法