DlgOpengl-06 纹理

纹理,用过三维建模软件的应该知道它是什么,三维软件的纹理就是给一个三角面绘制一个贴图,可以是图片,也可以是一种依靠灰度进行的诸如烟雾,置换,或者噪波等等类似的操作。之前使用3dmax建模时就有一个操作叫做展UV,将三维模型剖开,变成一个平面,再对这个UV平面贴上纹理坐标,最后把UV坐标与模型的坐标对应,自然就做出纹理了。

可以简单思考把一个正方体摊开,会变成什么?6个面组成的平面。

如果您以前从未编程过3D,您可能会错误地认为您使用世界坐标定义了纹理的位置。然而,一旦物体在太空中移动,这将产生致命的后果。我们每次都要重新计算位置。为了避免这个问题,您在3D编程中采用了不同的方式。只需为对象的每个角指定纹理的坐标。然后OpenGL根据这些纹理坐标计算纹理块,然后将其投影到整个对象上。

我们讨论的是所谓的UV映射,它会引起轻微的不适感,尤其是初学者。然而,如果你对它有一半的理解,它就只有一半的野性。

让我们看看右边的图片,试着解决这个问题。由于纹理可以有不同的大小,所以引入了所谓的纹理坐标。纹理大小无关紧要,因为它只能具有从0到1的值范围。也就是说,如果一个纹理为256x256,另一个为512x512,则两者的最大大小都为1。

在这张图片上,我们一方面看到了我们想要使用的纹理,另一方面看到的是一个接一个地“粘合”的对象。当然,这在现实中看起来不像这样(纹理将覆盖整个对象)。但我认为这个演示更容易理解;)。

纹理的左上角包含纹理坐标(0.0)(即u->0和v ->0;)、左下角(0 \1)、右下角(1 \1),最后右上角包含坐标(1\1)。这意味着要将纹理粘贴到对象上,我们所要做的就是将相应的纹理坐标指定给正方形的角。在这个意义上,应该正确地用引号。没有错误的UV映射。您可以使用这些纹理坐标做很多事情,例如,在对象上镜像纹理。在我们的示例中,我们只需要交换左右UV贴图,例如,将第二个点和第三个点的坐标设置为(0.1)和(1.1)。以同样的方式,我们将切换较低的。上面给出的UV坐标只会使文件中显示的纹理粘到对象上。当然,也可以粘贴平铺的纹理,即通过指定纹理坐标1。也可以仅使用纹理的部分。玩它,看看会发生什么!我们将在最后回到一些伟大的噱头:)。

 

 当然,你们中的一些人已经在手指下燃烧,你会问“我如何将UV坐标指定给曲面的角点?”。首先,它的工作原理与OpenGL下的一切类似。我们设置了一个UV坐标,只要我们不做任何更改,所有点都会得到这些坐标,直到我们给出其他指令。当然,在我们的情况下,我们必须在每一点之后都这样做。用于此操作的函数是glTexCoord。因此,要在四边形上投影纹理,我们需要以下代码:

glBegin(GL_QUADS);
  glTexCoord2f(0,0); glVertex3f(-1,1,0);  //lo
  glTexCoord2f(0,1); glVertex3f(-1,-1,0); //lu
  glTexCoord2f(1,1); glVertex3f(1,-1,0);  //ru
  glTexCoord2f(1,0); glVertex3f(1,1,0);   //ro
glEnd;

代码可以看成是矩形的四个角与贴图的四个角对应了。

这会很好的,不是吗?为了真正享受纹理(或根本享受),我们必须借助glEnable和标记GL_texture_2D激活纹理。在我们的例子中,整个项目(一个四边形)都将被纹理化,您可以将调用直接写入GL初始化,否则它直接位于渲染循环中要纹理化的曲面的前面。

glEnable(GL_TEXTURE_2D);

借助glDisable和相同的标记,也可以绘制没有纹理的对象。否则,将使用最后一个纹理集和最后一个glTexCoord调用的纹理坐标。
但有一件事我没有告诉你!当然,我们仍然需要设置正确的纹理,以便OpenGL知道在这个四边形上绘制什么。这本身是相对容易的,但我们也需要将其放入内存,使其完全可用。现在它是理论上的;)。

然而,还有一些纹理加载器将接管接下来的章节,并为您完成所有这些工作。glBitmap就是这样一个加载器。您可以在glBitmap文章中找到更多信息。

对于SDL,我们只调用IMG_Load,然后检查加载是否成功。应该注意的是,在Linux下,如果程序不是从控制台启动的,则可能会导致问题。在这种情况下,纹理的路径设置不正确,加载将失败。补救措施可以通过使用绝对路径来实现。

uses SDL, SDL_Image;

var 
  tex : PSDL_Surface;
begin
  tex := IMG_Load(PChar(ExtractFileDir(paramStr(0))+'/wiki.jpg'));
  if assigned(tex) then
  begin
  原文这里就没有了。
现在,我们的纹理已经存储在计算机的内存中,这是为了制作一个合适的纹理,以便我们可以在OpenGL中显示它。到目前为止,只有原始数据存储在内存中。为此,我们告诉OpenGL我们要创建一个新的纹理:
glGenTextures(1, @TexID);
在这种情况下,TexID是一个gluInt,但也可以是它的数组,以创建多个纹理。正是出于这个目的,使用了第一个参数,它告诉OpenGL应该向这个数组中写入多少纹理。在我们的案例中,这只是一个要素。但TexID中的这个值是什么?OpenGL使用唯一的名称管理纹理。glGenTextures检测一个或多个以前未使用的名称并将其写入TexID。使用TexID,我们现在可以清楚地识别纹理。
glBindTexture(GL_TEXTURE_2D, TexID);

我们通知OpenGL,从现在起,所有与纹理相关的更改和指令都将引用纹理TexID。
下面这两行并不是创建纹理所必需的,但相信我,否则它们看起来会很糟糕。我们将在另一个教程中详细介绍它的含义,即所谓的纹理过滤器。当前设置稍微有点计算性,但质量也相当好。一开始速度不会有任何问题;)。

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

下面是使用BitMAP读取本地的一张图片进行绘制,最终结果是镜像的。。。

procedure TForm1.AddGLTexture;
var
TexID: GLuint;
Tex: tbitmap;
begin

  //glEnable(GL_TEXTURE_2D);  //这句和下面的active不知道具体作用是什么,在本例注释也能跑。留着以后解答。
glGenTextures(1, @TexID);//创建纹理,给texid写入1个纹理
//glActiveTexture(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, TexID);//绑定

try

//加载图片
Tex := tbitmap.Create;
Tex.LoadFromFile('.\123.bmp');

glTexImage2D(GL_TEXTURE_2D, 0, 3, Tex.Width, Tex.Height, 0, GL_BGR_EXT, GL_UNSIGNED_BYTE, Tex.ScanLine[Tex.Height - 1] );

//Tex.ScanLine[Tex.Height - 1] DIB数据是倒过来的。

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEnable(GL_TEXTURE_2D);
glClear(GL_COLOR_BUFFER_BIT Or GL_DEPTH_BUFFER_BIT); // 清除屏幕和深度缓存

glClearColor(0.5, 0.5, 0.5, 0.0);
glShadeModel(GL_SMOOTH); // 启用阴影平滑
glClearDepth(1.0); // 设置深度缓存
glEnable(GL_DEPTH_TEST); // 启用深度测试
glDepthFunc(GL_LESS); // 所作深度测试的类型
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // 真正精细的透视修正

glLoadIdentity(); // 重置当前的模型观察矩阵
glTranslatef(0.0, 0.0, -5.5); // 移入屏幕6个单位
glBindTexture(GL_TEXTURE_2D, TexID);

glBegin(GL_QUADS);
glTexCoord2f(0, 0);glVertex3f(-1, 1, 0); // lo
glTexCoord2f(0, 1);glVertex3f(-1, -1, 0); // lu
glTexCoord2f(1, 1);glVertex3f(1, -1, 0); // ru
glTexCoord2f(1, 0);glVertex3f(1, 1, 0); // ro
glEnd;
SwapBuffers(DC);
finally
Tex.Free;
end;
end;

 

 

 左侧是绘制处理的,右侧是实际的图片,图片上下翻转了,而且颜色也不正确。

颜色异常的问题找到了,需要设置颜色,这个颜色需要跟纹理的颜色乘积,但是我记得没有设置哪里有默认的颜色。

glColor3f(1.0, 1.0, 1.0);

 

 嗯 没错 这个方向也倒过来了,原因还是bitmap的保存数据的上下是颠倒的,所以直接把UV方向的V方向交换了下就可以了。

glBegin(GL_QUADS);
glTexCoord2f(0, 1);glVertex3f(0, 1, 0); 
glTexCoord2f(0, 0);glVertex3f(0, 0, 0); 
glTexCoord2f(1, 0);glVertex3f(1, 0, 0); 
glTexCoord2f(1, 1);glVertex3f(1, 1, 0);  
glEnd;

 

 

 

 

暂时到这里,纹理看来不好学。

相关转载:

 https://www.jb51.net/article/52127.htm?tdsourcetag=s_pcqq_aiomsg

 https://www.cnblogs.com/shangdawei/archive/2013/05/06/3063750.html

 








 

 

posted @ 2022-11-27 15:42  下雨天不爱打伞  阅读(72)  评论(0编辑  收藏  举报