在 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 纹理参数时出错的主要内容,如果未能解决你的问题,请参考以下文章
在 iOS 上的 OpenGL ES 着色器中混合多个纹理会导致反向行为