【问题标题】:OpenGL: Wrapping texture around cylinderOpenGL:围绕圆柱体包裹纹理
【发布时间】:2016-06-21 23:09:32
【问题描述】:

我正在尝试向圆柱体添加纹理以很好地绘制石头。我从一个圆柱体开始,然后映射一个我发现here 的石头纹理,但得到了一些奇怪的结果。这是我正在使用的功能:

void draw_well(double x, double y, double z,
    double dx, double dy, double dz,
    double th)
{
    //  Set specular color to white
    float white[] = {1,1,1,1};
    float black[] = {0,0,0,1};
    glMaterialfv(GL_FRONT_AND_BACK,GL_SHININESS,shinyvec);
    glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,white);
    glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION,black);

    glPushMatrix();

    //  Offset
    glTranslated(x,y,z);
    glRotated(th,0,1,0);
    glScaled(dx,dy,dz);

    //  Enable textures
    glEnable(GL_TEXTURE_2D);
    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);

    glBindTexture(GL_TEXTURE_2D,texture[0]); // Stone texture

    glBegin(GL_QUAD_STRIP);
    for (int i = 0; i <= 359; i++)
    {
        glNormal3d(Cos(i), 1, Sin(i));

        glTexCoord2f(0,0); glVertex3f(Cos(i), -1, Sin(i));
        glTexCoord2f(0,1); glVertex3f(Cos(i), 1, Sin(i));
        glTexCoord2f(1,1); glVertex3f(Cos(i + 1), 1, Sin(i + 1));
        glTexCoord2f(1,0); glVertex3f(Cos(i + 1), -1, Sin(i + 1));
    }
    glEnd();

    glPopMatrix();
    glDisable(GL_TEXTURE_2D);
}


// Later down in the display function
draw_well(0, 0, 0, 1, 1, 1, 0);

我收到的输出是

我对 OpenGL 尤其是纹理还是很陌生,所以我的理解非常有限。我的想法是,我会将纹理映射到每个用于制作圆柱体的QUAD,但显然我做错了什么。任何关于导致这种奇怪输出的原因以及如何解决它的解释将不胜感激。

【问题讨论】:

  • 应用纹理坐标的方式每个四边形都应用了整个纹理。这肯定不是你想要的。

标签: c opengl textures


【解决方案1】:

您的绘图程序可能存在三个主要问题。四边形索引、纹理坐标重复过于频繁以及三角函数的使用可能不正确;

三角函数 函数通常接受以弧度而不是度数表示的角度值。仔细检查您使用的 Sin 和 Cos 函数的参数。

Quadstrip 索引不正确。索引应该是这样的......

注意四边形是如何以顺时针方式定义的,但是对角线顶点是按顺序定义的。您将四边形定义为 v0、v1、v3、v2 而不是 v0、v1、v2、v3,因此交换四个中的最后两个顶点。这也会导致另一个错误,即不能正确共享顶点。由于您在一个循环中绘制相同的一组顶点 (i+1),因此您正在沿每个垂直边缘复制它们,就像您在下一个循环中所做的那样(即,因为 i 现在已增加 1)。

纹理坐标的范围为每个四边形的 0 和 1,这意味着您正在定义一个分段 360 次的圆柱体,并且此纹理围绕圆柱体重复 360 次。我假设纹理应该 1:1 映射到圆柱体而不是重复?

这是一些使用您提供的示例代码。我已将段数减少到 64,如果您仍希望有 360,请相应地修改 numberOfSegments

float pi = 3.141592654f;

unsigned int numberOfSegments = 64;
float angleIncrement = (2.0f * pi) / static_cast<float>(numberOfSegments);
float textureCoordinateIncrement = 1.0f / static_cast<float>(numberOfSegments);

glBegin(GL_QUAD_STRIP);
for (unsigned int i = 0; i <= numberOfSegments; ++i)
{
    float c = cos(angleIncrement * i);
    float s = sin(angleIncrement * i);

    glTexCoord2f( textureCoordinateIncrement * i, 0); glVertex3f( c, -1.0f, s);
    glTexCoord2f( textureCoordinateIncrement * i, 1.0f); glVertex3f( c, 1.0f, s);
}
glEnd();

注意您使用的是旧版本的 OpenGL(使用 glBegin/glVertex 等)。

【讨论】:

  • 好的,非常感谢。坐标的重复是有道理的,我忘了OpenGL只需要2个新点就可以制作下一个QUAD。至于坐标的索引,我不知道它从 (0, 1) 跳到 (1, 0) 我认为它会像连接点一样跟踪它。实际上,我只是交换了循环中的 2 条线并得到了圆柱体形状,但纹理仍然很奇怪。你的代码虽然有效。
  • 很高兴它的工作“更好”;)关于纹理映射。纹理被映射为 0,0(纹理的左下角)到 1,1(纹理的右上角),因此要将纹理正确映射到圆柱体周围一次(这样纹理不会重复),您需要绘制纹理坐标的 x 分量到顶点所在圆柱体周围的距离。这就是纹理坐标增量不同于角度增量的原因。要重复纹理,请在我提供的代码中增加 textureCoordinateIncrement 定义中的分子。
  • 那个四边形图很不幸。虽然拓扑正确,但它以顺时针顺序显示顶点,而 OpenGL 中默认的缠绕顺序是逆时针。
  • @RetoKoradi,已使用 ccw 缠绕编辑了答案。
猜你喜欢
  • 1970-01-01
  • 2011-10-01
  • 2014-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-22
  • 1970-01-01
相关资源
最近更新 更多