使用C学习OpenGL,通过制作我自己设计的(据称简单的)基于平铺的游戏。最初我只绘制了大约10个左右的三角形用于测试,我设置了缓冲区数据和索引,如下所示:
const float vertexPositions[] = {
-1.0f, -0.8f, //0
-1.0f, -1.0f, //1
-0.8f, -0.8f, //2
-0.8f, -1.0f, //3
-0.8f, -0.8f, //2
-0.8f, -1.0f, //3
-0.6f, -0.8f, //4
-0.6f, -1.0f, //5
-0.6f, -0.8f, //4
-0.6f, -1.0f, //5
-0.4f, -0.8f, //6
-0.4f, -1.0f, //7
-0.4f, -0.8f, //6
-0.4f, -1.0f, //7
-0.2f, -0.8f, //8
-0.2f, -1.0f, //9
-0.2f, -0.8f, //8
-0.2f, -1.0f, //9
0.0f, -0.8f, //10
0.0f, -1.0f, //11
0.0f, -0.8f, //10
0.0f, -1.0f, //11
/////////////////////////////////// Texture coords:
0.0f, 1.0f, //0
0.0f, 0.0f, //1
1.0f, 1.0f, //2
1.0f, 0.0f, //3
0.0f, 1.0f, //2
0.0f, 0.0f, //3
1.0f, 1.0f, //4
1.0f, 0.0f, //5
0.0f, 1.0f, //4
0.0f, 0.0f, //5
1.0f, 1.0f, //6
1.0f, 0.0f, //7
0.0f, 1.0f, //6
0.0f, 0.0f, //7
1.0f, 1.0f, //8
1.0f, 0.0f, //9
0.0f, 1.0f, //8
0.0f, 0.0f, //9
1.0f, 1.0f, //10
1.0f, 0.0f, //11
0.0f, 1.0f, //10
0.0f, 0.0f, //11
const GLubyte indices[] = {
0, 1, 2,
3, 2, 1,
4, 5, 6,
7, 6, 5,
8, 9, 10,
11, 10, 9,
12, 13, 14,
15, 14, 13,
16, 17, 18,
19, 18, 17,
};
因为我需要更多的三角形来制作更多的三角形,所以我决定自动化它(同样,值是像素而不是屏幕/视口坐标,因为我打算在我的着色器中使用一些矩阵):< / p>
float vertexPositions[6400]; //Declared globally outside the function
int blah()
{
int count = 0, texture_start;
for (int y = 0; y < 20; y++)
{
for (int x = 0; x < 21; x++)
{
vertexPositions[count++] = x * 32.0f;
vertexPositions[count++] = (y + 1) * 32.0f;
vertexPositions[count++] = x * 32.0f;
vertexPositions[count++] = y * 32.0f;
if (x > 0 && x < 20)
{
vertexPositions[count++] = x * 32.0f;
vertexPositions[count++] = (y + 1) * 32.0f;
vertexPositions[count++] = x * 32.0f;
vertexPositions[count++] = y * 32.0f;
}
}
}
texture_start = count;
for (int z = 0; z < 400; z++)
{
vertexPositions[count++] = 0.0f;
vertexPositions[count++] = 1.0f;
vertexPositions[count++] = 0.0f;
vertexPositions[count++] = 0.0f;
vertexPositions[count++] = 1.0f;
vertexPositions[count++] = 1.0f;
vertexPositions[count++] = 1.0f;
vertexPositions[count++] = 0.0f;
}
return 0;
}
请注意,我没有自动化索引,因为我想确保我可以从这些新数据中获得完全相同的三角形。
我在某些 GL调用上反复访问违规行为。如果我在断点之间手动步进,它在到达glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, positionBufferObject);
时总是失败。
如果我在这一行上有一个断点,并且在这行之后有一个断点它会跳过(忽略?静默失败?)中间的行,当它到达时断开GLuint fShader = glCreateShader(GL_FRAGMENT_SHADER);
调用中的myProgram = CreateProgram();
(这是令人惊讶的,因为我的顶点着色器是在之前的同一个调用之前立即创建的并且工作正常)。
GLvoid InitGL(GLvoid)
{
blah(); <----where i initialize my vertex data
FnLdInit();
GetBitmap();
//char * glVer = (char *)glGetString(GL_VERSION);
//char * glSLV = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL); ---------------------------//~BREAKPOINT HERE!~
glGenBuffers(1, &positionBufferObject);
errort = glGetError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, positionBufferObject);
//errort = glGetError();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(vertexPositions), (const float *)vertexPositions, GL_STATIC_DRAW);
//errort = glGetError();
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
//errort = glGetError();
myProgram = CreateProgram(); -------------------------//~BREAKPOINT HERE!~
}
所有glGetError()都返回0,规范说它意味着:没有问题或者glGetError有自己的错误。
无论它在哪里打破,调用堆栈的粒子C显示我的时候它是'atio6axx.dll; DrvPresentBuffers()+ 163B7B',总是:
我最近为我的Radeon HD 6850安装了最新的Catalyst更新。关于GPU /顶点缓冲区对象/等等,我找不到关于内存限制的内容,我怀疑~25KB的数据会破坏很多东西。我觉得这不是一个OpenGL问题,而是我实现代码的方式或者我不熟悉的限制/内存问题。
这个网站上的 Poster #20有类似的问题,但它似乎与程序失败有关,而不是代码(我认为它发生在最新的驱动程序出现之前,即使它是在10月11日发布的) 。 GetBitmap()
使用glBindTexture和其他调用没有问题。
This似乎是最明显的,但我从旧算法改为新算法的唯一方法就是数据创建的自动化。没有涉及指针,我甚至转向const float *
,编译器甚至没有警告我是必要的。
我是否在寻找解决问题的错误位置?我会尝试解释我的代码/如果需要的话添加更多代码,只需要问。我真的不想手写出6400或更多的值。
编辑#1 :经过一些其他测试后,即使使用旧的实现,也会出现此错误。我一定不能编译它(一直在处理着色器,这是单独的文件)。我非常困惑。
编辑#2 :更多代码。这是在InitGL之前发生的唯一函数,并且是调用InitGl的函数。 :
bool CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
GLuint PixelFormat;
WNDCLASS wc;
DWORD dwExStyle;
DWORD dwStyle;
RECT WindowRect;
WindowRect.left = (long)0;
WindowRect.right = (long)width;
WindowRect.top = (long)0;
WindowRect.bottom = (long)height;
fullscreen = fullscreenflag;
hInstance = GetModuleHandle(NULL);
wc.style = CS_HREDRAW |CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = NULL;
wc.lpszMenuName = NULL;
wc.lpszClassName = "OpenGL";
if (!RegisterClass(&wc))
{
MessageBox(NULL, "Failed to register the window class", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (fullscreen)
{
int changeresult;
//char msg[100];
DISPLAY_DEVICE disp;
DEVMODE dmScreenSettings;
int dw;
memset(&disp, 0, sizeof(disp));
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
disp.cb = sizeof(disp);
if (!(EnumDisplayDevices(NULL, 0, &disp, 0)))
{
return 1;
}
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
//ENUM_CURRENT_SETTINGS
if (!(EnumDisplaySettings(disp.DeviceName, ENUM_CURRENT_SETTINGS, &dmScreenSettings)))
{
dw = GetLastError();
}
dmScreenSettings.dmPelsWidth = width; //enable this in real
dmScreenSettings.dmPelsHeight = height; //enable this in real
changeresult = ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
//dmScreenSettings.dmPelsWidth = width;
//dmScreenSettings.dmPelsHeight = height;
//dmScreenSettings.dmBitsPerPel = bits;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (changeresult != DISP_CHANGE_SUCCESSFUL)
{
if (MessageBox(NULL, "Use window mode?", "GL", MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
{
fullscreen = FALSE;
}
else
{
return FALSE;
}
}
}
if (fullscreen)
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP;
ShowCursor(FALSE);
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
}
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
if(!(hWnd = CreateWindowEx( dwExStyle,
"OpenGL",
title,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dwStyle,
0,
0,
WindowRect.right - WindowRect.left,
WindowRect.bottom - WindowRect.top,
NULL,
NULL,
hInstance,
NULL)))
{
KillGLWindow();
MessageBox(NULL, "Window Creation error", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
0, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
pfd.cColorBits = bits;
if (!(hDC = GetDC(hWnd)))
{
KillGLWindow();
MessageBox(NULL, "Can't create a GL device context", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd)))
{
KillGLWindow();
MessageBox(NULL, "Can't find a suitable pixelformat", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!SetPixelFormat(hDC, PixelFormat, &pfd))
{
KillGLWindow();
MessageBox(NULL, "Can't set the pixel format", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!(hRC = wglCreateContext(hDC)))
{
KillGLWindow();
MessageBox(NULL, "Can't create a GL rendering context", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
if (!wglMakeCurrent(hDC, hRC))
{
KillGLWindow();
MessageBox(NULL, "Can't activate the GL rendering context", "Error", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);
SetFocus(hWnd);
InitGL();
ResizeGLScene(width, height);
//char * glVer = (char *)glGetString(GL_VERSION);
//char * glSLV = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
return TRUE;
}
FnLdInit是我连接所有扩展的地方:
void FnLdInit(void)
{
HINSTANCE hGLLIB = NULL;
hGLLIB = LoadLibrary("opengl32.dll");
glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
glDeleteShader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
glDetachShader = (PFNGLDETACHSHADERPROC)wglGetProcAddress("glDetachShader");
glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glDisableVertexAttribArray");
glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray");
glGenBuffers = (PFNGLGENBUFFERSPROC)wglGetProcAddress("glGenBuffers");
glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
glGetShaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv");
glGetUniformfv = (PFNGLGETUNIFORMFVPROC)wglGetProcAddress("glGetUniformfv");
glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
glLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
glUniform1i = (PFNGLUNIFORM1IPROC)wglGetProcAddress("glUniform1i");
glUniform2f = (PFNGLUNIFORM2FPROC)wglGetProcAddress("glUniform2f");
glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");
glBindTexture = (PFNGLBINDTEXTUREPROC)GetProcAddress(hGLLIB, "glBindTexture");
glClear = (PFNGLCLEARPROC)GetProcAddress(hGLLIB, "glClear");
glClearColor = (PFNGLCLEARCOLORPROC)GetProcAddress(hGLLIB, "glClearColor");
glClearDepth = (PFNGLCLEARDEPTHPROC)GetProcAddress(hGLLIB, "glClearDepth");
glDepthFunc = (PFNGLDEPTHFUNCPROC)GetProcAddress(hGLLIB, "glDepthFunc");
glDrawArrays = (PFNGLDRAWARRAYSPROC)GetProcAddress(hGLLIB, "glDrawArrays");
glEnable = (PFNGLENABLEPROC)GetProcAddress(hGLLIB, "glEnable");
glGenTextures = (PFNGLGENTEXTURESPROC)GetProcAddress(hGLLIB, "glGenTextures");
glTexImage2D = (PFNGLTEXIMAGE2DPROC)GetProcAddress(hGLLIB, "glTexImage2D");
glTexParameteri = (PFNGLTEXPARAMETERIPROC)GetProcAddress(hGLLIB, "glTexParameteri");
glViewport = (PFNGLVIEWPORTPROC)GetProcAddress(hGLLIB, "glViewport");
glDrawElements = (PFNGLDRAWELEMENTSPROC)GetProcAddress(hGLLIB, "glDrawElements");
glGetError = (PFNGLGETERRORPROC)GetProcAddress(hGLLIB, "glGetError");
glGetString = (PFNGLGETSTRINGPROC)GetProcAddress(hGLLIB, "glGetString");
}
这是GetBitmap():
int GetBitmap(void)
{
char * bmBuffer, * pxPtr;
FILE * bmFile;
//FILE * result;
GLuint texture;
int bmSize,
dataOffset,
dibSize,
bmWidthPx,
bmHeightPx,
bmCompression,
dataSize,
dataHorRes,
dataVerRes,
paletteNumClrs,
importantClrs,
bmBytesPerPixel = 3, //Default -> RGB
totalBytesPerRow,
pixelBytesPerRow,
padCount = 0;
short int bmClrPlane, bmBPP;
char bmChar0, bmChar1;
//char msgData[100];
bmFile = fopen("multisquare.bmp", "rb");
if (bmFile == NULL)
{
return 1;
}
bmChar0 = fgetc(bmFile);
bmChar1 = fgetc(bmFile);
if (bmChar0 != 'B' || bmChar1 != 'M')
{
return 2;
}
//sprintf(msgData, "%c%c", bmChar0, bmChar1);
//MessageBox(NULL, msgData, NULL, MB_OK | MB_ICONINFORMATION);
bmSize = Get4Bytes(bmFile);
//Skip 4 bytes. These bytes are application specific,
//and generally unused.
if (fseek(bmFile, 4, SEEK_CUR) != 0)
{
return 3;
}
dataOffset = Get4Bytes(bmFile);
dibSize = Get4Bytes(bmFile);
//Replace 'if dibSize' check with case statement
//which branches to functions for different sized
//DIBHeaders.
//
//
if (dibSize != 40)
{
return 4;
}
bmWidthPx = Get4Bytes(bmFile);
bmHeightPx = Get4Bytes(bmFile); //Later -> handle negative = top->bottom.
bmClrPlane = Get2Bytes(bmFile); //Must always be 1 anyways, consider removing this and skipping 2 bytes.
bmBPP = Get2Bytes(bmFile);
if (bmBPP == 24)
{
bmBytesPerPixel = 3;
}
bmCompression = Get4Bytes(bmFile);
//Handle other compressions at some later time.
if (bmCompression != 0)
{
return 5;
}
//Can use this to allocate appropriate memory space.
dataSize = Get4Bytes(bmFile);
//Resolutions doesn't seem too important atm.
dataHorRes = Get4Bytes(bmFile);
dataVerRes = Get4Bytes(bmFile);
//Will probably both be 0. Irrelevant atm.
paletteNumClrs = Get4Bytes(bmFile);
importantClrs = Get4Bytes(bmFile);
bmBuffer = (char *) calloc(dataSize, sizeof(char)); //Space allocated.
fseek(bmFile, dataOffset, SEEK_SET);
//Ex: 10 pixels * 3 bytes/pixel = 30 bytes
// 30 + 3 = 33 -> 0010 0001
// Right shift 2: 0000 1000 -> These operations round to nearest
// Shift left 2: 0010 0000 -> multiple of 4.
// 32 bytes to reach 4byte multiple
// So 30 bytes for 10 pixles plus 2 extra bytes of padding, per row.
pixelBytesPerRow = bmWidthPx * bmBytesPerPixel;
totalBytesPerRow = ((pixelBytesPerRow + bmBytesPerPixel) >> 2) << 2;
padCount = totalBytesPerRow - pixelBytesPerRow;
pxPtr = bmBuffer;
switch(padCount)
{
case 0:
{
for (int A = 0; A <= bmHeightPx; A++)
{
/*
for (int B = 0; B <= bmWidthPx; B++)
{
*(pxPtr + 2) = fgetc(bmFile);
*(pxPtr + 1) = fgetc(bmFile);
*pxPtr = fgetc(bmFile);
}
*/
fread(pxPtr, 1, pixelBytesPerRow, bmFile);
pxPtr += totalBytesPerRow;
}
break;
}
case 1:
case 2:
case 3:
{
for (int A = 0; A <= bmHeightPx; A++)
{
/*
for (int B = 0; B <= bmWidthPx; B++)
{
*(pxPtr + 2) = fgetc(bmFile);
*(pxPtr + 1) = fgetc(bmFile);
*pxPtr = fgetc(bmFile);
}
*/
fread(pxPtr, 1, pixelBytesPerRow, bmFile);
if (fseek(bmFile, padCount, SEEK_CUR) != 0)
{
return 3;
}
pxPtr += totalBytesPerRow;
}
break;
}
default:
//Shouldn't get here
break;
}
//result = fopen("test.txt","w");
//fwrite(bmBuffer, 1, dataSize , result);
//fclose(result);
fclose(bmFile);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, /*Type of texture*/
0, /*Level of Detail number*/
GL_RGB, /*Internal format*/
bmWidthPx, /*Width in texels(pixels?)*/
bmHeightPx, /*Height in texels(pixels?)*/
0, /*Border. Must be 0 (probably only for 2D)*/
GL_BGR, /*Format, of the data the texture will be created from*/
GL_UNSIGNED_BYTE,/*Data type of the pixel data*/
bmBuffer); /*Pointer to the image data to create the texture from*/
//glBindTexture(GL_TEXTURE_2D, 0);
free(bmBuffer);
return 0;
}
编辑#3 :Unistalled Catalyst 12.10及所有相关驱动程序。重新安装12.8。同样的问题,但现在它发生在GenBuffers上。奇
编辑#4 :我尝试将我的项目设为32位,然后进行编译。我得到完全相同的问题,虽然由于某种原因,Pelles C没有标记LIB(它只是说“无标题”,只要它提到一个)所以我只能假设AMD提供的32位lib也失败了(作为atio6axx.dll /。没有加载lib)。我觉得这个问题没有任何真正的解决方案,因为它似乎源于驱动程序,而不是我的代码。在搜索和查看this等相关问题后,似乎没有真正的客户端解决方案。
编辑#5 :我之前没有注意到的另一个问题是因为该程序此时从未向我发出访问冲突,因此代码将到达glActiveTexture(GL_TEXTURE0);
并突然跳过所有的后续行和退出函数。通过删除该行,将执行下一行。 glActiveTexture(GL_TEXTURE0);
来自atio6axx.dll
,而所有其他命令均来自OPENGL32.dll
,因此似乎已将其缩小。奇怪的是,此时没有访问冲突,只是奇怪的跳过。
我想没有人能看到发生这种情况的原因吗?我甚至安装了 beta Catalyst驱动程序,它的版本为atio6axx.dll,日期为15 \ 11 \ 2012(最后一个星期四)。因此,最新的驱动程序不是问题。我甚至尝试了自Catalyst 12.4以来的每个驱动程序版本(当前为12.10,此程序以12.8运行)。不知所措,甚至一个新的计划遇到了同样的问题。
答案 0 :(得分:2)
顶点位置的代码似乎很好,并且似乎不会在数组的边界外写入。您看到的访问冲突可能是由于r11无效引起的。 OpenGL驱动程序代码通常是多线程的,因此当工作线程尝试访问该错误的缓冲区时,您可能只看到该错误。这可以解释您在失败地点看到的奇怪行为。
确保在GPU完成之前不释放缓冲区,传递适当的大小等等。
我担心您必须为我们粘贴更多代码才能进一步为您提供帮助。
同样向我们提供r11的价值可能有所帮助。