如何在OpenGL中使用triangle_strip创建圆柱体纹理
How do I texture a cylinder in OpenGL created with triangle_strip?
这是我创建的圆柱体:
void drawCylinder(float r, float g, float b) {
setMaterialColors(r, g, b);
glColor4f(r, g, b, 1.0);
/* top triangle */
double i, resolution = 0.1;
double height = 1, radius = 0.5;
glPushMatrix();
glTranslatef(0, -0.5, 0);
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0, height, 0); /* center */
for (i = 0; i <= 2 * PI; i += resolution)
glVertex3f(radius * cos(i), height, radius * sin(i));
glEnd();
/* bottom triangle: note: for is in reverse order */
glBegin(GL_TRIANGLE_FAN);
glVertex3f(0, 0, 0); /* center */
for (i = 2 * PI; i >= 0; i -= resolution)
glVertex3f(radius * cos(i), 0, radius * sin(i));
/* close the loop back to 0 degrees */
glVertex3f(radius, height, 0);
glEnd();
/* middle tube */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= 2 * PI; i += resolution)
{
glVertex3f(radius * cos(i), 0, radius * sin(i));
glVertex3f(radius * cos(i), height, radius * sin(i));
}
/* close the loop back to zero degrees */
glVertex3f(radius, 0, 0);
glVertex3f(radius, height, 0);
glEnd();
glPopMatrix();
}
现在,我无法将纹理映射到它。我尝试将纹理坐标与三角形条带坐标保持一致,但没有成功。
附言:我不想使用gluCylinder。我知道它的存在。
编辑:如果我只能对磁盘进行纹理处理,那也没关系。四边形条纹不必有纹理。
对于中心:将i
除以2 * PI
,得到一个在0.0
和1.0
之间变化的数字,并将其用作纹理坐标:
for (i = 0; i <= 2 * PI; i += resolution)
{
const float tc = ( i / (float)( 2 * PI ) );
glTexCoord2f( tc, 0.0 );
glVertex3f(radius * cos(i), 0, radius * sin(i));
glTexCoord2f( tc, 1.0 );
glVertex3f(radius * cos(i), height, radius * sin(i));
}
/* close the loop back to zero degrees */
glTexCoord2f( 0.0, 0.0 );
glVertex3f(radius, 0, 0);
glTexCoord2f( 0.0, 1.0 );
glVertex3f(radius, height, 0);
对于端盖:您可以(几乎)直接使用sin()
/cos()
输出:
glTexCoord2f( 0.5, 0.5 );
glVertex3f(0, height, 0); /* center */
for (i = 0; i <= 2 * PI; i += resolution)
{
// scale sin/cos range (-1 to 1) by 0.5 to get -0.5 to 0.5
// then shift that range up/right by 0.5 to get 0 to 1:
glTexCoord2f( 0.5f * cos(i) + 0.5f, 0.5f * sin(i) + 0.5f );
glVertex3f(radius * cos(i), height, radius * sin(i));
}
完整示例:
#include <GL/glew.h>
#include <GL/glut.h>
#include <cmath>
void cylinder()
{
const double PI = 3.14159;
/* top triangle */
double i, resolution = 0.1;
double height = 1;
double radius = 0.5;
glPushMatrix();
glTranslatef(0, -0.5, 0);
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f( 0.5, 0.5 );
glVertex3f(0, height, 0); /* center */
for (i = 2 * PI; i >= 0; i -= resolution)
{
glTexCoord2f( 0.5f * cos(i) + 0.5f, 0.5f * sin(i) + 0.5f );
glVertex3f(radius * cos(i), height, radius * sin(i));
}
/* close the loop back to 0 degrees */
glTexCoord2f( 0.5, 0.5 );
glVertex3f(radius, height, 0);
glEnd();
/* bottom triangle: note: for is in reverse order */
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f( 0.5, 0.5 );
glVertex3f(0, 0, 0); /* center */
for (i = 0; i <= 2 * PI; i += resolution)
{
glTexCoord2f( 0.5f * cos(i) + 0.5f, 0.5f * sin(i) + 0.5f );
glVertex3f(radius * cos(i), 0, radius * sin(i));
}
glEnd();
/* middle tube */
glBegin(GL_QUAD_STRIP);
for (i = 0; i <= 2 * PI; i += resolution)
{
const float tc = ( i / (float)( 2 * PI ) );
glTexCoord2f( tc, 0.0 );
glVertex3f(radius * cos(i), 0, radius * sin(i));
glTexCoord2f( tc, 1.0 );
glVertex3f(radius * cos(i), height, radius * sin(i));
}
/* close the loop back to zero degrees */
glTexCoord2f( 0.0, 0.0 );
glVertex3f(radius, 0, 0);
glTexCoord2f( 0.0, 1.0 );
glVertex3f(radius, height, 0);
glEnd();
glPopMatrix();
}
GLuint tex;
void init()
{
unsigned char data[] =
{
128, 128, 128, 255,
255, 0, 0, 255,
0, 255, 0, 255,
0, 0, 255, 255,
};
glGenTextures( 1, &tex );
glBindTexture( GL_TEXTURE_2D, tex );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
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, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data );
}
float angle = 0;
void timer( int value )
{
angle += 6;
glutPostRedisplay();
glutTimerFunc( 16, timer, 0 );
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective( 60, 1.0, 0.1, 100.0 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glTranslatef( 0, 0, -5 );
glEnable( GL_CULL_FACE );
glEnable( GL_DEPTH_TEST );
glRotatef( angle, 0.2, 0.3, 0.1 );
glEnable( GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, tex );
cylinder();
glutSwapBuffers();
}
int main(int argc, char **argv)
{
glutInit( &argc, argv );
glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
glutInitWindowSize( 600, 600 );
glutCreateWindow( "GLUT" );
init();
glutDisplayFunc( display );
glutTimerFunc( 0, timer, 0 );
glutMainLoop();
return 0;
}
看起来您有一个功能性的解决方案。但与原始代码相比,我认为还有一些地方值得改进,所以我仍然想提供一个替代方案。它的地址:
- 它的效率非常低,使用了大量的
sin
/cos
调用以及除法,这些都相当昂贵。下面的代码使用一个sin
、一个cos
和几个可以在编译时计算的除法。剩下的都是加法和乘法,它们的运算速度要快得多 - 原始代码使用浮点值进行循环控制。由于浮点值本质上是不精确的,这将或多或少地"随机"导致一次或多或少的迭代,这取决于舍入的计算方式
- 原始代码使用
float
、double
和int
类型的任意混合。float
对坐标来说很好,不需要使用较慢的双精度,也不需要昂贵的类型转换回float
代码(未经测试,但希望足够接近以传达所提出的方法):
// Number of segments a circle is divided into.
const unsigned DIV_COUNT = 32;
// Calculate angle increment from point to point, and its cos/sin.
float angInc = 2.0f * M_PI / static_cast<float>(DIV_COUNT);
float cosInc = cos(angInc);
float sinInc = sin(angInc);
// Draw top cap.
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(0.5f, 0.5f);
glVertex3f(0.0f, height, 0.0f);
glTexCoord2f(1.0f, 0.5f);
glVertex3f(radius, height, 0.0f);
float xc = 1.0f;
float yc = 0.0f;
for (unsigned iDiv = 1; iDiv < DIV_COUNT; ++iDiv) {
float xcNew = cosInc * xc - sinInc * yc;
yc = sinInc * xc + cosInc * yc;
xc = xcNew;
glTexCoord2f(0.5f + 0.5f * xc, 0.5f + 0.5f * yc);
glVertex3f(radius * xc, height, -radius * yc);
}
glTexCoord2f(1.0f, 0.5f);
glVertex3f(radius, height, 0.0f);
glEnd();
// Draw bottom cap.
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(0.5f, 0.5f);
glVertex3f(0.0f, 0.0f, 0.0f);
glTexCoord2f(1.0f, 0.5f);
glVertex3f(radius, 0.0f, 0.0f);
xc = 1.0f;
yc = 0.0f;
for (unsigned iDiv = 1; iDiv < DIV_COUNT; ++iDiv) {
float xcNew = cosInc * xc - sinInc * yc;
yc = sinInc * xc + cosInc * yc;
xc = xcNew;
glTexCoord2f(0.5f + 0.5f * xc, 0.5f + 0.5f * yc);
glVertex3f(radius * xc, 0.0f, radius * yc);
}
glTexCoord2f(1.0f, 0.5f);
glVertex3f(radius, 0.0f, 0.0f);
glEnd();
float texInc = 1.0f / static_cast<float>(DIV_COUNT);
// Draw cylinder.
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(radius, 0.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(radius, height, 0.0f);
xc = 1.0f;
yc = 0.0f;
float texCoord = 0.0f;
for (unsigned iDiv = 1; iDiv < DIV_COUNT; ++iDiv) {
float xcNew = cosInc * xc - sinInc * yc;
yc = sinInc * xc + cosInc * yc;
xc = xcNew;
texCoord += texInc;
glTexCoord2f(texCoord, 0.0f);
glVertex3f(radius * xc, 0.0f, radius * yc);
glTexCoord2f(texCoord, 1.0f);
glVertex3f(radius * xc, height, radius * yc);
}
glTexCoord2f(0.0f, 0.0f);
glVertex3f(radius, 0.0f, 0.0f);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(radius, height, 0.0f);
glEnd();
如果您有兴趣使用现代OpenGL,我对这个问题的回答将展示如何使用VBO绘制圆:如何在ES2.0中使用VBO来绘制圆。
相关文章:
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- 使用std::multimap迭代器创建std::list
- 在全局变量中保存类的实例以重新创建类(创建"backup")
- 使用CMake创建QML插件
- 如何在c++中为模板函数实例创建快捷方式
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- OpenCV EqualizeHist()从彩色图像创建黑白图像
- 试图在visual studio上用C++创建一个桌面应用程序
- std::threads可以从Windows DLL中的全局变量创建/销毁吗?
- 如何在C++20中创建模板别名的推导指南
- 如何为模板化对象创建模板向量?VS正在投掷C3203
- 如何创建一个空的全局类并在启动时实例化它
- 无法创建抽象类的实例
- 链接到自行创建的dll失败
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 如何在C++类内存结构中创建"spacer"?
- 终端不会为C++文件创建.exe文件吗
- 在createdialog创建的窗口中捕获用于编辑控件的OnMouseMove消息