【问题标题】:opengl: how to avoid texture scalingopengl:如何避免纹理缩放
【发布时间】:2008-11-23 04:42:37
【问题描述】:

如何应用始终保持其原始比例(纹理中的 1 个像素 = 屏幕上的 1 个像素)的重复纹理,而不管应用的顶点数据如何。

我意识到这不是最常见的任务,但是否可以轻松设置 opengl 来执行此操作,或者我是否需要对尊重其原始外观的顶点数据应用某种掩码?

编辑:在我的具体情况下,我正在尝试使用相同的像素模式绘制不同大小的 2D 椭圆。椭圆是由三角形扇形制成的,我很难在上面画出任何类型的重复纹理。我希望有一些 opengl 配置组合可以轻松地做到这一点。另外,现在我意识到有一点很重要,因为我正在为 iphone 使用 opengles,所以 GLU 不可用。

【问题讨论】:

  • 还有一个 glut|es 库,但它适用于 windows CE 和 windows mobile。我不知道它的便携性如何。
  • Steph,我在底部添加了一个 opengles 3D 示例的链接,我找不到执行 2D 的 opengles 示例,但标题支持该功能。
  • 哦,最后一个例子,它是一个重复的纹理。

标签: opengl-es


【解决方案1】:

创建有问题的 3D 对象,但不显示它。

您可以使用 gluProject 将对象的边界作为像素位置获取(以获取表示对象边缘的像素。然后您可以使用 gluUnProject 将中间像素映射到对象的坐标。

然后,您重新开始绘制,并在同一对象上映射自定义(动态)纹理并显示它。

不知道您为什么要这样做,但这应该是一个很好的起点。

编辑:

我所说的自定义的意思是,如果你的对象的边界(在一个维度上)是 -3.0 到 1.0,并且第一个像素行是从 -3.0 到 -2.0,那么你的纹理贴图将表明你的 25%在该点上自定义纹理贴图,然后使用要在该点显示的像素的颜色创建它。

仔细考虑之后,我意识到您可以在投影屏幕坐标的顶部绘制纹理(使用 2D 绘图工具。)

我认为这可以理解您的想法的要点。如果“对象”靠近并移开,如果纹理似乎没有放大和缩小,我认为它在交互式 3D 演示中效果不佳。但你没有说你实际上在做什么。

编辑 2:

OpenGL 2D 投影:


注意
注意函数名称,例如,opengles 1.1 有 glOrthox 和 glOrthof。确保检查 gl.h 头文件中的可用内容。

const XSize = 640, YSize = 480
glMatrixMode (GL_PROJECTION)
glLoadIdentity ()
glOrtho (0, XSize, YSize, 0, 0, 1)
glMatrixMode (GL_MODELVIEW)
glDisable(GL_DEPTH_TEST)
glClear(GL_COLOR_BUFFER_BIT)

// Now draw with 2i or 2f vertices instead of the normal vertex3f functions.
// And for ES, of course set up your data structures and call drawarrays ofr drawelements.

SwapBuffers()

这将允许您在 OpenGL 中绘制 2D 形状(比使用 3D 投影更简单)。要将两者混合,例如,先绘制 3D 再绘制 2D,请点击第二个链接。

这是一个关于 2D 绘图的优秀教程:
http://basic4gl.wikispaces.com/2D+Drawing+in+OpenGL

以下是混合两者的基础知识:
http://www.gamedev.net/community/forums/topic.asp?topic_id=96440

我希望那是你想要的。我从您的帖子中偷偷地怀疑您在将纹理映射到三角形点以使其显示为“笔直”时遇到了麻烦。您可能想查看 NeHe 上的基本纹理映射:
http://www.gamedev.net/community/forums/topic.asp?topic_id=96440
例如,gltexcoord2f 根据映射到下一个绘制顶点的纹理宽度和高度的百分比来指定纹理内的点 (0.0-1.0)。使用三角扇,您可以通过一些数学方法来计算您使用顶点指定的整个对象的宽度和高度的百分比。

举个例子,一个带有纹理贴图(地球的墨卡托投影)的球体最好通过计算纬度线作为底层三角形扇形顶点值的基础来映射,因为它简化了纹理坐标的计算。使您的多边形近似于简单的几何形状使您可以使用三角函数更轻松地计算纹理坐标。

我希望这会有所帮助。

在这里,我将不再继续使用您必须修改的桌面示例。这是一个执行正确 3D 纹理映射的 OpenGLES 示例。你可以使用我上面说的和这个例子来做 2D 纹理映射。
http://www.zeuscmd.com/tutorials/opengles/17-TextureMapping.php

【讨论】:

  • 嘿,克里斯,感谢您的意见。我不太了解第一种方法,但无论如何我都不能使用 GLU(请参阅我的编辑)。您能否描述一下您提到的第二种方法,即使用 2D 绘图工具绘制纹理?
  • 谢谢克里斯...这些资源非常好。现在我放弃了我想要的视觉效果,因为根据我得到的答案,结果证明它太复杂了。当我有更多时间时,我会研究它。我仍然很好奇是否可以使用某种面具来实现这一点。
  • 不客气,如果我理解正确的话,我认为面具上没有。
【解决方案2】:

我认为以下代码 sn-p 就是您所说的。但是,如果没有 reshape() 中的 hack,它会在 GL_NEAREST 和非偶数视口尺寸下闪烁得非常糟糕。任何见解将不胜感激。

虽然它使用纹理坐标生成,所以我不确定在 OpenGL ES 1.1 前面该告诉你什么。一位 PowerVR 代表 hinted 在解决方案中,但不是很明确。

#include <GL/glut.h>
#include <cstdlib>
#include <cmath>

static GLuint texName;

void init(void)
{
glClearColor(0,0,0,0);

// create random texture
const int texWidth = 8;
const int texHeight = 8;
GLubyte tex[texHeight][texWidth][4];
for(int i = 0; i < texHeight; i++)
    {
    for(int j = 0; j < texWidth; j++) 
        {
        tex[i][j][0] = (GLubyte) rand()%255;
        tex[i][j][1] = (GLubyte) rand()%255;
        tex[i][j][2] = (GLubyte) rand()%255;
        tex[i][j][3] = (GLubyte) 255;
        }
    }
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);

// planes for texture coordinate generation
GLfloat xp[] = {1,0,0,0};
GLfloat yp[] = {0,1,0,0};
GLfloat zp[] = {0,0,1,0};
GLfloat wp[] = {0,0,0,1};
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGenfv(GL_S, GL_EYE_PLANE, xp);
glTexGenfv(GL_T, GL_EYE_PLANE, yp);
glTexGenfv(GL_R, GL_EYE_PLANE, zp);
glTexGenfv(GL_Q, GL_EYE_PLANE, wp);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_GEN_Q);

glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// projection
glMatrixMode(GL_PROJECTION); glLoadIdentity();
int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport);
gluPerspective(60.0, (GLdouble)viewport[2]/(GLdouble)viewport[3], 1.0, 100.0 );

// texture matrix trickery
int tw,th;
glMatrixMode(GL_TEXTURE); glLoadIdentity();
glBindTexture(GL_TEXTURE_2D, texName);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &tw);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &th);
glScaled( (viewport[2]/2)/(GLdouble)tw, (viewport[3]/2)/(GLdouble)th, 0 );
GLdouble proj[16];
glGetDoublev(GL_PROJECTION_MATRIX, proj); // grab projection matrix
glMultMatrixd(proj);

// view transform
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glTranslatef(0,0,-2.5);

// render textured teapot
glPushMatrix();
const float ANGLE_SPEED = 60; // degrees/sec
float angle = ANGLE_SPEED * (glutGet(GLUT_ELAPSED_TIME) / 1000.0f);
glRotatef(angle*0.5f, 1, 0, 0);
glRotatef(angle, 0, 1, 0);
glRotatef(angle*0.7f, 0, 0, 1);
glScalef(-1,-1,-1); // teapot is wound backwards (GL_CW), so flip it
glutSolidTeapot(1);
glPopMatrix();

glutSwapBuffers();
}

void reshape(int w, int h)
{
// make width/height evenly divisible by 2
w -= (w%2);
h -= (h%2);
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
}

void keyboard (unsigned char key, int x, int y)
{
switch (key) 
    { 
    case 27: exit(0); break;
    default: break; 
    }
}

void idle() { glutPostRedisplay(); }

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(640, 480);
glutInitWindowPosition(100, 100);
glutCreateWindow (argv[0]);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutIdleFunc(idle);

init();
glutMainLoop();
return 0;
}

编辑:找出纹理矩阵唯一的方法(应该是 OpenGL ES 1.1-able):

#include <GL/glut.h>
#include <cstdlib>
#include <cmath>

void glutTexturedCube(GLdouble size)
{
    GLfloat texc[] = {
        1,1,    0,1,    0,0,    1,0,
        0,1,    0,0,    1,0,    1,1,
        1,0,    1,1,    0,1,    0,0,
        1,1,    0,1,    0,0,    1,0,
        0,0,    1,0,    1,1,    0,1,
        0,0,    1,0,    1,1,    0,1,
    };

    GLfloat norm[] = {
        0,0,1,      0,0,1,      0,0,1,      0,0,1,
        1,0,0,      1,0,0,      1,0,0,      1,0,0,
        0,1,0,      0,1,0,      0,1,0,      0,1,0,
        -1,0,0,     -1,0,0,     -1,0,0,     -1,0,0,
        0,-1,0,     0,-1,0,     0,-1,0,     0,-1,0,
        0,0,-1,     0,0,-1,     0,0,-1,     0,0,-1,
    };

    GLfloat vert[] = {
        1,1,1,      -1,1,1,     -1,-1,1,    1,-1,1,
        1,1,1,      1,-1,1,     1,-1,-1,    1,1,-1,
        1,1,1,      1,1,-1,     -1,1,-1,    -1,1,1,
        -1,1,1,     -1,1,-1,    -1,-1,-1,   -1,-1,1,
        -1,-1,-1,   1,-1,-1,    1,-1,1,     -1,-1,1,
        1,-1,-1,    -1,-1,-1,   -1,1,-1,    1,1,-1,
    };

    GLuint idxs[] = { 
        0, 1, 2, 3,     
        4, 5, 6, 7,     
        8, 9, 10, 11,
        12, 13, 14, 15,
        16, 17, 18, 19,
        20, 21, 22, 23,
    };

    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);
    // feed vertices in as texture coordinates
    glTexCoordPointer(3, GL_FLOAT, 0, vert);
    glNormalPointer(GL_FLOAT, 0, norm);
    glVertexPointer(3, GL_FLOAT, 0, vert);

    glPushMatrix();
    glColor4f(1, 1, 1, 1);
    glScaled(size, size, size);
    glDrawElements(GL_QUADS, sizeof(idxs)/sizeof(idxs[0]), GL_UNSIGNED_INT, idxs);
    glPopMatrix();

    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
}

static GLuint texName;

void init(void)
{
glClearColor(0,0,0,0);

// create random texture
const int texWidth = 8;
const int texHeight = 8;
GLubyte tex[texHeight][texWidth][4];
for(int i = 0; i < texHeight; i++)
    {
    for(int j = 0; j < texWidth; j++) 
        {
        tex[i][j][0] = (GLubyte) rand()%255;
        tex[i][j][1] = (GLubyte) rand()%255;
        tex[i][j][2] = (GLubyte) rand()%255;
        tex[i][j][3] = (GLubyte) 255;
        }
    }
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex);

glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
}

void display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// projection
glMatrixMode(GL_PROJECTION); glLoadIdentity();
int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport);
gluPerspective(60.0, (GLdouble)viewport[2]/(GLdouble)viewport[3], 1.0, 100.0 );

// view transform
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
glTranslatef(0,0,-3);

// render textured teapot
glPushMatrix();
const float ANGLE_SPEED = 10; // degrees/sec
float angle = ANGLE_SPEED * (glutGet(GLUT_ELAPSED_TIME) / 1000.0f);
glRotatef(angle*0.5f, 1, 0, 0);
glRotatef(angle, 0, 1, 0);
glRotatef(angle*0.7f, 0, 0, 1);

// texture matrix trickery
int tw,th;
glBindTexture(GL_TEXTURE_2D, texName);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &tw);
glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &th);
GLint mmode = 0;
glGetIntegerv(GL_MATRIX_MODE, &mmode);
glMatrixMode(GL_TEXTURE); glLoadIdentity();
glScaled( (viewport[2]/2)/(GLdouble)tw, (viewport[3]/2)/(GLdouble)th, 0 );
GLdouble mat[16];
glGetDoublev(GL_PROJECTION_MATRIX, mat);
glMultMatrixd(mat);
glGetDoublev(GL_MODELVIEW_MATRIX, mat);
glMultMatrixd(mat);
glMatrixMode(mmode);

glutTexturedCube(1);
glPopMatrix();

glutSwapBuffers();
}

void reshape(int w, int h)
{
// make width/height evenly divisible by 2
w -= (w%2);
h -= (h%2);
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
}

void keyboard (unsigned char key, int x, int y)
{
switch (key) 
    { 
    case 27: exit(0); break;
    default: break; 
    }
}

void idle() { glutPostRedisplay(); }

int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(640, 480);
glutInitWindowPosition(100, 100);
glutCreateWindow (argv[0]);
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutIdleFunc(idle);

init();
glutMainLoop();
return 0;
}

【讨论】:

  • 哇,这是一个很大的 sn-p,谢谢。它究竟是做什么的?我现在无法测试它,因为 glut 库不在 iphone SDK 上。
  • 第一个只是使用 glTexGen() 和朋友绘制一个 glutTeapot,第二个是一个仅使用纹理矩阵的立方体。核心逻辑应该与过剩无关。我在 Windows XP 上使用 FreeGLUT 构建了它们,但如果你在 OSX 上运行 GLUT/FreeGLUT,它们应该可以正常工作。
【解决方案3】:

我不太确定,但试试这样的:

获取您的模型矩阵、透视矩阵和类似的东西。 通过将它们相乘以正确的顺序将它们混合在一起。 取该矩阵的逆矩阵。 将它乘以您的纹理矩阵(可能是单位矩阵)。 将其设置为纹理矩阵。

【讨论】:

  • 将它乘以 Identity Matrix 将如何实现?您仍然会得到模型 * 透视 * 等的合并。
猜你喜欢
  • 2012-01-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多