【问题标题】:Texturing a Sphere in OpenGL 3+在 OpenGL 3+ 中对球体进行纹理化
【发布时间】:2013-05-21 23:18:23
【问题描述】:

我想用一个 1024*512 的图像环绕一个球体。

这是我的代码:(未全部显示)

在 main.cpp 中:

struct Vertex {

    GLdouble position[3];
    GLfloat color[3];
    GLfloat textureUV[2];
};

void SetupGemetry() {

    //Allocate 4 VBOs
    glGenBuffers(4, vbo);

    }

//Setting the current Buffer.
void setBuffer(int buffer_no, int no_vertices, Vertex *vertices_array)
{

    glBindBuffer(GL_ARRAY_BUFFER, vbo[buffer_no]);

    glBufferData ( GL_ARRAY_BUFFER, no_vertices * sizeof ( struct Vertex ), vertices_array, GL_STATIC_DRAW );

    glEnableVertexAttribArray( 0 );

    glVertexAttribPointer ( ( GLuint ) 0, 3, GL_DOUBLE, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) 
    offsetof(struct Vertex ,position) );        

    glEnableVertexAttribArray ( 1 );

    glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* )
    offsetof(struct Vertex,color) );

    //Textute Handling
    glEnableVertexAttribArray( 2 );
    glVertexAttribPointer(( GLuint ) 2,3,GL_FLOAT,GL_FALSE,sizeof(struct Vertex),(const GLvoid* )offsetof(struct Vertex ,texture));

}

现在在我的 Sphere.cpp 中(这里我加载 *.bmp 文件)

GLuint Sphere::loadBMP_custom(const char * imagepath)
{
    // Data read from the header of the BMP file
    unsigned char header[54]; // Each BMP file begins by a 54-bytes header
    unsigned int dataPos;     // Position in the file where the actual data begins
    unsigned int width, height;
    unsigned int imageSize;   // = width*height*3
    // Actual RGB data
    unsigned char * data;
    // Open the file
    FILE * file = fopen(imagepath,"rb");
    if (!file)
    {
        printf("Image could not be opened\n"); 
        return 0;
    }
    //Checking the header file
    if ( fread(header, 1, 54, file)!=54 )
    { // If not 54 bytes read : problem
        printf("Not a correct BMP file\n");
        return false;
    }
    if ( header[0]!='B' || header[1]!='M' )
    {
        printf("Not a correct BMP file\n");
        return 0;
    }

    dataPos    = *(int*)&(header[0x0A]);
    imageSize  = *(int*)&(header[0x22]);
    width      = *(int*)&(header[0x12]);
    height     = *(int*)&(header[0x16]);
    // Some BMP files are misformatted, guess missing information
    if (imageSize==0)    imageSize=width*height*3; // 3 : one byte for each Red, Green and Blue component
    if (dataPos==0)      dataPos=54; // The BMP header is done that way

    // Create a buffer
    data = new unsigned char [imageSize];

    // Read the actual data from the file into the buffer
    fread(data,1,imageSize,file);

    //Everything is in memory now, the file can be closed
    fclose(file);

    //OpenGL Part
    // Create one OpenGL texture
    GLuint textureID;
    glGenTextures(1, &textureID);

    // "Bind" the newly created texture : all future texture functions will modify this texture
    glBindTexture(GL_TEXTURE_2D, textureID);

    // Give the image to OpenGL
    glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, data);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}

void Sphere::SetupShaders_sphere(void){

    // Read our shaders into the appropriate buffers
    sphere_vertexsource = filetobuf_sphere("vertex_shader_2.vert");
    sphere_fragmentsource = filetobuf_sphere("fragment_shader_2.frag");

    //Assign our handles a "name" to new shader objects 
    sphere_vertexshader = glCreateShader(GL_VERTEX_SHADER);
    sphere_fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);

    // Associate the source code buffers with each handle
    glShaderSource(sphere_vertexshader, 1, (const GLchar**)&sphere_vertexsource, 0);
    glShaderSource(sphere_fragmentshader, 1, (const GLchar**)&sphere_fragmentsource, 0);

    //Setting them up by compiling, attaching and linking them!
    glCompileShader(sphere_vertexshader);
    glCompileShader(sphere_fragmentshader);

    sphere_shaderprogram = glCreateProgram();
    glAttachShader(sphere_shaderprogram, sphere_vertexshader);
    glAttachShader(sphere_shaderprogram, sphere_fragmentshader);

    glBindAttribLocation(sphere_shaderprogram, 0, "in_Position"); 
    glBindAttribLocation(sphere_shaderprogram, 1, "in_Color");

    glLinkProgram(sphere_shaderprogram);
    glUseProgram(sphere_shaderprogram);

}

现在我的片段和顶点着色器:

顶点:

#version 330 core

// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 in_Position;
layout(location = 1) in vec3 inColor;
layout(location = 2) in vec2 vertexUV;

// Output data ; will be interpolated for each fragment.
out vec2 UV;

// Values that stay constant for the whole mesh.
uniform mat4 MVP_matrix;

void main(){

    // Output position of the vertex, in clip space : MVP * position
    gl_Position =  MVP_matrix * vec4(in_Position,1);

    // UV of the vertex. No special space for this one.
    UV = vertexUV;
}

片段:

#version 330 core

// Interpolated values from the vertex shaders
in vec2 UV;

// Ouput data
out vec3 color;

// Values that stay constant for the whole mesh.
uniform sampler2D myTextureSampler;

void main(){

    // Output color = color of the texture at the specified UV
    color = texture2D( myTextureSampler, UV ).rgb;
}

如何将图像文件坐标 (UV) 转换为 3D 坐标?如何将它们传递给我的顶点着色器? (嗯,我知道如何将数据传递给顶点,我的意思是如何将 2D 图像文件转换为 3D?)例如我找到了这个不错的教程

www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/

这就是说:“好吧,我们必须在这里做完全相同的事情,但是我们不会给出一个缓冲 (R,G,B) 三元组,而是给出一个 (U,V) 对的缓冲。 "

// Two UV coordinatesfor each vertex. They were created with Blender. You'll learn shortly how to do this yourself.
static const GLfloat g_uv_buffer_data[] = {
    0.000059f, 1.0f-0.000004f,
    0.000103f, 1.0f-0.336048f,
    0.335973f, 1.0f-0.335903f,
    1.000023f, 1.0f-0.000013f,
    0.667979f, 1.0f-0.335851f,
    0.999958f, 1.0f-0.336064f,
    0.667979f, 1.0f-0.335851f,
    0.336024f, 1.0f-0.671877f,
    0.667969f, 1.0f-0.671889f,
    1.000023f, 1.0f-0.000013f,
    0.668104f, 1.0f-0.000013f,
    0.667979f, 1.0f-0.335851f,
    0.000059f, 1.0f-0.000004f,
    0.335973f, 1.0f-0.335903f,
    0.336098f, 1.0f-0.000071f,
    0.667979f, 1.0f-0.335851f,
    0.335973f, 1.0f-0.335903f,
    0.336024f, 1.0f-0.671877f,
    1.000004f, 1.0f-0.671847f,
    0.999958f, 1.0f-0.336064f,
    0.667979f, 1.0f-0.335851f,
    0.668104f, 1.0f-0.000013f,
    0.335973f, 1.0f-0.335903f,
    0.667979f, 1.0f-0.335851f,
    0.335973f, 1.0f-0.335903f,
    0.668104f, 1.0f-0.000013f,
    0.336098f, 1.0f-0.000071f,
    0.000103f, 1.0f-0.336048f,
    0.000004f, 1.0f-0.671870f,
    0.336024f, 1.0f-0.671877f,
    0.000103f, 1.0f-0.336048f,
    0.336024f, 1.0f-0.671877f,
    0.335973f, 1.0f-0.335903f,
    0.667969f, 1.0f-0.671889f,
    1.000004f, 1.0f-0.671847f,
    0.667979f, 1.0f-0.335851f
};

我必须使用搅拌机吗? 我找到了这个http://www.opengl.org/wiki/Texturing_a_Sphere#2D_Texture_Mapping_a_Sphere 但是还是看不懂

【问题讨论】:

    标签: c++ opengl


    【解决方案1】:

    如何将图像文件坐标 (UV) 转换为 3D 坐标?

    你没有。纹理不会构成您的几何图形。您还需要提供球体的坐标。不,您不必使用 Blender,它只是用来导出一些顶点数据(位置、法线和纹理坐标)以供以后使用。所以除了UV缓冲,还应该有一个position和一个normal缓冲。

    【讨论】:

    • 我有球体的位置缓冲区,也很正常!问题是紫外线缓冲液。我不知道如何实现它。我发现的教程对我来说不够简单。当您说“您还需要提供球体的坐标”时,我已经这样做了。我将位置坐标传递给顶点着色器。
    • 那我没看到你的问题。您已经传递了 UV 坐标。这是您的 main.cpp sn-p 中的最后一个 glVertexAttribPointer 调用(这并不完全正确,每个 texcoord 只有 2 个元素,而不是 3 个)。您如何将到目前为止编写的源代码上传到某个地方?这样我就可以尝试重现您的问题,修复您的代码,以便您从中学习。
    • 我还没有通过紫外线,因为我还没有计算它们。我已经像你说的那样激活了最后一个 glVertexAttribPointer,但我还没有传递任何东西,因为我不明白 UV 坐标与我试图包裹在球体上的图像的颜色有什么关系
    • @TestTest:UV坐标通常不计算(少数情况除外),而是由一些艺术家应用。纹理是图像。图像的左下角在 (0,0),右上角在 (1,1)。三角形的每个顶点都被分配了一个 [0,1] 范围内的 2 个值,这使得三角形从纹理中采样。
    • "UV 坐标通常不计算" 那么opengl 是如何知道它们的呢?
    【解决方案2】:

    问题“如何将图像文件坐标 (UV) 转换为 3D 坐标?”听起来颠倒了。您应该问“如何将球体坐标 (3D) 转换为图像坐标 (UV)?教程示例使用 Blender 创建 UV 数据的静态数组。如果您正在计算球体的顶点,则需要计算UV 坐标同时存储在 Vertex 结构体中。或者如果你有一组预先计算好的静态球体坐标,你需要计算一组类似的 UV 坐标。想法是取 3D 数据并传递它通过一个映射函数,该函数返回纹理像素用于该 3D 点的 U、V 坐标。

    最简单的计算是使用极坐标(方位角、高度)并将其映射到 U、V 范围的计算。如果正在计算球体 3D 顶点,则算法很可能已经使用极坐标并调用三角函数来获取 X、Y、Z。

    opengl.org 链接提到'cubemap' 是对球体进行纹理化的首选方法。 “为了获得最佳效果,请使用立方体贴图。应用 2D 纹理的问题在于,当您将 2D 纹理包裹到球体上时,球体的顶部和底部区域会显得纹理被挤压。”

    您提出的 2D 地图在环绕球体或其他 3D 曲线时总是会出现变形。可以调整 U、V 映射算法以最小化影响或将接缝隐藏在主要视线之外,但如果球体旋转,它们会出现在某个地方。

    【讨论】:

    • 这是我不明白的。我可以像你在我的顶点结构中所说的那样轻松计算 UV 坐标并将它们存储起来,然后将它们传递给顶点着色器。但我不明白的是图像与所有这些 UV 坐标的关系,我的意思是颜色等
    • @TestTest:也许这个视频说得很清楚。左窗格是纹理,图像的左下角是(U,V)=(0,0),右上角是(U,V)=(1,1),右窗格是一些几何图形,在这种情况下一个三角形。 youtube.com/watch?v=I0kP_YA5oE0
    猜你喜欢
    • 2017-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-23
    • 2011-09-08
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    相关资源
    最近更新 更多