c - OpenGL:根据 C 语言改编的红皮书示例进行不稳定渲染

标签 c arrays pointers opengl

(请参阅最后的更新以了解我的具体案例的解决方案...这里的问题更加简洁,并且该问题中更全面地涵盖了解决方案: Cannot cast array to pointer )

<小时/> 我成功运行了第一个示例(蓝色三角形),然后将其从 C++ 重构为 C99,也成功了。我基于此 C 版本启动了一个新项目,该项目通过算法生成点,但在功能上与仍在运行的示例相同,并且渲染的图像在不同执行之间不一致。

程序应在屏幕的上半部分绘制一条蓝色抛物线,但在空黑框和从窗口中心到左中点或右中点的水平线之间变化。

我开始做一些不同的事情,更“正确”,比如不使用全局变量或在我看来滥用枚举(NumVAOs、NumBuffers),但由于事情并没有像我预期的那样,我更改越来越多以匹配示例代码。使用 -std=c99 -Wall -pedantic 一切都可以正常编译,并且无论 glew 和 freeglut 是静态还是动态链接,结果都是相同的。

我真的看不出有什么问题。我验证了抛物线函数返回了正确的结果,并且数据的格式与书中的相同。由于结果不一致,我怀疑这可能与 malloc 未清除顶点数组的内存有关,但使用 calloc 得到了相同的结果。屏幕坐标似乎表现不正常,我无法想象为什么。

完整来源位于 https://github.com/markmccormack/concentrator

我相当确定问题出在我的抛物线代码上,因为这是唯一真正的区别,所以这里是相关部分:

/* parabola.h
 * generate parabolas in the form y = ax^2
 * return a compact set of 2D points describing it
 */

#ifndef __PARABOLA_H__
#define __PARABOLA_H__

#include <GL/glew.h>

GLfloat**
v_parabola_by_a ( GLfloat a, GLuint num_points ) ;

#endif /* __PARABOLA_H__ */

以及实现:

#include <stdio.h>
#include <stdlib.h>
#include "parabola.h"

GLfloat**
v_parabola_by_a ( GLfloat a, GLuint num_points ) {
    /* Array of X and Y values */
    GLfloat **points ;
    points = calloc( num_points, sizeof(GLfloat[2]) ) ;
    if( points == NULL ) {
        fprintf( stderr, "Could not allocate memory, exiting.\n" ) ;
        exit(EXIT_FAILURE) ;
    } else {
        int iter_alloc ;
        for( iter_alloc = 0; iter_alloc <= num_points; iter_alloc++ ) {
            points[iter_alloc] = calloc( 2, sizeof(GLfloat) ) ;
        }
    }

    /* Each point is incremented along x by 'inc_x,' for a -1,+1 range */
    GLfloat inc_x = 2.0 / (float)num_points ; 

    int iter_point ;
    for (iter_point = 0; iter_point <= num_points; iter_point++ ) {
        GLfloat x_value = (GLfloat)iter_point * inc_x - 1.0 ;
        GLfloat y_value = x_value * x_value * a ; /* y = a x^2 */
        points[iter_point][0] = x_value ;
        points[iter_point][1] = y_value ;
    }

    return points ;
}

GLfloat** 数组像这样传递给 OpenGL:

GLfloat **points ;
points = calloc( num_points, sizeof(GLfloat[2]) ) ;
if( points == NULL ) {
    fprintf( stdout, "Could not allocate memory.\n" ) ;
    exit( EXIT_FAILURE ) ;
} else {
    int iter_alloc ;
    for( iter_alloc = 0; iter_alloc <= num_points; iter_alloc++ ) {
        points[iter_alloc] = calloc( 2, sizeof(GLfloat) ) ;
    }
}

points = v_parabola_by_a( 1.0, num_points ) ;
/* Create & bind renderable asset */
glGenVertexArrays( NumVAOs, VAOs ) ;
glBindVertexArray( VAOs[Parabola] ) ;
/* Create & bind vertex array */
glGenBuffers( NumBuffers, Buffers ) ;
glBindBuffer( GL_ARRAY_BUFFER, Buffers[ArrayBuffer] ) ;
/* Populate bound vertex array with the asset */
glBufferData( GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW ) ;

非常感谢任何帮助或建议!

<小时/>

我遇到的核心问题是我缺乏理解指针与数组的关系,错误地假设两者在这种情况下可以互换使用。具体来说,使用像 n 维数组这样的指针数组是不正确的,虽然数据可以通过这种方式存储,但在将其作为内存块传递之前必须将其展开为平面数组。这些是修复程序的更改:

  • 顶点数组从 GLfloat** 更改为 GLfloat*
  • glBufferData 的大小参数已从 sizeof(points) 更改为 num_points*2*sizeof(GLfloat)
  • 生成顶点数组的函数从 GLfloat** v_parabola_by_a( float a, int num_points ) ; 更改为 void v_parabola_by_a( float a, int num_points, GLfloat* output) ;memcpy(output,points, num_points*2*sizeof(GLfloat)) 代替 return(points),这纠正了对指针的多重赋值。

这并不是严格意义上的建议,但我相信这是一个可行的解决方案。

最佳答案

glBufferData( GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW ) ;

这是错误的。 glBufferData 需要平面数组,而不是指向 float 组的指针数组。另外,sizeof(points) 是一个指针的大小,而不是数组的大小。

分配 2 个 float 组的数组是没有意义的。创建一个可以容纳所有数据的大数组,并填充它 [0] = first_x, [1] = first_y, [2] = secondary_x, ...

关于c - OpenGL:根据 C 语言改编的红皮书示例进行不稳定渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22784735/

相关文章:

c - 检测消息字符串是否是 QP 编码的

c - 如果地址已知,如何通过指针处理地址内容而不触发段错误?

C语言 : remove the last element of a vector

c - 字符串中的冗余字符,c

在C中创建linux ubuntu下文件和文件夹的路径

javascript - 将数组中的最后一个对象推送到下一个数组

java - 如何将字符串添加到对象的二维数组中?

ios - Objective-C 定义供多个 ViewController 使用的全局数组

c++ - 用指针 C++ 实现双向链表

c++ - 将类对象指针传递给默认构造函数(C++ 子例程)