【问题标题】:SDL OpenGL Normal mappingSDL OpenGL 法线映射
【发布时间】:2014-04-05 20:56:40
【问题描述】:

在 SDL 中将法线贴图应用于带纹理的四顶点多边形的最简单方法是什么?你必须创建一个着色器还是有更简单的方法?我在这里有我的代码,它创建了一个带有旋转卫星灯的带纹理的旋转立方体。

如果我还想将生成的纹理 (tex_Norm = generateTexture()) 用作法线贴图,我需要对我的代码做哪些补充?

#include <windows.h>
#include <SDL.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <GL/glext.h>

#include <math.h>

void            initAll();
void            setupBox();
void            mainloop();
unsigned int    generateTexture();
void            handle_inputs();
void            updateScreen();
void            clean_up();

int             scrWidth, scrHeight, flags;
bool            bQuit = false;
float           angle = 0.0f;

GLuint          tex_Box, tex_Norm;

struct sVert
{
    float x;
    float y;
    float z;
};

class cPolygon
{
public:
    int v[4];

    void fillverts(int v1, int v2, int v3, int v4) {
        v[0] = v1;
        v[1] = v2;
        v[2] = v3;
        v[3] = v4;
    }
} p[6];

sVert pv[8];

int main(int argc, char *argv[])
{
    initAll();
    mainloop();
    clean_up();
    return 0;
}

void initAll()
{
    scrWidth = 800;
    scrHeight = 600;

    SDL_InitSubSystem(SDL_INIT_VIDEO);
    SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
    SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
    SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );

    flags = SDL_OPENGL | SDL_ANYFORMAT ;

    SDL_SetVideoMode(scrWidth, scrHeight, 16, flags);
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity( );
    gluPerspective( 45.0f, (GLfloat)scrWidth/(GLfloat)scrHeight, 1.0f, 500.0f );
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity( );

    glEnable (GL_DEPTH_TEST);
    glEnable (GL_LIGHTING);
    glEnable (GL_LIGHT0);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);

    SDL_WM_SetCaption( "Normal Mapping", NULL );

    tex_Box = generateTexture();
    tex_Norm = generateTexture();

    setupBox();
}

void setupBox()
{

    for (int z=0;z<2;z++)
    for (int y=0;y<2;y++)
    for (int x=0;x<2;x++)
    {
        pv[x+y*2+z*4].x = -1.0+x;
        pv[x+y*2+z*4].y = -1.0+y;
        pv[x+y*2+z*4].z = -1.0+z;
    }

    // Box object
    p[0].fillverts (0, 1, 3, 2);    // above
    p[1].fillverts (4, 5, 1, 0);    // behind
    p[2].fillverts (6, 7, 3, 2);    // in front
    p[3].fillverts (5, 7, 3, 1);    // right
    p[4].fillverts (0, 2, 6, 4);    // left
    p[5].fillverts (7, 6, 4, 5);    // below
}

unsigned int generateTexture()
{
    BYTE    data[128*128*3];
    unsigned int id;

    for (int x=0;x<128;x++)
        for (int y=0;y<128;y++)
        {
            data[y*128*3+x*3+0] = x;        // Red
            data[y*128*3+x*3+1] = y;        // Green
            data[y*128*3+x*3+2] = 128-(abs(64-x)+abs(64-y));    // Blue
        }

    glGenTextures(1, &id); 
    glBindTexture(GL_TEXTURE_2D, id); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, GL_BYTE, data);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 

    return id;
}

void mainloop()
{
    while(bQuit == false)
    {
        handle_inputs();
        updateScreen();
        angle += 1.5f;
        Sleep(50);
    }
}

void handle_inputs()
{
    SDL_PumpEvents();
    Uint8 * keystate = SDL_GetKeyState(NULL);
    if(keystate[SDLK_ESCAPE]) bQuit = true;
}

void updateScreen()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glPushMatrix();

    glTranslatef(0.0f, 0.0f, -3.0f);        
    glRotatef(-angle*2.0, 1.0f, 1.0f, 1.0f);

    // Setup a light source
    float lpos[] = {0.0, 0.0, 2.0, 1.0};    // position
    float ldif[] = {1.0, 1.0, 1.0, 1.0};    // diffuse 
    float lamb[] = {0.3, 0.3, 0.2, 1.0};    // ambient 

    glLightfv(GL_LIGHT0, GL_POSITION, lpos);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, ldif);
    glLightfv(GL_LIGHT0, GL_AMBIENT, lamb);

    glPopMatrix();
    glPushMatrix();

    glTranslatef(0.5f, 0.5f, -3.0f);        
    glRotatef(angle, 1.0f, 1.0f, 1.0f); 

    // Draw box object
    glBindTexture(GL_TEXTURE_2D, tex_Box);
    glEnable(GL_TEXTURE_2D);
    glBegin(GL_QUADS);

    for(int pi=0; pi<6; pi++)
        for(int vi=0; vi<4; vi++)
        {
            switch(vi) {
            case 0: glTexCoord2d(0.0,2.0); break;
            case 1: glTexCoord2d(0.0,0.0); break;
            case 2: glTexCoord2d(2.0,0.0); break;
            case 3: glTexCoord2d(2.0,2.0); break; };

            glVertex3f( pv[ p[pi].v[vi] ].x, 
                        pv[ p[pi].v[vi] ].y, 
                        pv[ p[pi].v[vi] ].z );

        };

    glEnd();
    glDisable(GL_TEXTURE_2D);
    glPopMatrix();

    glFinish();
    SDL_GL_SwapBuffers();
}

void clean_up()
{
    SDL_QuitSubSystem(SDL_INIT_VIDEO);
    glDeleteTextures(1, &tex_Box);
    glDeleteTextures(1, &tex_Norm);
    SDL_Quit();
}

【问题讨论】:

    标签: opengl sdl bump-mapping


    【解决方案1】:

    抱歉,如果你想使用现代 OpenGL 功能,你需要现代 OpenGL,这意味着着色器。 :( 这也意味着您的所有照明都需要在着色器中手动完成,因此您的程序会变得相当复杂,但这就是您为酷图像付出的代价。

    这里不适合详细解释如何进行法线贴图,但是那里有很好的教程,例如http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/

    祝你好运!

    【讨论】:

    • 我已经阅读了一些 Shader 教程但没有理解它们。当您说“这也意味着您的所有照明都需要在着色器中手动完成”时,您的回答中就有一些东西,我也从未意识到这一点。实际上,我还没有找到任何教程,从我在示例中的简单方式到使用 Shader 进行,并解释了必须使用 Shader 完成事情的区别。是否也在 Shader 中将纹理应用于网格?我的意思是,在我实现了 Shader 之后,我的“updateScreen()”函数就不会剩下太多了,对吧?
    【解决方案2】:

    经过几个小时的冒险进入 GLSL 的世界并从这个问题的答案中得到一些帮助:SDL OpenGL in C++, Texture Shader missing the texture

    ...我终于用我生成的纹理制作了一张法线贴图。结果如下:

    #include <windows.h>
    #include <SDL.h>
    
    #include <GL/glew.h>
    #include <GL/glu.h>
    #include <GL/glut.h>
    #include <stdio.h>
    
    #include <math.h>
    #include <string>
    
    using namespace std;
    #define LOG_SIZE 10000
    
    void            initAll();
    void            setupBox();
    void            mainloop();
    unsigned int    generateTexture();
    void            handle_inputs();
    void            updateScreen();
    void            clean_up();
    void            dbpf(int, const char *, ...);
    
    int             scrWidth, scrHeight, flags;
    bool            bQuit = false;
    float           angle = 0.0f;
    
    va_list         m;
    int             db_threashold = 0;
    GLint           status;
    GLchar          elog[LOG_SIZE];
    GLint           rLength = 0;
    
    GLuint          tex_Box, tex_Norm;
    
    std::string     vertex_source, fragment_source;
    GLuint          shader_program, vertex_shader, fragment_shader;
    
    GLuint          vao, vbo;
    
    const char      *source;
    int             length;
    
    struct sVert
    {
        float x;
        float y;
        float z;
    };
    
    class cPolygon
    {
    public:
        int v[4];
    
        void fillverts(int v1, int v2, int v3, int v4) {
            v[0] = v1;
            v[1] = v2;
            v[2] = v3;
            v[3] = v4;
        }
    } p[6];
    
    sVert pv[8];
    
    int main(int argc, char *argv[])
    {
        initAll();
        mainloop();
        clean_up();
        return 0;
    }
    
    void initAll()
    {
        scrWidth = 800;
        scrHeight = 600;
    
        vertex_source =
            "#version 330\n"
            "in vec3 Position;\n"
            "in vec2 TexCoord;\n"
            "out vec3 oColor;\n"
            "out vec2 oTexcoord;\n"
            "void main() {\n"
            "    oTexcoord = TexCoord;\n"
            "    gl_Position = gl_ModelViewProjectionMatrix*vec4(Position, 1.0);\n"
            "}\n";
    
        fragment_source =
            "#version 330\n"
            "in vec2 oTexcoord;\n"
            "out vec4 oColor;\n"
            "uniform sampler2D tex;\n"
            "uniform sampler2D tex_norm;\n"
            "void main() {\n"
            "   vec4 lightpos = normalize(-gl_ModelViewProjectionMatrix*vec4(1.0, -1.0, -1.5, 1.0));\n"
            "   vec3 tmpNorm = normalize(texture2D(tex_norm, oTexcoord).rgb * 2.0 - 1.0);\n"
            "   float difuse = max(dot(tmpNorm, lightpos.xyz), 0.0);\n"
            "   vec3 tmpcolor = difuse * texture2D(tex, oTexcoord).rgb;\n"
            "   oColor = vec4(tmpcolor, 1.0);\n"
            "}\n";
    
        SDL_InitSubSystem(SDL_INIT_VIDEO);
        SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
        SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
        SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
        SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
        SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
        SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
    
        flags = SDL_OPENGL | SDL_ANYFORMAT ;
    
        SDL_SetVideoMode(scrWidth, scrHeight, 16, flags);
    
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity( );
        gluPerspective( 45.0f, (GLfloat)scrWidth/(GLfloat)scrHeight, 1.0f, 500.0f );
        glMatrixMode( GL_MODELVIEW );
        glLoadIdentity( );
    
        glEnable (GL_DEPTH_TEST);
        glEnable (GL_LIGHTING);
        glEnable (GL_LIGHT0);
    
        SDL_WM_SetCaption( "Normal map", NULL );
    
        glewInit();
    
        // vertex shader
        vertex_shader = glCreateShader(GL_VERTEX_SHADER);
        source = vertex_source.c_str();
        length = vertex_source.size();
        glShaderSource(vertex_shader, 1, &source, &length); 
        glCompileShader(vertex_shader);
    
        glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &status);
        glGetShaderInfoLog(vertex_shader, LOG_SIZE, &rLength, elog);
        dbpf(10, "Compile vertex log: \n %s \n", elog);
    
        // fragment shader
        fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
        source = fragment_source.c_str();
        length = fragment_source.size();
        glShaderSource(fragment_shader, 1, &source, &length);
        glCompileShader(fragment_shader);
    
        glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &status);
        glGetShaderInfoLog(fragment_shader, LOG_SIZE, &rLength, elog);
        dbpf(10, "Compile fragment log: \n %s \n", elog);
    
        // create program
        shader_program = glCreateProgram();
    
        // attach shaders
        glAttachShader(shader_program, vertex_shader);
        glAttachShader(shader_program, fragment_shader);
    
        // link the program and check for errors
        glLinkProgram(shader_program);
        glGetProgramiv(shader_program, GL_LINK_STATUS, &status);
        glGetProgramInfoLog(shader_program, LOG_SIZE, &rLength, elog);
        dbpf(10, "Link log: \n %s \n", elog);
    
        glGenVertexArrays(1, &vao);
        glBindVertexArray(vao);
    
        glGenBuffers(1, &vbo);
        glBindBuffer(GL_ARRAY_BUFFER, vbo);
    
        setupBox();
    
        GLfloat vd[6*5*6];
    
        for(int pi=0; pi<6; pi++)
        {
            vd[pi*30+ 0] = pv[ p[pi].v[0] ].x;
            vd[pi*30+ 1] = pv[ p[pi].v[0] ].y;
            vd[pi*30+ 2] = pv[ p[pi].v[0] ].z;
    
            vd[pi*30+ 3] = 0.0;
            vd[pi*30+ 4] = 1.0;
    
            vd[pi*30+ 5] = pv[ p[pi].v[1] ].x;
            vd[pi*30+ 6] = pv[ p[pi].v[1] ].y;
            vd[pi*30+ 7] = pv[ p[pi].v[1] ].z;
    
            vd[pi*30+ 8] = 0.0;
            vd[pi*30+ 9] = 0.0;
    
            vd[pi*30+10] = pv[ p[pi].v[2] ].x;
            vd[pi*30+11] = pv[ p[pi].v[2] ].y;
            vd[pi*30+12] = pv[ p[pi].v[2] ].z;
    
            vd[pi*30+13] = 1.0;
            vd[pi*30+14] = 0.0;
    
            vd[pi*30+15] = pv[ p[pi].v[0] ].x;
            vd[pi*30+16] = pv[ p[pi].v[0] ].y;
            vd[pi*30+17] = pv[ p[pi].v[0] ].z;
    
            vd[pi*30+18] = 0.0;
            vd[pi*30+19] = 1.0;
    
            vd[pi*30+20] = pv[ p[pi].v[2] ].x;
            vd[pi*30+21] = pv[ p[pi].v[2] ].y;
            vd[pi*30+22] = pv[ p[pi].v[2] ].z;
    
            vd[pi*30+23] = 1.0;
            vd[pi*30+24] = 0.0;
    
            vd[pi*30+25] = pv[ p[pi].v[3] ].x;
            vd[pi*30+26] = pv[ p[pi].v[3] ].y;
            vd[pi*30+27] = pv[ p[pi].v[3] ].z;
    
            vd[pi*30+28] = 1.0;
            vd[pi*30+29] = 1.0;
        }
    
        glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*6*5*6, vd, GL_STATIC_DRAW);
    
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (char*)0 + 0*sizeof(GLfloat));
    
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (char*)0 + 3*sizeof(GLfloat));
    
        tex_Box = generateTexture();
        tex_Norm = generateTexture();
    }
    
    void setupBox()
    {
    
        for (int z=0;z<2;z++)
        for (int y=0;y<2;y++)
        for (int x=0;x<2;x++)
        {
            pv[x+y*2+z*4].x = -1.0+x;
            pv[x+y*2+z*4].y = -1.0+y;
            pv[x+y*2+z*4].z = -1.0+z;
        }
    
        p[0].fillverts (0, 1, 3, 2);    // above
        p[1].fillverts (4, 5, 1, 0);    // behind
        p[2].fillverts (6, 7, 3, 2);    // in front
        p[3].fillverts (5, 7, 3, 1);    // right
        p[4].fillverts (0, 2, 6, 4);    // left
        p[5].fillverts (7, 6, 4, 5);    // below
    }
    
    unsigned int generateTexture()
    {
        BYTE    data[128*128*3];
        unsigned int id;
    
        for (int x=0;x<128;x++)
            for (int y=0;y<128;y++)
            {
                data[y*128*3+x*3+0] = x;        // Red
                data[y*128*3+x*3+1] = y;        // Green
                data[y*128*3+x*3+2] = 128-(abs(64-x)+abs(64-y));    // Blue
            }
    
        glGenTextures(1, &id); 
        glBindTexture(GL_TEXTURE_2D, id); 
        glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); 
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);
    
        return id;
    }
    
    void mainloop()
    {
        while(bQuit == false)
        {
            handle_inputs();
            updateScreen();
            angle += 1.5f;
            Sleep(50);
        }
    }
    
    void handle_inputs()
    {
        SDL_PumpEvents();
        Uint8 * keystate = SDL_GetKeyState(NULL);
        if(keystate[SDLK_ESCAPE]) bQuit = true;
    }
    
    void updateScreen()
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glLoadIdentity();
    
        gluLookAt (2.0, 2.0, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    
        // use the shader program
        glUseProgram(shader_program);
    
        // bind the vao
        glBindVertexArray(vao);
    
        // rotation
        glRotatef(angle, 1.0, 0.0, 0.0); //rotate on the x axis
        glRotatef(angle, 0.0, 1.0, 0.0); //rotate on the y axis
        glRotatef(angle, 0.0, 0.0, 1.0); //rotate on the z axis
    
        // bind texture
        glActiveTexture(GL_TEXTURE0);
        int loc = glGetUniformLocation(shader_program, "tex");
        glUniform1i(loc, 0); 
        glBindTexture(GL_TEXTURE_2D, tex_Box);
    
        // bind normal texture
        glActiveTexture(GL_TEXTURE1);
        loc = glGetUniformLocation(shader_program, "tex_norm");
        glUniform1i(loc, 1); 
        glBindTexture(GL_TEXTURE_2D, tex_Norm);
    
        // draw
        glDrawArrays(GL_TRIANGLES, 0, 6*6);
    
        // cleanup
        glActiveTexture(GL_TEXTURE1); 
        glBindTexture(GL_TEXTURE_2D, 0); 
        glDisable(GL_TEXTURE_2D);
    
        glActiveTexture(GL_TEXTURE0); 
        glBindTexture(GL_TEXTURE_2D, 0);
        glDisable(GL_TEXTURE_2D);
    
        glUseProgram(0);
        SDL_GL_SwapBuffers();
    }
    
    void clean_up()
    {
        glDeleteVertexArrays(1, &vao);
        glDeleteBuffers(1, &vbo);
    
        glDetachShader(shader_program, vertex_shader);
        glDetachShader(shader_program, fragment_shader);
        glDeleteShader(vertex_shader);
        glDeleteShader(fragment_shader);
        glDeleteProgram(shader_program);
    
        SDL_QuitSubSystem(SDL_INIT_VIDEO);
        glDeleteTextures(1, &tex_Box);
        glDeleteTextures(1, &tex_Norm);
        SDL_Quit();
    }
    
    void dbpf(int t, const char * msg, ...)
    {
        va_start(m, msg);
        if (t >= db_threashold) vfprintf(stderr, msg, m);
        va_end(m);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-10-04
      • 2017-03-28
      • 2011-10-12
      • 1970-01-01
      • 2011-05-04
      • 2011-03-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多