OpenGL纹理坐标 与 Cocos2d-x 纹理坐标

Cocos2d-x 纹理坐标

声明:本文使用的是cocos2d-x-3.17的代码

OpenGL纹理坐标

在OpenGL中2D纹理坐标系如下:

原点为左下角,向右为X轴正方向,向上为Y轴正方向。

纹理数据排列

创建一个2*2的二维纹理,需要四个像素,以下是4个像素的数据

    float texData[] = { 1.0, 0.0, 0.0, 1.0,
                        0.0, 1.0, 0.0, 1.0,
                        0.0, 0.0, 1.0, 1.0,
                        1.0, 1.0 ,1.0, 1.0 };

创建一个纹理,使用这4个像素设置纹理数据

glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2Dtex);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 2, 2);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, GL_RGBAGL_FLOATtexData);
 

glTexParameteri(GL_TEXTURE_2DGL_TEXTURE_MIN_FILTERGL_NEAREST);
glTexParameteri(GL_TEXTURE_2DGL_TEXTURE_MAG_FILTERGL_NEAREST);
glTexParameteri(GL_TEXTURE_2DGL_TEXTURE_WRAP_SGL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2DGL_TEXTURE_WRAP_TGL_CLAMP_TO_EDGE);

使用以下矩形数据显示纹理:

struct Vertex
{
    
GLfloat position[3];
    
GLfloat TexCoord[2];
Verts[] = {
    { { -0.5f,-0.5f, 0.0f },{ 0.0f,0.0f } },
    { {  0.5f,-0.5f, 0.0f },{ 1.0f,0.0f } },
    { { -0.5f, 0.5f, 0.0f },{ 0.0f,1.0f } },
    { {  0.5f, 0.5f, 0.0f },{ 1.0f,1.0f } }, };

显示结果如下:

(设置纹理像素数据程序完整代码下载)

这里的4个颜色的矩形分别来自4个不同的像素。红绿在下方,对应像素数据数组中0、1的数据,蓝白对应2、3中的数据。

从上面程序可以看出在OpenGL设置二维纹理数据时,像素数据是从纹理最底下往上排列

纹理数据与图片数据

对于一张图片,不管是png,jpg,dds等格式,其数据是从上往下排列的,这与OpenGL纹理数据排列是相反的。所以如果我们直接使用图片数据初始化纹理,然后直接映射绘制矩形,会发现图片是上下颠倒的。为了使得图片显示正常,这时需要调整一下纹理坐标,纹理坐标Y轴需要使用1.0减去纹理坐标Y轴值,如下:

如果时直接使用图片数据设置纹理,需要将纹理坐标调整为右边图片的坐标,这个时候看上去如同纹理坐标系原点在左上角。

渲染数据到纹理

当通过FrameBuffer渲染数据到二维纹理时,渲染的像素数据是从底部向上排列的,显示这种纹理只需要使用原点为左下角的纹理坐标系。

OpenGL截图

当通过glReadPixels等函数从OpenGL中读取像素数据时,像素数据也是从底部向上排列的,而一般图片的数据是从上往下排列的,所以需要将读取的像素上下翻转。以下是Cocos2d-x中截图部分代码,文件” cocos2d\cocos\base\ccUtils.cpp”,函数“onCaptureScreen”:

        glPixelStorei(GL_PACK_ALIGNMENT, 1);

        glReadPixels(0, 0, widthheightGL_RGBAGL_UNSIGNED_BYTEbuffer.get());

        std::shared_ptr<GLubyteflippedBuffer(new GLubyte[width * height * 4], [](GLubytep) { CC_SAFE_DELETE_ARRAY(p); });

        if (!flippedBuffer)

        {

            break;

        }

        for (int row = 0; row < height; ++row)//上下翻转像素

        {

            memcpy(flippedBuffer.get() + (height - row - 1) * width * 4, buffer.get() + row * width * 4, width * 4);

        }

Cube纹理坐标

立方体纹理由六个面组成,每个面是相当于一个二维纹理,六个面中二维坐标的纹理坐标映射都一样。这里取Z轴正方向平面也就是Z=1平面从立方体外面看立方体纹理,Cube纹理坐标与相应平面的2D纹理坐标对应关系如下:

图片中蓝色的坐标其(0, 0)点在左上角,所以与实际的二维纹理坐标相比这个是上下颠倒到。对于实际的图片来说纹理数据是纹理数据是从上到下的,所以如果Cube纹理是通过实际图片加载的,显示的时候是可以正常显示的。图片上是从立方体外面看立方体纹理,如果从立方体中心往外面看,图形会左右颠倒。如果立方体纹理是用来做天空盒子使用,这种情况是从立方体中心往外看,如果是用来做物体表面的环境映射,此时是从外面往里看。

以下Cube纹理坐标测试程序,下载地址

渲染生成Cube纹理

OpenGL渲染生成的像素数据是从底部向上排列的,而Cube纹理需要从上往下的数据。另外还有一点不同,因为渲染生成的纹理一般是用来做物体表面环境映射用的,所以查看立方体纹理方向为从立方体外面看立方体纹理,导致摄像机方向和查看纹理方向不同,这会引起图形左右相反。以下图片是一个投影的俯视图:

可以假设上图是在生成Z轴负面的纹理,此时摄像机方向为Z轴负方向,在立方体外面看立方体纹理,查看方向为Z轴正方向。

最终图形是上下左右都相反,这也就相当于图形被旋转了180°,为了抵消这个偏差,我们可以将摄像机按Z轴旋转180°。在生成视图矩阵(摄像机矩阵)时一般会用到3个参数:摄像机位置、摄像机朝向(查看目标)、向上方向,要将摄像机旋转180°,只需要将摄像机的向上方向设为负的就可以抵消这个偏差。以下是生成Cube纹理坐标六个摄像机的朝向和向上方向:

X 轴正面方向:{Vec3( 1,  0,  0) 向上:Vec3(  0,  -1,  0)}

X 轴负面方向:{Vec3(-1,  0,  0) 向上:Vec3(  0,  -1,  0)}

Y 轴正面方向:{Vec3( 0,  1,  0) 向上:Vec3(  0,   0,  1)}

Y 轴负面方向:{Vec3( 0, -1,  0) 向上:Vec3(  0,   0,  -1)}

Z 轴正面方向:{Vec3( 0,  0,  1) 向上:Vec3(  0,  -1,  0)}

Z 轴负面方向:{Vec3( 0,  0, -1) 向上:Vec3(  0,  -1,  0)}

以下是一个Cocos2d-x渲染到Cube纹理的例子,代码下载地址,对应的程序菜单:“1:Render To Cube”

Cocos2d纹理坐标

二维纹理坐标

Cocos2d二维纹理主要用于Sprite、ParticleSystem等等。Cocos2d二维纹理是直接使用图片数据初始化的,所以显示图片时坐标需要将纹理坐标原点调整到左上角。以下是调试时Sprite设置纹理坐标的代码和坐标变量的值:

因为Sprite纹理坐标原点在左上角,而使用FrameBuffer生成的纹理原点在左下角,所以如果使用Sprite类显示FrameBuffer生成的纹理,图形会上下颠倒。

3D纹理

Cocos2d中3D显示中也会使用二维纹理贴图。Cocos2d显示的3D模型需要显示用使用fbx-conv.exe程序转换。fbx-conv.exe程序转换fbx后会生成相应的二维纹理图片已经带纹理坐标的3D 模型(*.c3b/*.c3t),这个模型的纹理坐标是基于右下角为原点计算的。在Cocos中加载的图片纹理是需要使用原点在左上角的坐标,这个与模型中的纹理坐标不一致,所以Cocos在显示3D时会使用1减模型中的纹理Y轴坐标。以下代码来自Cocos中一个3D顶点着色器:

void main(void)

{

    gl_Position = CC_MVPMatrix * a_position;

    TextureCoordOut = a_texCoord;

    TextureCoordOut.y = 1.0 - TextureCoordOut.y;

}

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值