zoukankan      html  css  js  c++  java
  • OpenGL中的光照技术(翻译)

    Lighting:https://www.evl.uic.edu/julian/cs488/2005-11-03/index.html

    光照

    OpenGL中的光照(Linghting)是很重要的,为什么重要?请看下图

    上图中左图是有光照的效果,右图是没有光照的效果。

    有光照的好处:

    • 给人更多关于曲率和深度的视觉感受
    • 给人更明显的3D效果

    隐藏面清除

    在照明和着色中,深度信息和法向量变得非常重要。

    旧的painter算法是这样的:

    while (1) {

    get_viewing_point_from_mouse_position();

    glClear(GL_COLOR_BUFFER_BIT);

    draw_3d_object_A();

    draw_3d_object_B();

    }

    这样的话,一个对象可能会遮挡另一个对象

    隐藏面清除通过使用Z-buffer(深度缓存)来实现

    请看如下的代码示例:

    glutInitDisplayMode ( GLUT_DEPTH | ... );

    glEnable ( GL_DEPTH_TEST );

    ...

    while(1) {

    glClear( GLCOLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    get_viewing_point_from_mouse_position();

    draw_3d_object_A();

    draw_3d_object_B();

    }

     

    光照组成

    • 环境光(Ambient

        光从各个方向均匀地到达。事实上,光散射太大,我们无法确定它的方向

    • 散射光(Diffuse

        来自点光源的光线将被漫射反射(即在远离表面的所有方向上均匀地重新选择)

    • 镜面光(Specular

        从点光源发出的光线将被镜面反射(即以镜面形式反射,如从光亮的表面反射)。

        

    •     放射光(Emissive

        在没有入射光的情况下,表面的发射率控制着表面发出的光的数量。从一个表面发出的光不能作为照亮其他表面的光源;相反,它只影响观察者看到的颜色。

    多个灯光组件结果

        

    光照和材料的RGB

        RGB values for light and material have different meanings

        For light: light colors(intensities)

        (R, G, B) = (1, 1, 0) -> yellow light

        For material: reflected proportions

     (R, G, B) = (1, 0.5, 0) -> the material reflects all the incoming red light, half the incoming green light, and nonn of the incoming blue light.

        ( LR*MR, LG*MG, LB*MB )

        Multiple light source: Light1 + Light2

        ( R1+R2, G1+G2, B1+B2 )

        If the result is greater than 1.0, clamp to 1.0

    光照例子    

    为所有对象的每个顶点定义法向量。这些法线确定对象相对于光源的方向。(在我们的示例中,法线定义为glutsolidSphere()的一部分)

    • Needs unit normal vector
    • void glEnable(GL_NORMALIZE)
    • void glEnable(GL_RESCALE_NORMAL)

    Create, select, and position one or more light sources.

    可以创建最多8中不同的光源(GL_LIGHT0 to GL_LIGHT7),但是光源多了会导致更多的计算复杂性。

    创建并选择照明模型Light Mode),该模型定义全局环境光的级别和视点的有效位置(用于照明计算)。

    为场景中的对象定义材质属性。

    #include <gl/glut.h>

    #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")

     

    /* Initialize material property, light source, lighting model,

    * and depth buffer.

    */

    void init(void)

    {

    GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };

    GLfloat mat_shininess[] = { 50.0 };

    GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };

    GLfloat light[] = { 1.0, 0.2, 0.2 };

    GLfloat lmodel_ambient[] = { 0.1, 0.1, 0.1, 1.0 };

    glClearColor (0.0, 0.0, 0.0, 0.0);

    glShadeModel (GL_SMOOTH);

     

    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);

    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

     

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glLightfv(GL_LIGHT0, GL_DIFFUSE, light );

    glLightfv(GL_LIGHT0, GL_SPECULAR, light );

    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);

     

    glEnable(GL_LIGHTING);

    glEnable(GL_LIGHT0);

    glEnable(GL_DEPTH_TEST);

    }

     

    void display(void)

    {

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glutSolidSphere (1.0, 20, 16);

    glFlush ();

    }

     

    void reshape (int w, int h)

    {

    glViewport (0, 0, (GLsizei) w, (GLsizei) h);

    glMatrixMode (GL_PROJECTION);

    glLoadIdentity();

    if (w <= h)

    glOrtho (-1.5, 1.5, -1.5*(GLfloat)h/(GLfloat)w,

    1.5*(GLfloat)h/(GLfloat)w, -10.0, 10.0);

    else

    glOrtho (-1.5*(GLfloat)w/(GLfloat)h,

    1.5*(GLfloat)w/(GLfloat)h, -1.5, 1.5, -10.0, 10.0);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    }

     

    int main(int argc, char** argv)

    {

    glutInit(&argc, argv);

    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

    glutInitWindowSize (500, 500);

    glutInitWindowPosition (100, 100);

    glutCreateWindow (argv[0]);

    init ();

    glutDisplayFunc(display);

    glutReshapeFunc(reshape);

    glutMainLoop();

    return 0;

    }

    光照API

    void glLight{if}(GLenum light, GLenum pname, TYPE param);

    void glLight{if}v(GLenum light, GLenum pname, TYPE *param);

    Creates the light specified by light, which can be GL_LIGHT0, GL_LIGHT1, ... , or GL_LIGHT7. The characteristic of the light being set is defined by pname, which specifies a named parameter (see Table below). param indicates the values to which the pname characteristic is set; it's a pointer to a group of values if the vector version is used, or the value itself if the nonvector version is used. The nonvector version can be used to set only single-valued light characteristics.

    衰减(定义光衰减的强度)

    对于现实世界中的灯光,灯光强度随着与灯光的距离的增加而降低。由于定向光无限远,因此在距离上衰减其强度是没有意义的,因此对定向光禁用衰减。但是,您可能希望减弱来自位置光的光。OpenGL通过将光源的贡献乘以衰减因子来衰减光源:

    d = distance between the light's position and the vertex

    kc = GL_CONSTANT_ATTENUATION

    kl = GL_LINEAR_ATTENUATION

    kq = GL_QUADRATIC_ATTENUATION

    By default, kc = 1.0, kl = kq = 0.0.

    可以为这些参数指定不同的值:

        glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 2.0);
    
        glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 1.0);
    
        glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.5);
    

    聚光灯(默认gl_spot_cutoff=180

    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 45.0); 

    GLfloat spot_direction[] = { -1.0, -1.0, 0.0 }; 

    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, spot_direction);

            

    可以设置多个光源

    GLfloat light1_ambient[] = { 0.2, 0.2, 0.2, 1.0 };
    
    GLfloat light1_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
    
    GLfloat light1_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    
    GLfloat light1_position[] = { -2.0, 2.0, 1.0, 1.0 };
    
    GLfloat spot_direction[] = { -1.0, -1.0, 0.0 };
    

     

    glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
    
    glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
    
    glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
    
    glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
    
    glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.5);
    
    glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.5);
    
    glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.2);
    

     

    glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0);
    
    glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction);
    
    glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 2.0);
    

     

    glEnable(GL_LIGHT1);
    

    光源位置(Position)

    • 定向光——光源无限远(W=0
    GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 }; 
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);
    位置的第四个分量是0.0,表示光是定向光。
    默认情况下,GL_POSITION是(0010),它定义了方向光。(xyz)是它的方向。
    • 位置光——有限距离光源(W不是0

     GLfloat light_position[] = { 5.0, 10.0, 2.0, 1.0 }; 
     glLightfv(GL_LIGHT0, GL_POSITION, light_position);

     位置由模型视图矩阵转换并存储在眼睛坐标系中(即相对于眼睛)。

     请注意,默认情况下(即不调用gluLookat()),相机(眼睛)位于原点,指向负Z轴。

     默认情况下,位置光源向所有方向辐射。

     

    移动光源

    • 固定光源

    glViewport (0, 0, (GLsizei) w, (GLsizei) h);

    glMatrixMode (GL_PROJECTION);

    glLoadIdentity();

    if (w <= h)

      glOrtho (-1.5, 1.5, -1.5*h/w, 1.5*h/w, -10.0, 10.0);

    else

      glOrtho (-1.5*w/h, 1.5*w/h, -1.5, 1.5, -10.0, 10.0);

    glMatrixMode (GL_MODELVIEW);

    glLoadIdentity();

    /* later in init() */

    GLfloat light_position[] = { 1.0, 1.0, 1.0, 1.0 };

    glLightfv(GL_LIGHT0, GL_POSITION, position);

     

    • 光源的独立移动

    旋转或平移灯光位置:灯光相对于静止物体移动。

    static GLdouble spin;

    void display(void)

    {

    GLfloat light_position[] = { 0.0, 0.0, 1.5, 1.0 };

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

     

    glPushMatrix();

    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

    glPushMatrix();

    glRotated(spin, 1.0, 0.0, 0.0);

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glPopMatrix();

    glutSolidTorus (0.275, 0.85, 8, 15);

    glPopMatrix();

    glFlush();

    }

     

            

     

    通过模型变换(Model)来移动光源例子:

    #include <GL/glut.h> 

    #pragma comment(linker, "/subsystem:windows /ENTRY:mainCRTStartup")

    static int spin = 0;

    void init(void)

    {

      glClearColor (0.0, 0.0, 0.0, 0.0);

      glShadeModel (GL_SMOOTH);

      glEnable(GL_LIGHTING);

      glEnable(GL_LIGHT0);

      glEnable(GL_DEPTH_TEST);

    }

     

    /* Here is where the light position is reset after the modeling

    * transformation (glRotated) is called. This places the

    * light at a new position in world coordinates. The cube

    * represents the position of the light.

    */

    void display(void)

    {

    GLfloat position[] = { 0.0, 0.0, 1.5, 1.0 };

     

    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glPushMatrix ();

    glTranslatef (0.0, 0.0, -5.0);

     

    glPushMatrix ();

    glRotated ((GLdouble) spin, 1.0, 0.0, 0.0);

    glLightfv (GL_LIGHT0, GL_POSITION, position);

     

    glTranslated (0.0, 0.0, 1.5);

    glDisable (GL_LIGHTING);

    glColor3f (0.0, 1.0, 1.0);

    glutWireCube (0.1);                    // 模拟光源

    glEnable (GL_LIGHTING);

    glPopMatrix ();

     

    glutSolidTorus (0.275, 0.85, 8, 15);

    glPopMatrix ();

    glFlush ();

    }

     

    void reshape (int w, int h)

    {

    glViewport (0, 0, (GLsizei) w, (GLsizei) h);

    glMatrixMode (GL_PROJECTION);

    glLoadIdentity();

    gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 20.0);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    }

     

    void mouse(int button, int state, int x, int y)

    {

    switch (button) {

    case GLUT_LEFT_BUTTON:

    if (state == GLUT_DOWN) {

    spin = (spin + 30) % 360;

    glutPostRedisplay();

    }

    break;

    default:

    break;

    }

    }

    int main(int argc, char** argv)

    {

    glutInit(&argc, argv);

    glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

    glutInitWindowSize (500, 500);

    glutInitWindowPosition (100, 100);

    glutCreateWindow (argv[0]);

    init ();

    glutDisplayFunc(display);

    glutReshapeFunc(reshape);

    glutMouseFunc(mouse);

    glutMainLoop();

    return 0;

    }

        光源随视点移动

      要创建随视点移动的灯光,需要在查看转换之前设置灯光位置。

      然后观察变换以同样的方式影响光和视点。

      记住灯光位置存储在眼睛坐标中。

      

    光源随视点移动

    GLfloat light_position[] = { 0.0, 0.0, 0.0, 1.0 };

    glViewport(0, 0, (GLint) w, (GLint) h);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    gluPerspective(40.0, (GLfloat) w/(GLfloat) h, 1.0, 100.0);

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    如果现在移动视点,灯光将随之移动,相对于眼睛保持(0,0,0)距离。

    //viewpoint参数,可改变

    static GLdouble ex, ey, ez, upx, upy, upz;

    void display(void)

    {

      glClear(GL_COLOR_BUFFER_MASK | GL_DEPTH_BUFFER_MASK);

      glPushMatrix();

      gluLookAt (ex, ey, ez, 0.0, 0.0, 0.0, upx, upy, upz);

      glutSolidTorus (0.275, 0.85, 8, 15);

      glPopMatrix();

      glFlush();

    }

  • 相关阅读:
    写一个webpack plugin
    element的隐藏组件滚动条el-scrollbar使用
    iview 父组件动态传值给子组件
    RabbitMQ + Springboot +“Hello Word”
    Exception in thread "main" SettingsException[Failed to load settings from [elasticsearch.yml]]; nested: ElasticsearchParseException[malformed, expected end of settings but encountered additional conte
    java.nio.file.NoSuchFileException
    A.CTable 自动创建数据表
    mybatis 动态添加表,查看表,添加数据
    异常:Error resolving template "xxx", template might not exist or might not be accessible...解决办法
    Springboot项目启动后访问不到Controller
  • 原文地址:https://www.cnblogs.com/MakeView660/p/10484909.html
Copyright © 2011-2022 走看看