精华内容
下载资源
问答
  • OpenGL光照

    2015-05-21 17:10:22
    了解掌握OpenGL程序的光照与材质,能正确使用光源与材质函数设置所需的绘制效果。 二.实验内容: (1)下载并运行Nate Robin教学程序包中的lightmaterial程序,试验不同的光照与材质系数; (2)

    【原文:http://www.cnblogs.com/opengl/archive/2012/11/14/2770745.html

    一.实验目的:

    了解掌握OpenGL程序的光照与材质,能正确使用光源与材质函数设置所需的绘制效果。

    二.实验内容:

    (1)下载并运行Nate Robin教学程序包中的lightmaterial程序,试验不同的光照与材质系数;

    (2)运行示范代码1,了解光照与材质函数使用;

    (3)在示范代码2的基础上,为其增加光照与材质效果,如下图所示。

    clip_image002clip_image004

    (a)原图                          (b)增加光照后的效果

    三.实验原理:

    为在场景中增加光照,需要执行以下步骤:

    (1) 设置一个或多个光源,设定它的有关属性;

    (2) 选择一种光照模型;

    (3) 设置物体的材料属性。

    具体如下:

    1.设置光源

    (1)光源的种类

    环境光

    环境光是一种无处不在的光。环境光源放出的光线被认为来自任何方向。因此,当你仅为场景指定环境光时,所有的物体无论法向量如何,都将表现为同样的明暗程度。

    点光源

    由这种光源放出的光线来自同一点,且方向辐射自四面八方。

    平行光

    平行光又称镜面光,这种光线是互相平行的。从手电筒、太阳等物体射出的光线都属于平行光。

    聚光灯

    这种光源的光线从一个锥体中射出,在被照射的物体上产生聚光的效果。使用这种光源需要指定光的射出方向以及锥体的顶角α。

    (2)光的成分

    对于每一种光源,都有漫射光和平行光两种成分。在OpenGL中,环境光也被作为一种特殊的光源的成分来看待。漫射光是指在光源中能够被漫反射的光的颜色成分(白色则包含所有颜色),而平行光是指光源中所有能够被镜面反射的光的颜色成分。通过指定这两种成分的颜色,就能决定光源是平行光源还是点光源。

    (3)设置光源成分

    OpenGL可以同时为我们提供8个有效的光源。也就是说,我们最多可以同时启用8个光源。它们分别是GL_LIGHT0,GL_LIGHT1,GL_LIGHT2 ……其中,GL_LIGHT0是最特殊的一个光源。我们可以为GL_LIGHT0指定环境光成分。

    a) 设置环境光

    对于GL_LIGHT0,我们可以为其指定环境光成分。 调用

    glLightfv(GL_LIGHT0,GL_AMBIENT, ambientLight);

    来设置场景的环境光。在上述函数调用中,第一个参数表示我们要对GL_LIGHT0进行设置,第二个参数表示我们要设置的是环境光成分,第三个参数则是一个数组,它有4个值,分别表示光源中含有红、绿、蓝三种光线的成分。一般情况下都为1,最后一项为透明度值,一般也为1。完整的代码是这样的:

    intAmbientLight[4]={1,1,1,1};
    glLightfv(GL_LIGHT0,GL_AMBIENT, AmbientLight);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);

    请注意在上述代码的第三行和第四行我们分别调用了glEnable函数开启GL_LIGHT0光源和光照系统。

    b)设置漫射光成分

    通过对漫射光成分的设置,我们可以产生一个点光源。方法和设置环境光成分相似,只需调用

    glLightfv(GL_LIGHT0,GL_DIFFUSE, DiffuseLight);

    即可。其中DiffuseLight是漫射光的颜色成分。一般情况下也为(1,1,1,1)。

    c)设置镜面光成分

    通过对镜面光成分的设置,我们可以产生一个平行光源。方法和设置漫射光成分相似,只需调用

    glLightfv(GL_LIGHT0,GL_SPECULAR, SpecularLight);

    即可。其中SpecularLight是漫射光的颜色成分。可以根据不同需要指定不同的颜色。

    (4)设置光源的位置

    对于点光源和平行光源,我们常常需要指定光源的位置来产生需要的效果。方法仍然是调用glLightfv函数,仅仅是换换参数而已:

    glLightfv(GL_LIGHT0,GL_POSITION,@LightPosition);

    其中,LightPosition也是一个四维数组,四维数组的前3项依次为光源位置的X,Y,Z分量,第四个值很特殊,一般为1或-1。当LightPosition[4]=-1的时候,表示光源位于距离场景无限远的地方,无论前面设置的X,Y,Z是什么值。当LightPosition[4]=1时,光源的位置就是前三项所指定的位置。

    2.光照模型

    OpenGL的光照模型是用来模拟现实生活中的光照的。

    3.材质设定

    (1)材质颜色

    OpenGL用材料对光的红、绿、蓝三原色的反射率来近似定义材料的颜色。象光源一样,材料颜色也分成环境、漫反射和镜面反射成分,它们决定了材料对环境光、漫反射光和镜面反射光的反射程度。在进行光照计算时,材料对环境光的反射率与每个进入光源的环境光结合,对漫反射光的反射率与每个进入光源的漫反射光结合,对镜面光的反射率与每个进入光源的镜面反射光结合。对环境光与漫反射光的反射程度决定了材料的颜色,并且它们很相似。对镜面反射光的反射率通常是白色或灰色(即对镜面反射光中红、绿、蓝的反射率相同)。镜面反射高光最亮的地方将变成具有光源镜面光强度的颜色。例如一个光亮的红色塑料球,球的大部分表现为红色,光亮的高光将是白色的。

    (2)材质定义

    材质的定义与光源的定义类似。其函数为:

    void glMaterial{if}[v](GLenum face,GLenum pname,TYPE param);

    定义光照计算中用到的当前材质。face可以是GL_FRONT、GL_BACK、GL_FRONT_AND_BACK,它表明当前材质应该应用到物体的哪一个面上;pname说明一个特定的材质;param是材质的具体数值,若函数为向量形式,则param是一组值的指针,反之为参数值本身。非向量形式仅用于设置GL_SHINESS。pname参数值具体内容见下表。另外,参数GL_AMBIENT_AND_DIFFUSE表示可以用相同的RGB值设置环境光颜色和漫反射光颜色。

    ___________________________________________________________________

    参数名 缺省值 说 明

    GL_AMBIENT (0.2,0.2,0.2,1.0) 材料的环境光颜色

    GL_DIFFUSE (0.8,0.8,0.8,1.0) 材料的漫反射光颜色

    GL_AMBIENT_AND_DIFFUSE 材料的环境光和漫反射光颜色

    GL_SPECULAR (0.0,0.0,0.0,1.0) 材料的镜面反射光颜色

    GL_SHINESS 0.0 镜面指数(光亮度)

    GL_EMISSION (0.0,0.0,0.0,1.0) 材料的辐射光颜色

    GL_COLOR_INDEXES (0,1,1) 材料的环境光、漫反射光和镜面光颜色

    _______________________________________________

    (3)材质RGB值和光源RGB值的关系

    材质的颜色与光源的颜色有些不同。对于光源,R、G、B值等于R、G、B对其最大强度的百分比。若光源颜色的R、G、B值都是1.0,则是最强的白光;若值变为0.5,颜色仍为白色,但强度为原来的一半,于是表现为灰色;若R=G=1.0,B=0.0,则光源为黄色。对于材质,R、G、B值为材质对光的R、G、B成分的反射率。比如,一种材质的R=1.0,G=0.5,B=0.0,则材质反射全部的红色成分,一半的绿色成分,不反射蓝色成分。也就是说,若OpenGL的光源颜色为(LR,LG,LB),材质颜色为(MR,MG,MB),那么,在忽略所有其他反射效果的情况下,最终到达眼睛的光的颜色为(LR*MR,LG*MG,LB*MB)。同样,如果有两束光,相应的值分别为(R1,G1,B1)和(R2,G2,B2),则OpenGL将各个颜色成分相加,得到(R1+R2,G1+G2,B1+B2),若任一成分的和值大于1(超出了设备所能显示的亮度)则约简到1.0。

    四.示范代码:

    (1)茶壶光照

    #include <GL/glut.h>

    #include <stdlib.h>

    // 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 white_light[] = { 1.0, 1.0, 1.0, 1.0 };

    GLfloat Light_Model_Ambient[] = { 0.2 , 0.2 , 0.2 , 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, white_light);

    glLightfv(GL_LIGHT0, GL_SPECULAR, white_light);

    glLightModelfv( GL_LIGHT_MODEL_AMBIENT , Light_Model_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);

    glutSolidTeapot(0.5);

    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;

    }

    (2)太阳系:

    #include <GL/glut.h>

    #include <stdlib.h>

    static int year = 0, day = 0, moon = 0;

    void init(void)

    {

    glClearColor (0.0, 0.0, 0.0, 0.0);

    glShadeModel (GL_FLAT);

    }

    void display(void)

    {

    glClear (GL_COLOR_BUFFER_BIT);

    glColor3f (1.0, 1.0, 1.0);

    glPushMatrix();

    glColor3f(1.0, 0.0, 0.0);

    glutSolidSphere(1.0, 20, 16); /* draw sun */

    glRotatef ((GLfloat) year, 0.0, 1.0, 0.0);

    glTranslatef (2.0, 0.0, 0.0);

    glRotatef ((GLfloat) day, 0.0, 1.0, 0.0);

    glColor3f(0.0, 0.0, 1.0);

    glutSolidSphere(0.3, 10, 8); /* draw earth */

    glTranslatef (1.0, 0.0, 0.0);

    glRotatef ((GLfloat) moon, 0.0, 1.0, 0.0);

    glColor3f(1.0, 1.0, 1.0);

    glutSolidSphere(0.2, 10, 8); /* draw moon */

    glPopMatrix();

    glutSwapBuffers();

    }

    void reshape (int w, int h)

    {

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

    glMatrixMode (GL_PROJECTION);

    glLoadIdentity ();

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

    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();

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

    }

    void keyboard (unsigned char key, int x, int y)

    {

    switch (key) {

    case 'd':

    day = (day + 10) % 360;

    moon = (moon + 5) % 360;

    glutPostRedisplay();

    break;

    case 'D':

    day = (day - 10) % 360;

    glutPostRedisplay();

    break;

    case 'y':

    year = (year + 5) % 360;

    day = (day + 10) % 360;

    moon = (moon + 5) % 360;

    glutPostRedisplay();

    break;

    case 'Y':

    year = (year - 5) % 360;

    glutPostRedisplay();

    break;

    case 'm':

    moon = (moon + 5) % 360;

    glutPostRedisplay();

    break;

    case 27:

    exit(0);

    break;

    default:

    break;

    }

    }

    int main(int argc, char** argv)

    {

    glutInit(&argc, argv);

    glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);

    glutInitWindowSize (800, 600);

    glutInitWindowPosition (100, 100);

    glutCreateWindow (argv[0]);

    init ();

    glutDisplayFunc(display);

    glutReshapeFunc(reshape);

    glutKeyboardFunc(keyboard);

    glutMainLoop();

    return 0;

    }


    展开全文
  • opengl 光照

    2016-11-13 13:25:32
    颜色与光照的关系 我们看到的物体的颜色,实际上是光照射物体后反射的光进入眼睛后感受到的颜色,而不是物体实际材料的颜色。太阳的白光包含了所有我们可以感知的颜色,可以将这个白光通过棱镜折射后分离为各种...
     
    

    颜色与光照的关系

    我们看到的物体的颜色,实际上是光照射物体后反射的光进入眼睛后感受到的颜色,而不是物体实际材料的颜色。太阳的白光包含了所有我们可以感知的颜色,可以将这个白光通过棱镜折射后分离为各种颜色的光。一束白光照射到红颜色的车身上,光经过车身,一部分被吸收,一部分被反射进入人的眼睛,我们感知到的颜色就是这个反射后进入眼睛的光的颜色,如下图所示(来自:Modern OpenGL 06 – Diffuse Point Lighting):

    光的反射1 
    图中,红色的表面吸收了蓝色和绿色成分,将红色反射出来。颜色吸收和反射的过程可以表示为: 
    LightIntensityObjectColor=Reflectcolor  
    计算为: 
    (R,G,B)(X,Y,Z)=(XR,YG,ZB)  
    则上面的过程表示为: 
    (1,1,1)(1,0,0)=(1,0,0)  
    如果将cyan (blue + green) 颜色光束照射到车身,车身会是什么颜色呢?会是黑色的,因为 (0,1,1)(1,0,0)=(0,0,0) ,这个过程如下图所示(来自:Modern OpenGL 06 – Diffuse Point Lighting):

    光的反射2

    如果将cyan (blue + green) 颜色照射到magenta (red + blue) 颜色的表面,那么结果会是什么颜色呢?同理,我们可以得到结果颜色为蓝色,如下图所示来自:Modern OpenGL 06 – Diffuse Point Lighting):

    光的反射3 
    在实际场景中,光的强度的各个分量可以在[0,1]之间变化,材料表面的颜色分量也可以在[0,1]之间变化,例如光照射到一个玩具表面的计算过程为:

    glm::vec3 lightColor(0.33f, 0.42f, 0.18f);
    glm::vec3 toyColor(1.0f, 0.5f, 0.31f);
    glm::vec3 result = lightColor * toyColor; // = (0.33f, 0.21f, 0.06f);
       
    • 1
    • 2
    • 3
    • 1
    • 2
    • 3

    Phong Reflection Model

    要模拟现实的光照是困难的,例如实际光照中,一束光可以经过场景中若干物体反射后,照射到目标物体上,也可以是直接照射到目标物体上。其中经过其他物体反射后再次照射到目标物体上,这是一个递归的过程,将会无比复杂。因此实际模拟光照过程中,总是采用近似模型去接近现实光照。Phong Reflection Model是经典的光照模型,它计算光照包括三个部分:环境光+漫反射光+镜面光,一共三个成分,如下图所示(来自wiki ,作者Brad Smith): 
    Phong Reflection Model

    环境光成分

    环境光是场景中光源给定或者全局给定的一个光照常量,它一般很小,主要是为了模拟即使场景中没有光照时,也不是全部黑屏的效果。场景中总有一点环境光,不至于使场景全部黑暗,例如远处的月亮,远处的光源。 
    环境光的实现为:

    // 环境光成分
    float   ambientStrength = 0.1f;
    vec3    ambient = ambientStrength * lightColor * objectColor;
       
    • 1
    • 2
    • 3
    • 1
    • 2
    • 3

    给定环境光后,场景效果如下图所示: 
    环境光 
    这里使用了两个着色器绘图。一个着色器用来绘制光源,光源用一个缩小的立方体来模拟,如图中白色立方体所示;另一个着色器用来绘制我们的物体,这里只显示了一个大的立方体。当场景中只有环境光时,立方体只能很暗的显示。

    漫反射光成分

    漫反射光成分,是光照中的一个主要成分。漫反射光强度与光线入射方向和物体表面的法向量之间的夹角 θ 相关。当 θ  = 0时,物体表面正好垂直于光线方向,这是获得的光照强度最大;当 θ  = 90时物体表面与光线方向平行,此时光线照射不到物体,光的强度最弱;当 θ>90 后,物体的表面转向到光线的背面,此时物体对应的表面接受不到光照。入射角度如下图所示: 
    AOI

    这里需要的向量包括: 
    1.光源和顶点位置之间的向量L 需要计算。 
    2.法向量N 通过顶点属性里指定 经过模型和视变换后需要重新计算。

    作为本节的简单示例程序,我们在顶点属性中指定法向量,例如立方体的正面ABCD这个面的顶点属性如下所示:

    // 顶点属性 位置 纹理坐标  法向量
    GLfloat vertices[] = {
            -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f,1.0f,    // A
            0.5f, -0.5f, 0.5f, 1.0f, 0.0f,  0.0f, 0.0f, 1.0f,   // B
            0.5f, 0.5f, 0.5f,  1.0f, 1.0f,   0.0f, 0.0f, 1.0f,  // C
            0.5f, 0.5f, 0.5f,  1.0f, 1.0f,   0.0f, 0.0f, 1.0f,  // C
            -0.5f, 0.5f, 0.5f,  0.0f, 1.0f,  0.0f, 0.0f, 1.0f,  // D
            -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f,   // A
        ...省略
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    和顶点位置属性一样,我们需要将法向量数据发送到GPU,并且使用glVertexAttribPointer告诉OpenGL数据的解析方式。这些内容在前面已经介绍了,这里不再赘述。

    将顶点属性传递到着色器后,需要在着色器中开始我们的光照计算。有两种方法执行向量L和N的计算。一种方式是在世界坐标系中计算,另一种是在相机坐标系中计算,两种方法都可以实现。

    这里以在世界坐标系中计算L和N为例进行说明,在相机坐标系中计算也有类似操作。在世界坐标系中,计算L时,光源lightPos是在世界坐标系中指定的位置,直接使用即可。顶点位置需要变换到世界坐标系中,利用Model矩阵即可,使用式子: 
    FragPos=vec3(modelvec4(position,1.0));()
    在计算N时需要注意,我们不能直接利用 Modelnormal 来获取变换后的法向量,应该使用式子: 
    Normal=mat3(transpose(inverse(model)))normal() 。 
    这个式子的具体推导过程,可以参考The Normal Matrix。 
    综上所述,顶点着色器中计算顶点位置和法向量代码为:

    #version 330
    layout(location = 0) in vec3 position;
    layout(location = 1) in vec2 textCoord;
    layout(location = 2) in vec3 normal;
    
    out vec3 FragPos;
    out vec2 TextCoord;
    out vec3 FragNormal;
    
    uniform mat4 projection;
    uniform mat4 view;
    uniform mat4 model;
    
    void main()
    {
    gl_Position = projection * view * model * vec4(position, 1.0);
    FragPos = vec3(model * vec4(position, 1.0)); // 在世界坐标系中指定
    TextCoord = textCoord;
    mat3 normalMatrix = mat3(transpose(inverse(model)));
    FragNormal = normalMatrix * normal; // 计算法向量经过模型变换后值
    }
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在片元着色器中,计算漫反射光成分的代码为:

    // 漫反射光成分 此时需要光线方向为指向光源
    vec3    lightDir = normalize(lightPos - FragPos);
    vec3    normal = normalize(FragNormal);
    float   diffFactor = max(dot(lightDir, normal), 0.0);
    vec3    diffuse = diffFactor * lightColor * objectColor;
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 1
    • 2
    • 3
    • 4
    • 5

    这里使用max(dot(lightDir, normal), 0.0)主要是为了防止当光线和法向量夹角大于90后,取值为负的情况,因此使用max保证漫反射光照系数在[0.0,1.0]范围内。 
    添加了漫反射光成分后的效果如下图所示: 
    漫反射光

    镜面反射光成分

    镜面光成分模拟的是物体表面光滑时反射的高亮的光,镜面光反映的通常是光的颜色,而不是物体的颜色。计算镜面光成分时,要考虑光源和顶点位置之间向量L、法向量N、反射方向R、观察者和顶点位置之间的向量V之间的关系,如下图所示(来自:Lighting and Material): 
    light equatation 
    当R和V的夹角 θ 越小时,人眼观察到的镜面光成分越明显。镜面反射系数定义为: 
    specFactor=cos(θ)s  
    其中 s 表示为镜面高光系数(shininess ),它的值一般取为2的整数幂,值越大则高光部分越集中,例如下面图中,测试了几种不同的高光系数,效果如下所示: 
    镜面高光系数

    计算镜面光成分过程为:

    // 镜面反射成分 此时需要光线方向为由光源指出
    float   specularStrength = 0.5f;
    vec3    reflectDir = normalize(reflect(-lightDir, normal));
    vec3    viewDir = normalize(viewPos - FragPos);
    float   specFactor = pow(max(dot(reflectDir, viewDir), 0.0), 32); // 32为镜面高光系数
    vec3    specular = specularStrength * specFactor * lightColor * objectColor;
       
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    这里需要注意的是,利用reflect函数计算光的出射方向时,要求入射方向指向物体表面位置,因此这里翻转了lightDir,计算为:

       vec3 reflectDir = normalize(reflect(-lightDir, normal));
       
    • 1
    • 1

    将上述三种光成分叠加后,成为最终物体的颜色,片元着色器中实现为:

       vec3 result = ambient + diffuse + specular 
       color = vec4(result , 1.0f);
       
    • 1
    • 2
    • 1
    • 2

    绘制效果如下图所示: 
    包含三个成分后

    per-vertex 和per-fragment实现光照的对比

    上面我们实现的光照计算是在片元着色器中进行的,这种是基于片元计算的,称之为Phong shading。在过去OpenGL编程中实现的是在顶点着色器中进行光照计算,这是基元顶点的计算的,称之为Gouraud Shading。Gouraud Shading和Phong shading,两者的效果对比如下图所示(来自learnopengl.com Basic Lighting): 
    per-vertex

    基元顶点计算光照的优势在于顶点数目比片元数目少,因此计算速度快,但是基于顶点计算的光照没有基元片元的真实,主要是基元顶点计算时,只计算了顶点的光照,而其余片元的光照由插值计算得到,这种插值后的光照显得不是很真实,需要使用更多的顶点来加以完善。例如下面的图中,分别显示了使用少量和大量顶点的基于顶点的光照计算效果:

    low 
    high

    使用基于片元的光照计算时能够获取更为平滑的光照效果。实现基元顶点的光照计算过程,即将上述在片元着色器中的光照计算过程迁移到顶点着色器中执行。

    最后的说明

    在计算光照的过程中,注意使用的向量一定要单位化,因为 cosθ 值的计算依赖于两个参与点积的向量是单位向量这一事实,否则计算会出错。另外在世界坐标系还是在相机坐标系中进行光照计算都是可以的,这个取决于你的喜好,但是要注意将顶点位置、法向量都变换到同一个坐标系下进行光照计算。

    实现的Phong reflection model还不够完善,一方面从光源角度看,属于点光源,但是缺少随着距离的衰减;另一方面从物体的材质角度看,没有反映出物体不同部分对光感受的强度不同这一特点,需要使用材质属性加以改进。

    展开全文
  • C#+OpenGL编程之OpenGL 光照

    千次阅读 2014-12-26 10:38:11
     现在是第四章 OpenGL 光照,这章开始,我遇到麻烦了,因为原书的auxSolidSphere这个函数,C# 没有封装,我就把例程修改为:  3个光源,一个正方形。  using System; using System.Collections.Generic; using ...

      本文基础:C#+OpenGL编程之环境搭建

      现在是第四章 OpenGL 光照,这章开始,我遇到麻烦了,因为原书的auxSolidSphere这个函数,C# 没有封装,我就把例程修改为:

      3个光源,一个正方形。

      

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Tao.OpenGl;
    using Tao.Glfw;
    
    namespace OpenGL
    {
        class light : Examplefirst
        {
            /** 定义三个光源(红色 绿色和蓝色)的位置 */
            static float[] lightPositionR = new float[] { 0.0f, 0.0f, 5.0f, 1.0f };
            static float[] lightPositionG = new float[] { 0.0f, 0.0f, 5.0f, 1.0f };
            static float[] lightPositionB = new float[] { 0.0f, 0.0f, 5.0f, 1.0f };
    
            /** 定义三个光源的漫射光 */
            static float[] diffuseLightR = new float[] { 1.0f, 0.0f, 0.0f, 1.0f };
            static float[] diffuseLightG = new float[] { 0.0f, 1.0f, 0.0f, 1.0f };
            static float[] diffuseLightB = new float[] { 0.0f, 0.0f, 1.0f, 1.0f };
    
            /** 定义三个光源的镜面光 */
            static float[] specularLightR = new float[] { 1.0f, 0.0f, 0.0f, 1.0f };
            static float[] specularLightG = new float[] { 0.0f, 1.0f, 0.0f, 1.0f };
            static float[] specularLightB = new float[] { 0.0f, 0.0f, 1.0f, 1.0f };
    
            /** 再定义一个默认的光源 */
            static float[] diffuseLight = new float[] { 0.8f, 0.8f, 0.8f, 1.0f };
            static float[] specularLight = new float[] { 1.0f, 1.0f, 1.0f, 1.0f };
            static float[] lightPosition = new float[] { 0.0f, 0.0f, 10.0f, 1.0f };
    
            float m_Angle = 0.0f;												/**< 设置初始角度为0 */
    
            public light()
                : base()
            {
    
                base.title = "第四章 OpenGL 光照";
            }
    
    
    
    
    
            /// <summary>
            /// 初始化视口投影,恢复原书的视口
            /// </summary>
            public override void iniView(int windowWidth, int windowHeight)
            {
    
    
                Glu.gluPerspective(45.0f, windowWidth / windowHeight, 1.0f, 100.0f);
                Gl.glMatrixMode(Gl.GL_MODELVIEW);
                Gl.glLoadIdentity();
    
                /** 设置0号光源 */
                Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, diffuseLight);
                Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, specularLight);
                Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_POSITION, lightPosition);
    
                /** 设置1号红色光源 */
                Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_DIFFUSE, diffuseLightR);
                Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_SPECULAR, specularLightR);
                Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION, lightPositionR);
    
                /** 设置2号绿色光源 */
                Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_DIFFUSE, diffuseLightG);
                Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_SPECULAR, specularLightG);
                Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_POSITION, lightPositionG);
    
                /** 设置3号蓝色光源 */
                Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_DIFFUSE, diffuseLightB);
                Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_SPECULAR, specularLightB);
                Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_POSITION, lightPositionB);
    
                Gl.glEnable(Gl.GL_LIGHT0);                                        /**< 启用0号灰色光源,让物体可见 */
                Gl.glEnable(Gl.GL_LIGHTING);
                //虽然我们没有用到纹理,不过如果你没有执行NORMALIZE,立方体将是个灰色的(不正确的)。
                Gl.glEnable(Gl.GL_NORMALIZE);
            }
    
            /// <summary>
            /// 重载,使用Draw方法绘图
            /// </summary>
            /// <param name="mouseX"></param>
            /// <param name="currentTime"></param>
            public override void DrawGLScene(int mouseX, double currentTime)
            {
                Draw();
            }
    
            /// <summary>
            /// 重载
            /// </summary>
            /// <param name="mouseX"></param>
            /// <param name="currentTime"></param>
            public override void Update(float milliseconds)
            {
                //按下ESC结束
                isRunning = ((Glfw.glfwGetKey(Glfw.GLFW_KEY_ESC) == Glfw.GLFW_RELEASE) &&
                    Glfw.glfwGetWindowParam(Glfw.GLFW_OPENED) == Gl.GL_TRUE);
    
                /** 更新红色光源 */
                if (Glfw.glfwGetKey(Glfw.GLFW_KEY_F1) == Glfw.GLFW_RELEASE)       /**< 当数字'1'键没有被按下时 */
                {
                    Gl.glEnable(Gl.GL_LIGHT1);      /**< 启用1号红色光源*/
    
                }
                else
                {
                    Gl.glDisable(Gl.GL_LIGHT1);
                    /**< 当被按下时,禁用该光源 */
                }
    
    
                /** 更新绿色光源 */
                if (Glfw.glfwGetKey(Glfw.GLFW_KEY_F2) == Glfw.GLFW_RELEASE)        /**< 当数字'2'键没有被按下时 */
                {
                    Gl.glEnable(Gl.GL_LIGHT2);    /**< 启用2号绿色光源 */
                }
                else
                {
    
                    Gl.glDisable(Gl.GL_LIGHT2);          /**< 当被按下时,禁用该光源 */
                }
    
    
                /** 更新蓝色光源 */
                if (Glfw.glfwGetKey(Glfw.GLFW_KEY_F3) == Glfw.GLFW_RELEASE)      /**< 当数字'3'键没有被按下时 */
                {
                    Gl.glEnable(Gl.GL_LIGHT3);         /**< 启用3号蓝色光源*/
    
                }
                else
                {
                    Gl.glDisable(Gl.GL_LIGHT3);      /**< 当被按下时,禁用该光源 */
                }
                m_Angle = m_Angle + milliseconds * 10;
    
            }
    
            /** 绘制函数 */
            void Draw()
            {
                /** 用户自定义的绘制过程 */
    
                Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
                Gl.glLoadIdentity();
    
    
    
    
                /** 设置红色光源位置 */
                Gl.glLightfv(Gl.GL_LIGHT1, Gl.GL_POSITION, lightPositionR);
    
    
                /** 设置绿色光源位置 */
                Gl.glLightfv(Gl.GL_LIGHT2, Gl.GL_POSITION, lightPositionG);
    
    
    
                /** 设置蓝色光源位置 */
                Gl.glLightfv(Gl.GL_LIGHT3, Gl.GL_POSITION, lightPositionB);
    
    
    
                /** 绘制一个球体 */
                Gl.glPushMatrix();
                /**< 设置旋转 */
                Gl.glTranslatef(0.0f, 0.0f, -30.0f); /**< 移入屏幕 */
                Gl.glRotatef(m_Angle, 1.0f, 0.0f, 0.0f);
                Gl.glRotatef(m_Angle, 0.0f, 1.0f, 0.0f);
                Gl.glRotatef(m_Angle, 0.0f, 0.0f, 1.0f);
                auxSolidSphere(2.5f);
                Gl.glPopMatrix();
    
                Gl.glFlush();													/**< 强制执行所有的OpenGl.GL命令 */
            }
    
            /// <summary>
            /// 由于没有auxSolidSphere这个辅助函数,我做了修改,改为正方形
            /// </summary>
            /// <param name="p"></param>
            private void auxSolidSphere(float p)
            {
                Gl.glPushMatrix();
    
                Gl.glColor3f(1.0f, 0.0f, 0.0f);    /**< 红色 */
                Gl.glScalef(p, p, p);
                DrawCube();
                Gl.glPopMatrix();
    
            }
    
            public void DrawCube()
            {
                Gl.glBegin(Gl.GL_QUADS);
    
                Gl.glColor3f(1, 0, 0);
                Gl.glVertex3f(-1.0f, -1.0f, -1.0f);
                Gl.glVertex3f(-1.0f, 1.0f, -1.0f);
                Gl.glVertex3f(1.0f, 1.0f, -1.0f);
                Gl.glVertex3f(1.0f, -1.0f, -1.0f);
    
                Gl.glColor3f(1, 1, 0);
                Gl.glVertex3f(-1.0f, -1.0f, -1.0f);
                Gl.glVertex3f(1.0f, -1.0f, -1.0f);
                Gl.glVertex3f(1.0f, -1.0f, 1.0f);
                Gl.glVertex3f(-1.0f, -1.0f, 1.0f);
    
                Gl.glColor3f(1, 0, 1);
                Gl.glVertex3f(-1.0f, -1.0f, -1.0f);
                Gl.glVertex3f(-1.0f, -1.0f, 1.0f);
                Gl.glVertex3f(-1.0f, 1.0f, 1.0f);
                Gl.glVertex3f(-1.0f, 1.0f, -1.0f);
    
                Gl.glColor3f(0, 1, 0);
                Gl.glVertex3f(-1.0f, -1.0f, 1.0f);
                Gl.glVertex3f(1.0f, -1.0f, 1.0f);
                Gl.glVertex3f(1.0f, 1.0f, 1.0f);
                Gl.glVertex3f(-1.0f, 1.0f, 1.0f);
    
                Gl.glColor3f(0, 0, 1);
                Gl.glVertex3f(-1.0f, 1.0f, -1.0f);
                Gl.glVertex3f(-1.0f, 1.0f, 1.0f);
                Gl.glVertex3f(1.0f, 1.0f, 1.0f);
                Gl.glVertex3f(1.0f, 1.0f, -1.0f);
    
                Gl.glColor3f(0, 1, 1);
                Gl.glVertex3f(1.0f, -1.0f, -1.0f);
                Gl.glVertex3f(1.0f, 1.0f, -1.0f);
                Gl.glVertex3f(1.0f, 1.0f, 1.0f);
                Gl.glVertex3f(1.0f, -1.0f, 1.0f);
    
                Gl.glEnd();
            }
    
        }
    }
    
      程序我们用到了Update重载来计算动画变量,在我的机器上只用时间差值太慢,我 时间差值X10作为动画时间,大家可以根据自己机器修改。

      程序运行结果与原书不同,一个白色的正方形,因为三个颜色红 绿 蓝叠加就是白色,大家可以通过按住键盘F1 F2 F3 来关闭相应灯查看灯光颜色叠加效果。

    展开全文
  • OpenGL光照模型 OpenGL雾气效果 OpenGL透明函数 OpenGL表面绘制函数 OpenGL半色调操作   转载于:...

    OpenGL点光源函数

    83db9b752d977a8530ec4326a9c5479cd89.jpg

    指定一个OpenGL光源位置和类型

    74d2ed0cd4ca00e881b8168c202e4393d0c.jpg

    22219025fe6cbe59030d4bc7a7f837e9cfb.jpg

    指定OpenGL光源颜色

    40bfe535991262ffb1395777e4c16ca0853.jpg

    指定OpenGL光源的辐射强度衰减系数

    72fd9b9cf724ce10629f2ce174637e4b618.jpg

    OpenGL方向光源

    e1f3a4518e008591b00dad9a4e2ecd691f9.jpg

    30962d5a826b81e14a940d1c2e6a4cad260.jpg

    OpenGL全局光照参数

    80e9d779e62879d95698f2f745073f5e374.jpg

    8de28134ee3b6c31764934062243fd8e52f.jpg

    fb00ff5552300718ae615e39c4616331870.jpg

    OpenGL表面特性函数

    fbfcf61d86a77f782f1904b4d48f168ea54.jpg

    08ad6acec53e02666c514cdf7b117b35703.jpg

    OpenGL光照模型

    70e64dbfde19da111af107ae158c63c94db.jpg

    OpenGL雾气效果

    6086d4d107248806b54cbc798d28f2c3f57.jpg

    dfff495c5b6e3c8e9cc73c4a0f462afe27e.jpg

    OpenGL透明函数

    a4c07ab8c9c0173130b98f61285d784d427.jpg

    26560437040dc5d308508efeb109a8529d6.jpg

    OpenGL表面绘制函数

    539d5a134e53f24ccd78095f8e356472980.jpg

    f5a99b43fc10b32c0825fa759dde4bcd2ee.jpg

    OpenGL半色调操作

    78db656bc21b0e83d8eec8f11902b60183d.jpg

     

    转载于:https://my.oschina.net/liyangke/blog/2876782

    展开全文
  • opengl光照

    2016-04-21 22:12:06
    左边的一个是使用了简单的光照效果的,我们通过光照的层次,很容易的认为它是一个三维的物体 眼睛之所以看见各种物体,是因为光线直接或间接的从它们那里到达了眼睛。人类对于光线强弱的变化的反应,比对于颜色...
  • 浅析OpenGL光照

    千次阅读 多人点赞 2013-08-07 13:21:28
    浅谈OpenGL光照    之前从来都没有涉及光照的内容,心想只要能通过常规的方法渲染出几何体甚至是模型就可以了,然而没有光照的日子注定是苦涩的,因为仅凭几何体和模型的颜色无法达到真是渲染的效果,在实际中...
  • openGL 光照处理

    千次阅读 2012-09-28 11:05:07
    要绘制逼真的三维物体,必须做光照处理。...1. OpenGL光照基本概念 在屏幕上最终显示的象素颜色,受到glColor命令指定的颜色影响,同时也要反映出在场景中使用光照的特性,以及物体反射和吸收光的属性。OpenG
  • 一、OpenGL光照模型 1、OpenGL假定光线是可以分解为红光、绿光、蓝光成分的; 2、人眼看到的物体颜色由环境中的光线和物体本身的材质属性共同决定; 3、光源的特征是由其发射的红、绿、蓝光的数量决定的; 4、材质的...
  • OpenGL 光照和材质

    千次阅读 2017-07-25 19:42:39
    OpenGL 光照和材质 前言:很难受呀,一天又过去了,没有达到预期的进度,等下写完这篇博客,抓紧研究鼠标实现轨迹球! 长路漫漫啊…… 注:此篇文章建立在MFC环境搭建完成后 1.渲染处理 在...
  • 实验9 OpenGL光照

    千次阅读 2020-10-21 19:21:27
    了解掌握OpenGL程序的光照与材质,能正确使用光源与材质函数设置所需的绘制效果。 2.实验内容: (1)下载并运行Nate Robin程序包中的lightmaterial程序,试验不同光照、材质系数。 (2)运行示范代码,了解光照与材质...
  • 实验6 OpenGL光照

    2014-05-26 15:23:37
    实验6 OpenGL光照 一.实验目的: 了解掌握OpenGL程序的光照与材质,能正确使用光源与材质函数设置所需的绘制效果。 二.实验内容: (1)下载并运行Nate Robin教学程序包中的lightmaterial程序,试验...
  • OpenGL学习10-OpenGL光照

    2014-12-17 17:36:25
    OpenGL模型中,除非一个物体自己会发光,否则它将受到3中不同的光照射:环境光(ambient)、散射光(diffuse)和镜面光(specular)。现实世界中,当然不存在这样的光,但是,作为光抽象,这三种类型的光允许我们模拟和...
  • OpenGL光照设置问题

    千次阅读 2016-12-28 15:38:33
    OpenGL在处理光照时把光照系统分为三部分,分别是光源、材质和光照模型。 光源、材质和光照模式都有各自的属性,尽管属性种类繁多,但这些属性都只用很少的几个函数来设置。 使用glLight*函数可设置光源的属性...
  • OpenGL光照模型--四种光照效果

    千次阅读 2016-04-16 20:37:01
    OpenGL光照模型  为了能看出3D效果,给场景中添加光源。如果没有光照,绘出的球看上去和一个二维平面上圆没什么差别,如下图,左边为有光照效果的球体,右边为同一个球体但没有设置光源,看上去就没有立体效果,...
  • OpenGL光照和材质 当光照射到一个物体表面上时,会出现三种情形。首先,光可以通过物体表面向空间反射,产生反射光。其次,对于透明体,光可以穿透该物体并从另一端射出,产生透射光。最后,部分光将被物体表面...
  • 实验7 OpenGL光照

    千次阅读 2017-04-17 10:33:48
    了解掌握OpenGL程序的光照与材质,能正确使用光源与材质函数设置所需的绘制效果。 二.实验内容: (1)下载并运行Nate Robin教学程序包中的lightmaterial程序,试验不同的光照与材质系数; (2)运行示范代码1,...
  • OPENGL常见函数介绍

    千次阅读 2017-10-02 21:07:03
    1.OpenGL核心库  核心库包含有115个函数函数名的前缀为gl。  这部分函数用于常规的、核心的图形处理。此函数由gl.dll来负责解释执行。由于许多函数可以接收不同数以下几类。据类型的参数,因此派生出来的函数...
  • openGL 光照的学习

    千次阅读 2014-07-28 00:25:31
    接下来是光照部分的重点函数, glMaterial (), 他有 glMaterialf , glMateriali , glMaterialfv , glMaterialiv 。这四种形式,     如果是 void glMaterialf (GLenum face , GLenum ...
  • OpenGL光照设置

    2017-05-21 19:12:00
    OpenGL光照模型是用来模拟现实生活中的光照的。 3. 材质设定 ( 1 )材质颜色 OpenGL用材料对光的红、绿、蓝三原色的反射率来近似定义材料的颜色。象光源一样,材料颜色也分成环境、漫反射和镜面反射成分,...
  • opengl 光照闪烁

    千次阅读 2014-11-19 02:28:47
    opengl的时候, 遇到一个问题, 我设置程序
  • opengl光照模型

    千次阅读 2013-06-14 01:14:07
    OpenGL光照模型将光照分为四个独立的部分:环境光,散射光,镜面反射光和发射光,这四种光被分别计算,然后叠加起来. 光线的R,G,B值表示各分量的强度,材质的R,G,B值表示材质对相应分量的反射比例. 定向光源不存在三...
  • OpenGL 光照常识

    千次阅读 2009-06-17 13:19:00
    OpenGL 光照常识1. 几个概念环境光——经过多次反射而来的光称为环境光,无法确定其最初的方向,但当特定的光源关闭后,它们将消失. 全局环境光——它们并非来自特定的光源,这些光经过了多次散射,已经无法确定其...
  • openGL光照(illumination)

    千次阅读 2014-12-02 20:28:34
    在复习图形学illumination时,偶然看到网上将光照的博客, 觉得挺好,就转了下~ 链接:http://www.cppblog.com/zmj/archive/2006/01/17/2814.html 目 录  10.1 概念  10.2 光照模型  10.3 明暗处理 ...
  • OpenGl核心函数

    2015-06-11 08:51:03
    OpenGl核心函数库   glAccum 操作累加缓冲区 glAddSwapHintRectWIN 定义一组被SwapBuffers拷贝的三角形 glAlphaFunc允许设置alpha检测功能 glAreTexturesResident 决定特定的纹理对象是否常驻在纹理内存中...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,006
精华内容 3,602
关键字:

opengl光照函数