OpenGL - vertex normals in OBJ

后端 未结 1 992
陌清茗
陌清茗 2020-11-21 15:01

I want to know how can I use the vertex normals for lightning effect? Currently what I have is I can send both vertex and texture coords to the shader and use them but with

相关标签:
1条回答
  • 2020-11-21 15:40

    normal/bump maps

    Provide fine details without increasing complexity of geometry that means more details at very low performance cost. Normal/bump maps are optional of coarse.

    normal shading (fragment shader)

    Normal is vector perpendicular to fragment/face/primitive there are 2 use for it:

    1. dull surface illumination

      lets have:

      • color - per fragment/face/primitive color (modulated with texture)
      • normal - per fragment/face/primitive 3D normal vector (pointing out of mesh)
      • lt_ambient,lt_direct - the lights color and strength
      • lt_direct_dir - directional light direction

      then the output is easy:

      • fragment_color=(lt_ambient+(lt_direct*dot(lt_direct_dir,-normal))*color;

      this is called normal shading

      dot returns the cos(angle between light and normal) if you want to have booth sides geometries then use fabs(dot(...)). The light color and strength vectors summed together should not exceed 1.0 per channel otherwise clamping could cause color artifacts. Use for example:

      • lt_ambient=(0.2,0.2,0.2)
      • lt_direct =(0.8,0.8,0.8)

      as lt_direct_dir you can use (fragment_xyz-Sun.xyz) and normalize to unit vector or use camera view direction. You need to have unit vector for dot product otherwise it will not work properly

    2. reflection

      if you have any environment map (cube_map) then you can add reflections. You got the fragment (x,y,z) coordinates and normal so you can compute direction of reflected viewing direction and add the texel to which is it pointing to the result fragment_color.

      There are more stuff like specular highlights and different light equations but I think you should start with normal shading first. When you got the basics then is no problem to understand the more advanced stuff just always remember what is behind ...

    [edit1] well as you are rookie then you obviously need complete example to start with:

    So here complete GL+VAO/VBO+GLSL+shaders example in C++. As I use Borland environment it is in VCL form app so just ignore the VCL stuff and extract only what you need. This is how it looks like:

    That cross is my point light position to visually check the correctness and that arrow (hand drawed) shows average light direction.

    normal_shading.glsl_vert

    // Vertex
    #version 400 core
    layout(location = 0) in vec3 pos;
    layout(location = 2) in vec3 nor;
    layout(location = 3) in vec3 col;
    uniform mat4 m_model;   // model matrix
    uniform mat4 m_normal;  // model matrix with origin=(0,0,0)
    uniform mat4 m_view;    // inverse of camera matrix
    uniform mat4 m_proj;    // projection matrix
    out vec3 pixel_pos;     // fragment position [GCS]
    out vec3 pixel_col;     // fragment surface color
    out vec3 pixel_nor;     // fragment surface normal [GCS]
    void main()
        {
        pixel_col=col;
        pixel_pos=(m_model*vec4(pos,1)).xyz;
        pixel_nor=(m_normal*vec4(nor,1)).xyz;
        gl_Position=m_proj*m_view*m_model*vec4(pos,1);
        }
    

    normal_shading.glsl_frag

    // Fragment
    #version 400 core
    uniform vec3 lt_pnt_pos;// point light source position [GCS]
    uniform vec3 lt_pnt_col;// point light source color&strength
    uniform vec3 lt_amb_col;// ambient light source color&strength
    in vec3 pixel_pos;      // fragment position [GCS]
    in vec3 pixel_col;      // fragment surface color
    in vec3 pixel_nor;      // fragment surface normal [GCS]
    out vec4 col;
    void main()
        {
        float li;
        vec3 c,lt_dir;
        lt_dir=normalize(lt_pnt_pos-pixel_pos); // vector from fragment to point light source in [GCS]
        li=dot(pixel_nor,lt_dir);
        if (li<0.0) li=0.0;
        c=pixel_col*(lt_amb_col+(lt_pnt_col*li));
        col=vec4(c,1.0);
        }
    

    gl_simple.h

    //---------------------------------------------------------------------------
    //--- GL simple ver: 1.000 --------------------------------------------------
    //---------------------------------------------------------------------------
    #define GLEW_STATIC
    #include "glew.c"
    #include <gl\gl.h>
    #include <gl\glu.h>
    //---------------------------------------------------------------------------
    //--- OpenGL GL example -----------------------------------------------------
    //---------------------------------------------------------------------------
    int     xs,ys;      // screen size
    HDC     hdc=NULL;   // device context
    HGLRC   hrc=NULL;   // rendering context
    int  gl_inicialized=0;
    int  gl_init(HWND Handle);
    void gl_exit();
    void gl_draw();
    void gl_resize(int _xs,int _ys);
    //---------------------------------------------------------------------------
    //--- OpenGL GLSL example ---------------------------------------------------
    //---------------------------------------------------------------------------
    GLint prog_id=0,    // whole program
          vert_id=0,    // vertex shader
          frag_id=0;    // fragment shader
    char  glsl_log[4096];// compile/link GLSL log
    int   glsl_logs=0;
    void  glsl_init(char *vert,char *frag);     // create/compile/link GLSL program
    void  glsl_exit();
    //---------------------------------------------------------------------------
    //--- OpenGL VAO example ----------------------------------------------------
    //---------------------------------------------------------------------------
    #pragma pack(1)
    //#define vao_indices
    GLuint vbo[4]={-1,-1,-1,-1};
    GLuint vao[4]={-1,-1,-1,-1};
    const GLfloat vao_pos[]=
        {
    //  x    y    z     //ix
        -1.0,+1.0,-1.0, //0
        +1.0,+1.0,-1.0, //1
        +1.0,-1.0,-1.0, //2
        -1.0,-1.0,-1.0, //3
    
        -1.0,-1.0,+1.0, //4
        +1.0,-1.0,+1.0, //5
        +1.0,+1.0,+1.0, //6
        -1.0,+1.0,+1.0, //7
    
        #ifndef vao_indices
        -1.0,-1.0,-1.0, //3
        +1.0,-1.0,-1.0, //2
        +1.0,-1.0,+1.0, //5
        -1.0,-1.0,+1.0, //4
    
        +1.0,-1.0,-1.0, //2
        +1.0,+1.0,-1.0, //1
        +1.0,+1.0,+1.0, //6
        +1.0,-1.0,+1.0, //5
    
        +1.0,+1.0,-1.0, //1
        -1.0,+1.0,-1.0, //0
        -1.0,+1.0,+1.0, //7
        +1.0,+1.0,+1.0, //6
    
        -1.0,+1.0,-1.0, //0
        -1.0,-1.0,-1.0, //3
        -1.0,-1.0,+1.0, //4
        -1.0,+1.0,+1.0, //7
        #endif
        };
    
    const GLfloat vao_col[]=
        {
    //  r   g   b    //ix
        0.0,0.0,0.0, //0
        1.0,0.0,0.0, //1
        1.0,1.0,0.0, //2
        0.0,1.0,0.0, //3
        0.0,0.0,1.0, //4
        1.0,0.0,1.0, //5
        1.0,1.0,1.0, //6
        0.0,1.0,1.0, //7
    
        #ifndef vao_indices
        0.0,0.0,0.0, //0
        1.0,0.0,0.0, //1
        1.0,0.0,1.0, //5
        0.0,0.0,1.0, //4
    
        1.0,0.0,0.0, //1
        1.0,1.0,0.0, //2
        1.0,1.0,1.0, //6
        1.0,0.0,1.0, //5
    
        1.0,1.0,0.0, //2
        0.0,1.0,0.0, //3
        0.0,1.0,1.0, //7
        1.0,1.0,1.0, //6
    
        0.0,1.0,0.0, //3
        0.0,0.0,0.0, //0
        0.0,0.0,1.0, //4
        0.0,1.0,1.0, //7
        #endif
        };
    
    #ifndef vao_indices
    const GLfloat vao_nor[]=
        {
    //   nx   ny   nz   //ix
         0.0, 0.0,-1.0, //0
         0.0, 0.0,-1.0, //1
         0.0, 0.0,-1.0, //2
         0.0, 0.0,-1.0, //3
    
         0.0, 0.0,+1.0, //4
         0.0, 0.0,+1.0, //5
         0.0, 0.0,+1.0, //6
         0.0, 0.0,+1.0, //7
    
         0.0,-1.0, 0.0, //0
         0.0,-1.0, 0.0, //1
         0.0,-1.0, 0.0, //5
         0.0,-1.0, 0.0, //4
    
        +1.0, 0.0, 0.0, //1
        +1.0, 0.0, 0.0, //2
        +1.0, 0.0, 0.0, //6
        +1.0, 0.0, 0.0, //5
    
         0.0,+1.0, 0.0, //2
         0.0,+1.0, 0.0, //3
         0.0,+1.0, 0.0, //7
         0.0,+1.0, 0.0, //6
    
        -1.0, 0.0, 0.0, //3
        -1.0, 0.0, 0.0, //0
        -1.0, 0.0, 0.0, //4
        -1.0, 0.0, 0.0, //7
        };
    #endif
    
    #ifdef vao_indices
    const GLuint vao_ix[]=
        {
        0,1,2,3,
        4,5,6,7,
        3,2,5,4,
        2,1,6,5,
        1,0,7,6,
        0,3,4,7,
        };
    #endif
    
    #pragma pack()
    void vao_init();
    void vao_exit();
    void vao_draw();
    //---------------------------------------------------------------------------
    //--- bodies: ---------------------------------------------------------------
    //---------------------------------------------------------------------------
    int gl_init(HWND Handle)
        {
        if (gl_inicialized) return 1;
        hdc = GetDC(Handle);            // get device context
        PIXELFORMATDESCRIPTOR pfd;
        ZeroMemory( &pfd, sizeof( pfd ) );      // set the pixel format for the DC
        pfd.nSize = sizeof( pfd );
        pfd.nVersion = 1;
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
        pfd.iPixelType = PFD_TYPE_RGBA;
        pfd.cColorBits = 24;
        pfd.cDepthBits = 24;
        pfd.iLayerType = PFD_MAIN_PLANE;
        SetPixelFormat(hdc,ChoosePixelFormat(hdc, &pfd),&pfd);
        hrc = wglCreateContext(hdc);            // create current rendering context
        if(hrc == NULL)
                {
                ShowMessage("Could not initialize OpenGL Rendering context !!!");
                gl_inicialized=0;
                return 0;
                }
        if(wglMakeCurrent(hdc, hrc) == false)
                {
                ShowMessage("Could not make current OpenGL Rendering context !!!");
                wglDeleteContext(hrc);          // destroy rendering context
                gl_inicialized=0;
                return 0;
                }
        gl_resize(1,1);
        glEnable(GL_DEPTH_TEST);                // Zbuf
        glDisable(GL_CULL_FACE);                // vynechavaj odvratene steny
        glDisable(GL_TEXTURE_2D);               // pouzivaj textury, farbu pouzivaj z textury
        glDisable(GL_BLEND);                    // priehladnost
        glShadeModel(GL_SMOOTH);                // gourard shading
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);   // background color
        gl_inicialized=1;
        glewInit();
        return 1;
        }
    //---------------------------------------------------------------------------
    void gl_exit()
        {
        if (!gl_inicialized) return;
        wglMakeCurrent(NULL, NULL);     // release current rendering context
        wglDeleteContext(hrc);          // destroy rendering context
        gl_inicialized=0;
        }
    //---------------------------------------------------------------------------
    void gl_resize(int _xs,int _ys)
        {
        xs=_xs;
        ys=_ys;
        if (xs<=0) xs = 1;                  // Prevent a divide by zero
        if (ys<=0) ys = 1;
        if (!gl_inicialized) return;
        glViewport(0,0,xs,ys);              // Set Viewport to window dimensions
        glMatrixMode(GL_PROJECTION);        // operacie s projekcnou maticou
        glLoadIdentity();                   // jednotkova matica projekcie
        gluPerspective(30,float(xs)/float(ys),0.1,100.0); // matica=perspektiva,120 stupnov premieta z viewsize do 0.1
        glMatrixMode(GL_TEXTURE);           // operacie s texturovou maticou
        glLoadIdentity();                   // jednotkova matica textury
        glMatrixMode(GL_MODELVIEW);         // operacie s modelovou maticou
        glLoadIdentity();                   // jednotkova matica modelu (objektu)
        }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    void glsl_init(char *vert,char *frag)
        {
        const int _size=1024;
        GLint status,siz=0,i;
        const char * VS = vert;
        const char * FS = frag;
        glsl_logs=0;
        if (prog_id<=0) prog_id=glCreateProgram();
    
        if (vert_id<=0) vert_id=glCreateShader(GL_VERTEX_SHADER); else glDetachShader(prog_id,vert_id);
        if (vert)
            {
            glShaderSource(vert_id, 1, &VS,NULL);
            glCompileShader(vert_id);
            glAttachShader(prog_id,vert_id);
            glGetShaderiv(vert_id,GL_COMPILE_STATUS,&status);
            const char t[]="[Vertex]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
            glGetShaderInfoLog(vert_id,_size,&siz,glsl_log+glsl_logs);
            glsl_logs+=siz;
            }
        if (frag_id<=0) frag_id=glCreateShader(GL_FRAGMENT_SHADER); else glDetachShader(prog_id,frag_id);
        if (frag)
            {
            glShaderSource(frag_id, 1, &FS,NULL);
            glCompileShader(frag_id);
            glAttachShader(prog_id,frag_id);
            glGetShaderiv(frag_id,GL_COMPILE_STATUS,&status);
            const char t[]="[Fragment]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
            glGetShaderInfoLog(frag_id,_size,&siz,glsl_log+glsl_logs);
            glsl_logs+=siz;
            }
        glLinkProgram(prog_id);
        glGetProgramiv(prog_id,GL_LINK_STATUS,&status);
        const char t[]="[Program]\r\n"; for (i=0;t[i];i++) { glsl_log[glsl_logs]=t[i]; glsl_logs++; }
        glGetProgramInfoLog(prog_id,_size,&siz,glsl_log+glsl_logs);
        glsl_logs+=siz;
    
        glReleaseShaderCompiler();
        glsl_log[glsl_logs]=0;
        }
    //------------------------------------------------------------------------------
    void glsl_exit()
        {
        glUseProgram(0);
        if (vert_id>0) { glDetachShader(prog_id,vert_id); glDeleteShader(vert_id); }
        if (frag_id>0) { glDetachShader(prog_id,frag_id); glDeleteShader(frag_id); }
        if (prog_id>0) {                                  glDeleteShader(prog_id); }
        glsl_log[0]=0;
        }
    //---------------------------------------------------------------------------
    //------------------------------------------------------------------------------
    void vao_init()
        {
        GLuint i;
        glGenVertexArrays(4,vao);
        glGenBuffers(4,vbo);
        glBindVertexArray(vao[0]);
        i=0; // vertex
        glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vao_pos),vao_pos,GL_STATIC_DRAW);
        glEnableVertexAttribArray(i);
        glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
        i=1; // indices
        #ifdef vao_indices
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,vbo[i]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(vao_ix),vao_ix,GL_STATIC_DRAW);
        glEnableVertexAttribArray(i);
        glVertexAttribIPointer(i,4,GL_UNSIGNED_INT,0,0);
        #endif
        i=2; // normal
        #ifndef vao_indices
        glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vao_nor),vao_nor,GL_STATIC_DRAW);
        glEnableVertexAttribArray(i);
        glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
        #endif
        i=3; // color
        glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vao_col),vao_col,GL_STATIC_DRAW);
        glEnableVertexAttribArray(i);
        glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
    
        glBindVertexArray(0);
        glBindBuffer(GL_ARRAY_BUFFER,0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
        glDisableVertexAttribArray(2);
        glDisableVertexAttribArray(3);
        }
    //---------------------------------------------------------------------------
    void vao_exit()
        {
        glDeleteVertexArrays(4,vao);
        glDeleteBuffers(4,vbo);
        }
    //---------------------------------------------------------------------------
    void vao_draw()
        {
        glBindVertexArray(vao[0]);
        #ifndef vao_indices
        glDrawArrays(GL_QUADS,0,sizeof(vao_pos)/sizeof(vao_pos[0]));                    // QUADS ... no indices
        #endif
        #ifdef vao_indices
        glDrawElements(GL_QUADS,sizeof(vao_ix)/sizeof(vao_ix[0]),GL_UNSIGNED_INT,0);    // indices (choose just one line not both !!!)
        #endif
        glBindVertexArray(0);
        }
    //------------------------------------------------------------------------------
    //------------------------------------------------------------------------------
    

    VCL App main form source:

    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
    #include "Unit1.h"
    #include "gl_simple.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    GLfloat lt_pnt_pos[3]={+2.5,+2.5,+2.5};
    GLfloat lt_pnt_col[3]={0.8,0.8,0.8};
    GLfloat lt_amb_col[3]={0.2,0.2,0.2};
    //---------------------------------------------------------------------------
    void gl_draw()
        {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        // load values into shader
        GLint i,id;
        GLfloat m[16];
        glUseProgram(prog_id);
        id=glGetUniformLocation(prog_id,"lt_pnt_pos"); glUniform3fv(id,1,lt_pnt_pos);
        id=glGetUniformLocation(prog_id,"lt_pnt_col"); glUniform3fv(id,1,lt_pnt_col);
        id=glGetUniformLocation(prog_id,"lt_amb_col"); glUniform3fv(id,1,lt_amb_col);
        glGetFloatv(GL_MODELVIEW_MATRIX,m);
        id=glGetUniformLocation(prog_id,"m_model"   ); glUniformMatrix4fv(id,1,GL_FALSE,m);
        m[12]=0.0; m[13]=0.0; m[14]=0.0;
        id=glGetUniformLocation(prog_id,"m_normal"  ); glUniformMatrix4fv(id,1,GL_FALSE,m);
        for (i=0;i<16;i++) m[i]=0.0; m[0]=1.0; m[5]=1.0; m[10]=1.0; m[15]=1.0;
        id=glGetUniformLocation(prog_id,"m_view"    ); glUniformMatrix4fv(id,1,GL_FALSE,m);
        glGetFloatv(GL_PROJECTION_MATRIX,m);
        id=glGetUniformLocation(prog_id,"m_proj"    ); glUniformMatrix4fv(id,1,GL_FALSE,m);
        // draw VAO cube
        vao_draw();
        // turn of shader
        glUseProgram(0);
        // rotate the cube to see animation
        glMatrixMode(GL_MODELVIEW);
        glRotatef(1.0,0.0,1.0,0.0);
        glRotatef(1.0,1.0,0.0,0.0);
    
        // render point light source in [GCS]
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glLoadIdentity();
        GLfloat x,y,z,d=0.25;
        x=lt_pnt_pos[0];
        y=lt_pnt_pos[1];
        z=lt_pnt_pos[2];
        glBegin(GL_LINES);
        glColor3fv(lt_pnt_col);
        glVertex3f(x-d,y,z);
        glVertex3f(x+d,y,z);
        glVertex3f(x,y-d,z);
        glVertex3f(x,y+d,z);
        glVertex3f(x,y,z-d);
        glVertex3f(x,y,z+d);
        glEnd();
        glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
    
        glFlush();
        SwapBuffers(hdc);
        }
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
        {
        gl_init(Handle);
    
        int hnd,siz; char vertex[4096],fragment[4096];
        hnd=FileOpen("normal_shading.glsl_vert",fmOpenRead); siz=FileSeek(hnd,0,2); FileSeek(hnd,0,0); FileRead(hnd,vertex  ,siz); vertex  [siz]=0; FileClose(hnd);
        hnd=FileOpen("normal_shading.glsl_frag",fmOpenRead); siz=FileSeek(hnd,0,2); FileSeek(hnd,0,0); FileRead(hnd,fragment,siz); fragment[siz]=0; FileClose(hnd);
        glsl_init(vertex,fragment);
        hnd=FileCreate("GLSL.txt"); FileWrite(hnd,glsl_log,glsl_logs); FileClose(hnd);
    
        vao_init();
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormDestroy(TObject *Sender)
        {
        gl_exit();
        glsl_exit();
        vao_exit();
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormResize(TObject *Sender)
        {
        gl_resize(ClientWidth,ClientHeight);
        glMatrixMode(GL_PROJECTION);
        glTranslatef(0,0,-15.0);
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormPaint(TObject *Sender)
        {
        gl_draw();
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Timer1Timer(TObject *Sender)
        {
        gl_draw();
        }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormMouseWheel(TObject *Sender, TShiftState Shift, int WheelDelta, TPoint &MousePos, bool &Handled)
        {
        GLfloat dz=2.0;
        if (WheelDelta<0) dz=-dz;
        glMatrixMode(GL_PROJECTION);
        glTranslatef(0,0,dz);
        gl_draw();
        }
    //---------------------------------------------------------------------------
    

    Do not forget to change the layouts to yours, add textures and stuff only if this is already working and always check GLSL.txt (compile/link log) file to see if all is as should be.

    Also you need GLEW for this so see

    • GLEW sourceforge
    • Building glew on windows with mingw32
    0 讨论(0)
提交回复
热议问题