【问题标题】:How to correctly render a texture orthogonally in OpenGL?如何在 OpenGL 中正确地正交渲染纹理?
【发布时间】:2015-08-05 02:42:05
【问题描述】:

我正在尝试在正交投影中渲染 2D 纹理。
让我知道出了什么问题。
宽度和高度是 128,视图是 256px 宽和高,所以我希望纹理缩放 2 倍。
但我得到的只是:

代码:

@interface ModNesOpenGLView : NSOpenGLView {
   @public
      char *pixels;
      int width;
      int height;
      int zoom;
}
- (void) drawRect: (NSRect) bounds;
- (void) free;
@end

@implementation ModNesOpenGLView

-(void) awakeFromNib {
   self->pixels = malloc( self->width * self->height * 3 );
   memset( (void *)self->pixels, 0, self->width * self->height * 3 );

   for( int y=0; y<self->height; ++y )
   {
      for( int x=0; x<self->width; ++x )
      {
         char r=0,g=0,b=0;
         switch( y%3 ) {
            case 0: r=0xFF; break;
            case 1: g=0xFF; break;
            case 2: b=0xFF; break;
         }
         [self setPixel_x:x y:y r:r g:g b:b];
      }
   }
}

-(void) setPixel_x:(int)x y:(int)y r:(char)r g:(char)g b:(char)b
{
   self->pixels[ ( y * self->width + x ) * 3 ] = r;
   self->pixels[ ( y * self->width + x ) * 3 + 1 ] = g;
   self->pixels[ ( y * self->width + x ) * 3 + 2 ] = b;
}

-(void) drawRect: (NSRect) bounds
{
   glClearColor(0, 0, 0, 0);
   glClear(GL_COLOR_BUFFER_BIT );

   glTexImage2D( GL_TEXTURE_2D, 0, 3, self->width, self->height, 0,GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) self->pixels );
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // GL_LINEAR
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 
   glEnable(GL_TEXTURE_2D);

//   glTexSubImage2D(GL_TEXTURE_2D, 0 ,0, 0, self->width, self->height, GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) self->pixels );

   glBegin( GL_QUADS );
      glTexCoord2d(0.0, 0.0); glVertex2d(0.0,   0.0);
      glTexCoord2d(1.0, 0.0); glVertex2d(self->width, 0.0);
      glTexCoord2d(1.0, 1.0); glVertex2d(self->width, self->height);
      glTexCoord2d(0.0, 1.0); glVertex2d(0.0,   self->height);
   glEnd();

   glFlush();
}

- (void)prepareOpenGL
{
   // Synchronize buffer swaps with vertical refresh rate
   GLint swapInt = 1;
   [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
}

(^ 代码向下滚动)

我意识到我遗漏了有关投影矩阵和正交投影初始化的所有部分。
我添加了它:

- (void)prepareOpenGL
{
   // Synchronize buffer swaps with vertical refresh rate
   GLint swapInt = 1;
   [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];

   glClearColor(0, 0, 0, 0);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glMatrixMode(GL_MODELVIEW);
   glViewport(0, 0, self->width, self->height);
}

然后我得到这个:

我很困惑。

我从这里获得代码:code example

【问题讨论】:

    标签: objective-c macos cocoa opengl


    【解决方案1】:

    您的问题在于坐标系及其范围。查看您用于绘图的坐标:

    glTexCoord2d(0.0, 0.0); glVertex2d(0.0,   0.0);
    glTexCoord2d(1.0, 0.0); glVertex2d(self->width, 0.0);
    glTexCoord2d(1.0, 1.0); glVertex2d(self->width, self->height);
    glTexCoord2d(0.0, 1.0); glVertex2d(0.0,   self->height);
    

    如果不应用变换,OpenGL 坐标系在 x 和 y 方向的范围都是 [-1.0, 1.0]。这意味着 (0.0, 0.0),即您正在绘制的四边形的左下角,位于屏幕的中心。然后它延伸到右侧和顶部。四边形的大小实际上比窗口大得多,但它显然被剪裁了。

    这解释了您发布的原始版本和生成的图片。最后,右上角的象限被填充,只有很小一部分纹理(大约一个纹素)。

    然后在更新的代码中,添加以下内容:

    glViewport(0, 0, self->width, self->height);
    

    视口决定了您绘制到的窗口部分。既然你说widthheight 是128,并且窗口大小是256x256,这个调用指定你只想在你的窗口的左下角绘制。

    由于其他所有内容均未更改,因此您仍会绘制绘图区域的右上象限。因此,您最终会填充窗口左下象限的右上象限,这正是您在第二张图像中所拥有的。

    要解决此问题,最简单的方法是将视口设置为非默认值(删除 glViewport() 调用),并使用 [-1.0, 1.0] 范围内的坐标双向:

    glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, -1.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex2f( 1.0f, -1.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex2f( 1.0f,  1.0f);
    glTexCoord2f(0.0f, 1.0f); glVertex2f(-1.0f,  1.0f);
    

    另一个选项是您设置一个转换,将坐标范围更改为您正在使用的值。在您正在使用的旧版 OpenGL 中,这样的事情应该可以工作:

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, self->width, 0.0, self->height, -1.0, 1.0);
    

    【讨论】:

    • 酷。我怎么知道它是传统的 OpenGL,什么是现代的 OpenGL?
    • 传统 OpenGL 的典型标志是立即模式渲染(使用 glBegin()/glEnd())而不是将顶点数据存储在缓冲区中,并且不使用着色器。我将 OpenGL 3.2 及更高版本的核心配置文件称为“现代”,以及 OpenGL ES 2.0 及更高版本。例如,如果您搜索“OpenGL 核心配置文件”,应该有很多教程。如果允许一些自我推销,我在我的(稀疏的)个人网站上也有一篇关于该主题的小文章:retokoradi.com/2014/03/30/opengl-transition-to-core-profile
    • 允许和鼓励。谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-30
    • 1970-01-01
    • 2019-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多