精华内容
下载资源
问答
  • OpenGL添加纹理光照

    2017-05-11 19:58:39
    使用OpenGl完成纹理光照添加,使用a,b键进行平移,c,d键进行旋转,L键控制光照开关。纹理与源文件放在同一个文件加下。
  • Android OpenGL添加光照和材料属性

    千次阅读 2016-08-09 11:14:59
    在上一篇文章【 Android OpenGL显示任意3D模型文件 】中,我们学习了如何读取并显示STL格式的3D文件,但是,最后,看到的并没有添加光照效果,导致虽然模型在旋转,但是我们看到的画面却像一个平面。今天我们开始...

    转载请注明出处:【huachao1001的专栏:http://blog.csdn.net/huachao1001】

    在上一篇文章【 Android OpenGL显示任意3D模型文件 】中,我们学习了如何读取并显示STL格式的3D文件,但是,最后,看到的并没有添加光照效果,导致虽然模型在旋转,但是我们看到的画面却像一个平面。今天我们开始学习如何给模型添加灯照效果,以及如何为模型添加材料属性,使得最终看到的旋转模型真正为3D效果。首先,看看最终效果,如下图所示:

    光照效果

    材质效果

    1 光照效果

    因为我们所做的立体效果是根据真实世界原理来计算的,所以很有必要去了解在现实世界中,我们所看到的一个物体有哪些光。

    1.1 真实世界中的光照

    我们知道,在黑暗中,当我们将手电筒对准某个物体时,我们所看到的该物体的“亮度”有3种:

    • 物体表面发生镜面反射部分(Specular),一般是白色。
    • 物体表面发生漫反射部分(Diffuse),一般是物体表面的颜色。
    • 物体表面没有照射到光的部分,即通过环境光(Ambient)照射,在黑暗中环境光是黑色。

    如下图所示(图片出自www.guidebee.info):

    光照图示

    从上图中也可以看出,光源的位置也会影响到我们所看到的最终画面。显然,我们只需控制好光源位置、镜面反射颜色、漫反射颜色、环境光颜色这四个参数,就可以做到了。

    1.2 Android OpenGL相关API

    1.2.1 光源 GL10.GL_LIGHT0

    0号光源,该光源的默认颜色为白色,即RGBA(1.0,1.0,1.0,1.0),漫反射和镜面反射也为白色。类似的,还有其他光源如GL10.GL_LIGHT1,系统提供了0~78种光源,其他的光源默认为黑色,即RGBA(0.0,0.0,0.0,1.0).

    开启光源也非常简单:

    //启用光照功能
    gl.glEnable(GL10.GL_LIGHTING);
    //开启0号灯
    gl.glEnable(GL10.GL_LIGHT0);

    1.2.2 设置各种反射光颜色

    一旦开启了光照功能,就可以通过glLightfv函数来指定各种反射光的颜色了,glLightfv函数如下:

    public void glLightfv(int light,int pname, FloatBuffer params)
    public void glLightfv(int light,int pname,float[] params,int offset)
    public void glLightf(int light,int pname,float param)

    其中,

    • light: 指光源的序号,OpenGL ES可以设置从07共八个光源。
    • pname: 光源参数名称,可以有如下:
      • GL_SPOT_EXPONENT
      • GL_SPOT_CUTOFF
      • GL_CONSTANT_ATTENUATION
      • GL_LINEAR_ATTENUATION
      • GL_QUADRATIC_ATTENUATION
      • GL_AMBIENT(用于设置环境光颜色)
      • GL_DIFFUSE(用于设置漫反射光颜色)
      • GL_SPECULAR(用于设置镜面反射光颜色)
      • GL_SPOT_DIRECTION
      • GL_POSITION(用于设置光源位置)
    • params: 参数的值(数组或是Buffer类型),数组里面含有4个值分别表示R,G,B,A。

    指定光源的位置的参数为GL_POSITION,位置的值为(x,y,z,w),如果是平行光则将w 设为0,此时,(x,y,z)为平行光的方向:

    1.3 代码实现

    在上一篇的基础上,直接修改GLRenderer.java文件,添加一个openLight函数:

    
    public void openLight(GL10 gl) {
    
        gl.glEnable(GL10.GL_LIGHTING);
        gl.glEnable(GL10.GL_LIGHT0);
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, Util.floatToBuffer(ambient));
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, Util.floatToBuffer(diffuse));
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, Util.floatToBuffer(specular));
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, Util.floatToBuffer(lightPosition));
    
    
    }

    另外,分别添加我们设定的各种反射光的颜色:

    float[] ambient = {0.9f, 0.9f, 0.9f, 1.0f,};
    float[] diffuse = {0.5f, 0.5f, 0.5f, 1.0f,};
    float[] specular = {1.0f, 1.0f, 1.0f, 1.0f,};
    float[] lightPosition = {0.5f, 0.5f, 0.5f, 0.0f,};
    

    最后,在onSurfaceCreated函数里面调用一下openLight(gl);函数即可。最终效果如下:

    光照效果

    2 材料属性

    前面我们提到了可以为模型设置不同的材料属性,本节中,我们一起学习如何为模型设定不同的材料属性。我们知道,同样是一束光,照在不同颜色材料的物体上面,我们所看到的是不同的,反射出来的不仅仅颜色不同,光泽也是不同的。换句话说,不同的材质对最终的渲染效果影响很大!

    材料的属性设置和光源的设置有些类似,用到的函数

    public void glMaterialf(int face,int pname,float param)
    public void glMaterialfv(int face,int pname,float[] params,int offset)
    public void glMaterialfv(int face,int pname,FloatBuffer params)

    其中,

    • face : 在OpenGL ES中只能使用GL_FRONT_AND_BACK,表示修改物体的前面和后面的材质光线属性。
    • pname: 参数类型,这些参数用在光照方程。可以取如下值:
      • GL_AMBIENT
      • GL_DIFFUSE
      • GL_SPECULAR
      • GL_EMISSION
      • GL_SHININESS
    • param:指定反射的颜色。

    跟设置光照类似,设置材料属性首先需要定义各种反射光的颜色:

    float[] materialAmb = {0.4f, 0.4f, 1.0f, 1.0f};
    float[] materialDiff = {0.0f, 0.0f, 1.0f, 1.0f};//漫反射设置蓝色
    float[] materialSpec = {1.0f, 0.5f, 0.0f, 1.0f};

    然后就是将这些颜色通过glMaterialfv函数设置进去:

    public void enableMaterial(GL10 gl) {
    
        //材料对环境光的反射情况
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, Util.floatToBuffer(materialAmb));
        //散射光的反射情况
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, Util.floatToBuffer(materialDiff));
        //镜面光的反射情况
        gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, Util.floatToBuffer(materialSpec));
    
    }

    当然了,最后也别忘记了在onSurfaceCreated函数中调用 enableMaterial(gl);,最后看看效果:
    材质效果

    3 完整的GLRenderer类

    最后项目代码就不上传了,直接参考上一篇的文章中的源码即可,本位值修改了GLRenderer类,把该类的完整源码贴上:

    package com.hc.opengl;
    
    import android.content.Context;
    import android.opengl.GLSurfaceView;
    import android.opengl.GLU;
    
    import java.io.IOException;
    
    import javax.microedition.khronos.egl.EGLConfig;
    import javax.microedition.khronos.opengles.GL10;
    
    /**
     * Package com.hc.opengl
     * Created by HuaChao on 2016/8/9.
     */
    public class GLRenderer implements GLSurfaceView.Renderer {
    
        private Model model;
        private Point mCenterPoint;
        private Point eye = new Point(0, 0, -3);
        private Point up = new Point(0, 1, 0);
        private Point center = new Point(0, 0, 0);
        private float mScalef = 1;
        private float mDegree = 0;
    
        public GLRenderer(Context context) {
            try {
    
                model = new STLReader().parserBinStlInAssets(context, "huba.stl");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public void rotate(float degree) {
            mDegree = degree;
        }
    
        @Override
        public void onDrawFrame(GL10 gl) {
            // 清除屏幕和深度缓存
            gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    
    
            gl.glLoadIdentity();// 重置当前的模型观察矩阵
    
    
            //眼睛对着原点看
            GLU.gluLookAt(gl, eye.x, eye.y, eye.z, center.x,
                    center.y, center.z, up.x, up.y, up.z);
    
            //为了能有立体感觉,通过改变mDegree值,让模型不断旋转
            gl.glRotatef(mDegree, 0, 1, 0);
    
            //将模型放缩到View刚好装下
            gl.glScalef(mScalef, mScalef, mScalef);
            //把模型移动到原点
            gl.glTranslatef(-mCenterPoint.x, -mCenterPoint.y,
                    -mCenterPoint.z);
    
    
            //===================begin==============================//
    
            //允许给每个顶点设置法向量
            gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
            // 允许设置顶点
            gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
            // 允许设置颜色
    
            //设置法向量数据源
            gl.glNormalPointer(GL10.GL_FLOAT, 0, model.getVnormBuffer());
            // 设置三角形顶点数据源
            gl.glVertexPointer(3, GL10.GL_FLOAT, 0, model.getVertBuffer());
    
            // 绘制三角形
            gl.glDrawArrays(GL10.GL_TRIANGLES, 0, model.getFacetCount() * 3);
    
            // 取消顶点设置
            gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            //取消法向量设置
            gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
    
            //=====================end============================//
    
        }
    
    
        @Override
        public void onSurfaceChanged(GL10 gl, int width, int height) {
    
            // 设置OpenGL场景的大小,(0,0)表示窗口内部视口的左下角,(width, height)指定了视口的大小
            gl.glViewport(0, 0, width, height);
    
            gl.glMatrixMode(GL10.GL_PROJECTION); // 设置投影矩阵
            gl.glLoadIdentity(); // 设置矩阵为单位矩阵,相当于重置矩阵
            GLU.gluPerspective(gl, 45.0f, ((float) width) / height, 1f, 100f);// 设置透视范围
    
            //以下两句声明,以后所有的变换都是针对模型(即我们绘制的图形)
            gl.glMatrixMode(GL10.GL_MODELVIEW);
            gl.glLoadIdentity();
    
    
        }
    
    
        @Override
        public void onSurfaceCreated(GL10 gl, EGLConfig config) {
            gl.glEnable(GL10.GL_DEPTH_TEST); // 启用深度缓存
            gl.glClearColor(0f, 0f, 0f, 0f);// 设置深度缓存值
            gl.glDepthFunc(GL10.GL_LEQUAL); // 设置深度缓存比较函数
            gl.glShadeModel(GL10.GL_SMOOTH);// 设置阴影模式GL_SMOOTH
    
            //开启光
            openLight(gl);
            enableMaterial(gl);
            float r = model.getR();
            //r是半径,不是直径,因此用0.5/r可以算出放缩比例
            mScalef = 0.5f / r;
            mCenterPoint = model.getCentrePoint();
        }
    
    
        float[] ambient = {0.9f, 0.9f, 0.9f, 1.0f};
        float[] diffuse = {0.5f, 0.5f, 0.5f, 1.0f};
        float[] specular = {1.0f, 1.0f, 1.0f, 1.0f};
        float[] lightPosition = {0.5f, 0.5f, 0.5f, 0.0f};
    
        public void openLight(GL10 gl) {
    
            gl.glEnable(GL10.GL_LIGHTING);
            gl.glEnable(GL10.GL_LIGHT0);
            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, Util.floatToBuffer(ambient));
            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, Util.floatToBuffer(diffuse));
            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_SPECULAR, Util.floatToBuffer(specular));
            gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, Util.floatToBuffer(lightPosition));
    
    
        }
    
        float[] materialAmb = {0.4f, 0.4f, 1.0f, 1.0f,};
        float[] materialDiff = {0.0f, 0.0f, 1.0f, 1.0f,};
        float[] materialSpec = {1.0f, 0.5f, 0.0f, 1.0f,};
    
        public void enableMaterial(GL10 gl) {
    
            //材料对环境光的反射情况
            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, Util.floatToBuffer(materialAmb));
            //散射光的反射情况
            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, Util.floatToBuffer(materialDiff));
            //镜面光的反射情况
            gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, Util.floatToBuffer(materialSpec));
    
        }
    }

    最后感谢大家的关注,欢迎关注huachao1001的博客,http://blog.csdn.net/huachao10019

    展开全文
  • OpenGL光照之基础光照

    2019-10-03 17:18:32
    冯氏光照模型的主要结构由3分量组成: 环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照 环境光照(Ambient Lighting): 即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以...

    参考:

    https://learnopenglcn.github.io/02%20Lighting/02%20Basic%20Lighting/

    冯氏光照模型

    冯氏光照模型的主要结构由3个分量组成:
    环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照
    在这里插入图片描述
    环境光照(Ambient Lighting):
    即使在黑暗的情况下,世界上通常也仍然有一些光亮(月亮、远处的光),所以物体几乎永远不会是完全黑暗的。为了模拟这个,我们会使用一个环境光照常量,它永远会给物体一些颜色.


    漫反射光照(Diffuse Lighting):
    模拟光源对物体的方向性影响(Directional Impact)。它是冯氏光照模型中视觉上最显著的分量。物体的某一部分越是正对着光源,它就会越亮


    镜面光照(Specular Lighting):
    模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色

    环境光照

    现实生活中的光照极其复杂,通常周围环境会有许多光源。

    光的一个属性是,它可以向很多方向发散并反弹,从而能够到达不是非常直接临近的点.

    所以,光能够在其它的表面上反射,对一个物体产生间接的影响.

    考虑到这种情况的算法叫做全局照明(Global Illumination)算法,但是这种算法既开销高昂又极其复杂。

    所以我们将会先使用一个简化的全局照明模型,即环境光照.

    使用一个很小的常量(光照)颜色,添加到物体片段的最终颜色中,这样子的话即便场景中没有直接的光源也能看起来存在有一些发散的光

    用光的颜色乘以一个很小的常量环境因子,再乘以物体的颜色,然后将最终结果作为片段的颜色

    void main()
    {
        float ambientStrength = 0.1;
        vec3 ambient = ambientStrength * lightColor;
    
        vec3 result = ambient * objectColor;
        FragColor = vec4(result, 1.0);
    }
    


    漫反射光照

    漫反射光照使物体上与光线方向越接近的片段能从光源处获得更多的亮度
    在这里插入图片描述
    如果光线垂直于物体表面,这束光对物体的影响会最大化.

    为了测量光线和片段的角度,我们使用一个叫做法向量(Normal Vector)的东西,它是垂直于片段表面的一个向量(这里以黄色箭头表示



    两个单位向量的夹角越小,它们点乘的结果越倾向于1。当两个向量的夹角为90度的时候,点乘会变为0

    θ越大,光对片段颜色的影响就应该越小。
    所以,计算漫反射光照需要什么?

    法向量:一个垂直于顶点表面的向量。
    定向的光线:作为光源的位置与片段的位置之间向量差的方向向量。为了计算这个光线,我们需要光的位置向量和片段的位置向量。

    法向量

    法向量是一个垂直于顶点表面的(单位)向量
    由于顶点本身并没有表面,我们利用它周围的顶点来计算出这个顶点的表面.
    由于立方体是一个规则的物体,可以把法线数据手工添加到顶点数据中
    数据如下

    float vertices[] = {
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
         0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 
         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 
         0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 
        -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 
        -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f, 
    
        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
         0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
        -0.5f,  0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
        -0.5f, -0.5f,  0.5f,  0.0f,  0.0f, 1.0f,
    
        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
        -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
    
         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
         0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
         0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
         0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
         0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
    
        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
         0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
         0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
        -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
        -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
    
        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
         0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
         0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
        -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
        -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f
    };
    

    由于我们向顶点数组添加了额外的数据,所以我们应该更新光照的顶点着色器:

    #version 330 core
    layout (location = 0) in vec3 aPos;
    layout (location = 1) in vec3 aNormal;
    ...
    

    接下来更新顶点属性指针

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);
    

    所有光照的计算都是在片段着色器里进行,所以我们需要将法向量由顶点着色器传递到片段着色器。我们这么做

    out vec3 Normal;
    
    void main()
    {
        gl_Position = projection * view * model * vec4(aPos, 1.0);
        Normal = aNormal;
    }
    

    在片段着色器中定义相应的输入变量

    in vec3 Normal;
    

    每个顶点都有了法向量,但是我们仍然需要光源的位置向量和片段的位置向量。
    由于光源的位置是一个静态变量,我们可以简单地在片段着色器中把它声明为uniform:

    uniform vec3 lightPos;
    

    然后在渲染循环中,更新uniform
    使用在前面声明的lightPos向量作为光源位置:

    lightingShader.setVec3("lightPos", lightPos);
    

    最后,还需要片段的位置。我们会在世界空间中进行所有的光照计算,因此我们需要一个在世界空间中的顶点位置

    可以通过把顶点位置属性乘以模型矩阵(不是观察和投影矩阵)来把它变换到世界空间坐标。这个在顶点着色器中很容易完成,所以我们声明一个输出变量,并计算它的世界空间坐标:

    out vec3 FragPos;  
    out vec3 Normal;
    
    void main()
    {
        gl_Position = projection * view * model * vec4(aPos, 1.0);
        FragPos = vec3(model * vec4(aPos, 1.0));
        Normal = aNormal;
    }
    

    在片段着色器中添加相应的输入变量

    in vec3 FragPos;
    

    现在可以在片段着色器中添加光照计算了.
    第一件事是计算光源和片段位置之间的方向向量

    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(lightPos - FragPos);
    

    计算光照时我们通常不关心一个向量的模长或它的位置,我们只关心它们的方向。所以,几乎所有的计算都使用单位向量完成.


    下一步,对norm和lightDir向量进行点乘,计算光源对当前片段实际的漫发射影响结果值再乘以光的颜色,得到漫反射分量

    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = diff * lightColor;
    

    有了环境光分量和漫反射分量,我们把它们相加然后把结果乘以物体的颜色,来获得片段最后的输出颜色

    vec3 result = (ambient + diffuse) * objectColor;
    FragColor = vec4(result, 1.0);
    

    完整代码如下

    #include <glad/glad.h>
    #include <GLFW/glfw3.h>
    #include "shader.h"
    #include <iostream>
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    #include "Camera.h"
    #define STB_IMAGE_IMPLEMENTATION
    #include "stb_image.h"
    void framebuffer_size_callback(GLFWwindow* window, int width, int height);
    void mouse_callback(GLFWwindow* window, double xpos, double ypos);
    void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
    void processInput(GLFWwindow *window);
    
    const unsigned int SCR_WIDTH = 800;
    const unsigned int SCR_HEIGHT = 600;
    
    
    Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
    float lastX = SCR_WIDTH / 2.0f;
    float lastY = SCR_HEIGHT / 2.0f;
    bool firstMouse = true;
    
    float deltaTime = 0.0f;	
    float lastFrame = 0.0f;
    
    glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
    int main(void)
    {
    	//初始化glfw并创建窗口
    	//-------------------
    	glfwInit();
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    	GLFWwindow * window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "window", NULL, NULL);
    	if (window == NULL)
    	{
    		std::cout << "Failed to create GLFW window" << std::endl;
    		glfwTerminate();
    		return -1;
    	}
    	glfwMakeContextCurrent(window);
    	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    	glfwSetCursorPosCallback(window, mouse_callback);
    	glfwSetScrollCallback(window, scroll_callback);
    	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    
    	//初始化GLAD
    	//--------
    	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    	{
    		std::cout << "Failed to initialize GLAD" << std::endl;
    		return -1;
    	}
    	glEnable(GL_DEPTH_TEST);
    	//创建着色器
    	//---------
    	Shader lightingShader("D:\\OpenGL\\Project1\\lightshader.vs", "D:\\OpenGL\\Project1\\lightshader.fs");
    	Shader lampShader("D:\\OpenGL\\Project1\\4.1.texture.vs", "D:\\OpenGL\\Project1\\4.1.texture.fs");
    
    	//设置顶点坐标,颜色,纹理坐标
    	//--------
    	float vertices[] = {
    		-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		 0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		-0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    
    		-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		 0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		 0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		 0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		-0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    
    		-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
    
    		 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
    
    		-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
    		 0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
    		 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
    		 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
    		-0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
    		-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
    
    		-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
    		 0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
    		 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
    		 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
    		-0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
    		-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f
    	};
    
    	unsigned int VBO, cubeVAO;
    	glGenVertexArrays(1, &cubeVAO);
    	glGenBuffers(1, &VBO);
    
    	glBindBuffer(GL_ARRAY_BUFFER, VBO);
    
    	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    	glBindVertexArray(cubeVAO);
    
    	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    	glEnableVertexAttribArray(0);
    	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    	glEnableVertexAttribArray(1);
    
    	unsigned int lightVAO;
    	glGenVertexArrays(1, &lightVAO);
    	glBindVertexArray(lightVAO);
    
    
    	glBindBuffer(GL_ARRAY_BUFFER, VBO);
    
    	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    	glEnableVertexAttribArray(0);
    
    
    
    	while (!glfwWindowShouldClose(window))
    	{
    		float currentFrame = glfwGetTime();
    		deltaTime = currentFrame - lastFrame;
    		lastFrame = currentFrame;
    
    		processInput(window);
    
    		glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    		lightingShader.use();
    		lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
    		lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
    		lightingShader.setVec3("lightPos", lightPos);
    
    		glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
    		glm::mat4 view = camera.GetViewMatrix();
    		lightingShader.setMat4("projection", projection);
    		lightingShader.setMat4("view", view);
    
    
    		glm::mat4 model = glm::mat4(1.0f);
    		lightingShader.setMat4("model", model);
    
    
    		glBindVertexArray(cubeVAO);
    		glDrawArrays(GL_TRIANGLES, 0, 36);
    
    		lampShader.use();
    		lampShader.setMat4("projection", projection);
    		lampShader.setMat4("view", view);
    		model = glm::mat4(1.0f);
    		model = glm::translate(model, lightPos);
    		model = glm::scale(model, glm::vec3(0.2f)); // a smaller cube
    		lampShader.setMat4("model", model);
    
    
    		glBindVertexArray(lightVAO);
    		glDrawArrays(GL_TRIANGLES, 0, 36);
    
    		glfwSwapBuffers(window);
    		glfwPollEvents();
    	}
    	glDeleteVertexArrays(1, &cubeVAO);
    	glDeleteVertexArrays(1, &lightVAO);
    	glDeleteBuffers(1, &VBO);
    
    	glfwTerminate();
    	return 0;
    
    
    }
    void processInput(GLFWwindow *window)
    {
    	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    		glfwSetWindowShouldClose(window, true);
    
    	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
    		camera.ProcessKeyboard(FORWARD, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
    		camera.ProcessKeyboard(BACKWARD, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
    		camera.ProcessKeyboard(LEFT, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
    		camera.ProcessKeyboard(RIGHT, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
    		camera.ProcessKeyboard(UP, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
    		camera.ProcessKeyboard(DOWN, deltaTime);
    }
    
    void framebuffer_size_callback(GLFWwindow* window, int width, int height)
    {
    
    	glViewport(0, 0, width, height);
    }
    void mouse_callback(GLFWwindow* window, double xpos, double ypos)
    {
    	if (firstMouse)
    	{
    		lastX = xpos;
    		lastY = ypos;
    		firstMouse = false;
    	}
    
    	float xoffset = xpos - lastX;
    	float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
    
    	lastX = xpos;
    	lastY = ypos;
    
    	camera.ProcessMouseMovement(xoffset, yoffset);
    }
    void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
    {
    	camera.ProcessMouseScroll(yoffset);
    }
    

    法向量只是一个方向向量,不能表达空间中的特定位置,法向量没有齐次坐标。
    这意味着,位移不应该影响到法向量
    果我们打算把法向量乘以一个模型矩阵,我们就要从矩阵中移除位移部分,只选用模型矩阵左上角3×3的矩阵(注意,我们也可以把法向量的w分量设置为0,再乘以4×4矩阵;这同样可以移除位移)。
    对于法向量,我们只希望对它实施缩放和旋转变换

    如果模型矩阵执行了不等比缩放,顶点的改变会导致法向量不再垂直于表面了
    在这里插入图片描述
    在顶点着色器中,我们可以使用inverse和transpose函数自己生成法线矩阵

    Normal = mat3(transpose(inverse(model))) * aNormal;
    

    即使是对于着色器来说,逆矩阵也是一个开销比较大的运算,因此,只要可能就应该避免在着色器中进行逆矩阵运算,它们必须为你场景中的每个顶点都进行这样的处理。

    用作学习目这样做是可以的,但是对于一个对效率有要求的应用来说,在绘制之前你最好用CPU计算出法线矩阵,然后通过uniform把值传递给着色器(像模型矩阵一样)。

    镜面光照

    镜面光照也是依据光的方向向量和物体的法向量来决定的,但是它也依赖于观察方向,例如玩家是从什么方向看着这个片段的
    在这里插入图片描述
    通过反射法向量周围光的方向来计算反射向量,计算反射向量和视线方向的角度差,如果夹角越小,那么镜面光的影响就会越大
    观察向量是镜面光照附加的一个变量,我们可以使用观察者世界空间位置和片段的位置来计算它
    之后,我们计算镜面光强度,用它乘以光源的颜色,再将它加上环境光和漫反射分量。

    为了得到观察者的世界空间坐标,我们简单地使用摄像机对象的位置坐标代替.


    把另一个uniform添加到片段着色器,把相应的摄像机位置坐标传给片段着色器:

    uniform vec3 viewPos;
    
    lightingShader.setVec3("viewPos", camera.Position);
    

    已经获得所有需要的变量,可以计算高光强度了。
    首先,我们定义一个镜面强度(Specular Intensity)变量,给镜面高光一个中等亮度颜色,让它不要产生过度的影响。

    float specularStrength = 0.5;
    

    下一步,我们计算视线方向向量,和对应的沿着法线轴的反射向量:

    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    

    注意的对lightDir向量进行了取反
    reflect函数要求第一个向量是从光源指向片段位置的向量,但是lightDir当前正好相反,是从片段指向光源,所以取反。

    剩下要做的是计算镜面分量。下面的代码完成了这件事

    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
    vec3 specular = specularStrength * spec * lightColor;
    

    先计算视线方向与反射方向的点乘(并确保它不是负值),
    然后取它的32次幂。这个32是高光的反光度(Shininess)

    一个物体的反光度越高,反射光的能力越强,散射得越少,高光点就会越小
    在这里插入图片描述
    后一件事情是把它加到环境光分量和漫反射分量里,再用结果乘以物体的颜色:

    vec3 result = (ambient + diffuse + specular) * objectColor;
    FragColor = vec4(result, 1.0);
    

    在光照着色器的早期,开发者曾经在顶点着色器中实现冯氏光照模型。
    在顶点着色器中做光照的优势是,相比片段来说,顶点要少得多,因此会更高效,所以(开销大的)光照计算频率会更低。
    然而,顶点着色器中的最终颜色值是仅仅只是那个顶点的颜色值,片段的颜色值是由插值光照颜色所得来的。结果就是这种光照看起来不会非常真实,除非使用了大量顶点。

    完整代码如下

    #include <glad/glad.h>
    #include <GLFW/glfw3.h>
    #include "shader.h"
    #include <iostream>
    #include <glm/glm.hpp>
    #include <glm/gtc/matrix_transform.hpp>
    #include <glm/gtc/type_ptr.hpp>
    #include "Camera.h"
    #define STB_IMAGE_IMPLEMENTATION
    #include "stb_image.h"
    void framebuffer_size_callback(GLFWwindow* window, int width, int height);
    void mouse_callback(GLFWwindow* window, double xpos, double ypos);
    void scroll_callback(GLFWwindow* window, double xoffset, double yoffset);
    void processInput(GLFWwindow *window);
    
    const unsigned int SCR_WIDTH = 800;
    const unsigned int SCR_HEIGHT = 600;
    
    
    Camera camera(glm::vec3(0.0f, 0.0f, 3.0f));
    float lastX = SCR_WIDTH / 2.0f;
    float lastY = SCR_HEIGHT / 2.0f;
    bool firstMouse = true;
    
    float deltaTime = 0.0f;	
    float lastFrame = 0.0f;
    
    glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
    int main(void)
    {
    	//初始化glfw并创建窗口
    	//-------------------
    	glfwInit();
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    	GLFWwindow * window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "window", NULL, NULL);
    	if (window == NULL)
    	{
    		std::cout << "Failed to create GLFW window" << std::endl;
    		glfwTerminate();
    		return -1;
    	}
    	glfwMakeContextCurrent(window);
    	glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
    	glfwSetCursorPosCallback(window, mouse_callback);
    	glfwSetScrollCallback(window, scroll_callback);
    	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
    
    	//初始化GLAD
    	//--------
    	if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
    	{
    		std::cout << "Failed to initialize GLAD" << std::endl;
    		return -1;
    	}
    	glEnable(GL_DEPTH_TEST);
    	//创建着色器
    	//---------
    	Shader lightingShader("D:\\OpenGL\\Project1\\lightshader.vs", "D:\\OpenGL\\Project1\\lightshader.fs");
    	Shader lampShader("D:\\OpenGL\\Project1\\4.1.texture.vs", "D:\\OpenGL\\Project1\\4.1.texture.fs");
    
    	//设置顶点坐标,颜色,纹理坐标
    	//--------
    	float vertices[] = {
    		-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		 0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		 0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		-0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    		-0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,
    
    		-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		 0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		 0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		 0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		-0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    		-0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,
    
    		-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
    		-0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,
    
    		 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
    		 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,
    
    		-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
    		 0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
    		 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
    		 0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
    		-0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,
    		-0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,
    
    		-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
    		 0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,
    		 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
    		 0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
    		-0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,
    		-0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f
    	};
    
    	unsigned int VBO, cubeVAO;
    	glGenVertexArrays(1, &cubeVAO);
    	glGenBuffers(1, &VBO);
    
    	glBindBuffer(GL_ARRAY_BUFFER, VBO);
    
    	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
    	glBindVertexArray(cubeVAO);
    
    	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    	glEnableVertexAttribArray(0);
    	glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
    	glEnableVertexAttribArray(1);
    
    	unsigned int lightVAO;
    	glGenVertexArrays(1, &lightVAO);
    	glBindVertexArray(lightVAO);
    
    
    	glBindBuffer(GL_ARRAY_BUFFER, VBO);
    
    	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
    	glEnableVertexAttribArray(0);
    
    
    
    	while (!glfwWindowShouldClose(window))
    	{
    		float currentFrame = glfwGetTime();
    		deltaTime = currentFrame - lastFrame;
    		lastFrame = currentFrame;
    
    		processInput(window);
    
    		glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
    		lightPos.x = 1.0f + sin(glfwGetTime()) * 2.0f;
    		lightPos.y = sin(glfwGetTime() / 2.0f) * 1.0f;
    
    		lightingShader.use();
    		lightingShader.setVec3("objectColor", 1.0f, 0.5f, 0.31f);
    		lightingShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f);
    		lightingShader.setVec3("lightPos", lightPos);
    		lightingShader.setVec3("viewPos", camera.Position);
    
    
    		glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
    		glm::mat4 view = camera.GetViewMatrix();
    		lightingShader.setMat4("projection", projection);
    		lightingShader.setMat4("view", view);
    
    
    		glm::mat4 model = glm::mat4(1.0f);
    		lightingShader.setMat4("model", model);
    
    
    		glBindVertexArray(cubeVAO);
    		glDrawArrays(GL_TRIANGLES, 0, 36);
    
    		lampShader.use();
    		lampShader.setMat4("projection", projection);
    		lampShader.setMat4("view", view);
    		model = glm::mat4(1.0f);
    		model = glm::translate(model, lightPos);
    		model = glm::scale(model, glm::vec3(0.2f)); // a smaller cube
    		lampShader.setMat4("model", model);
    
    
    		glBindVertexArray(lightVAO);
    		glDrawArrays(GL_TRIANGLES, 0, 36);
    
    		glfwSwapBuffers(window);
    		glfwPollEvents();
    	}
    	glDeleteVertexArrays(1, &cubeVAO);
    	glDeleteVertexArrays(1, &lightVAO);
    	glDeleteBuffers(1, &VBO);
    
    	glfwTerminate();
    	return 0;
    
    
    }
    void processInput(GLFWwindow *window)
    {
    	if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
    		glfwSetWindowShouldClose(window, true);
    
    	if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
    		camera.ProcessKeyboard(FORWARD, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
    		camera.ProcessKeyboard(BACKWARD, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
    		camera.ProcessKeyboard(LEFT, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
    		camera.ProcessKeyboard(RIGHT, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
    		camera.ProcessKeyboard(UP, deltaTime);
    	if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
    		camera.ProcessKeyboard(DOWN, deltaTime);
    }
    
    void framebuffer_size_callback(GLFWwindow* window, int width, int height)
    {
    
    	glViewport(0, 0, width, height);
    }
    void mouse_callback(GLFWwindow* window, double xpos, double ypos)
    {
    	if (firstMouse)
    	{
    		lastX = xpos;
    		lastY = ypos;
    		firstMouse = false;
    	}
    
    	float xoffset = xpos - lastX;
    	float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top
    
    	lastX = xpos;
    	lastY = ypos;
    
    	camera.ProcessMouseMovement(xoffset, yoffset);
    }
    void scroll_callback(GLFWwindow* window, double xoffset, double yoffset)
    {
    	camera.ProcessMouseScroll(yoffset);
    }
    
    展开全文
  • OpenGL消隐和光照

    2016-05-28 09:21:54
    OpenGL观察实验的基础上,通过实现实验内容,掌握OpenGL中消隐和光照的设置,并验证课程中消隐和光照的内容。...5. 在场景中添加一个聚光光源,其照射区域正好覆盖茶壶,并能调整改聚光光源的照射角度和朝向。
  • OpenGL中给场景添加光照

    万次阅读 2014-11-25 22:15:20
    OpenGL中给场景添加光照  为了在OpenGL中使用光照计算,我们需要调用glEnable方法,并用GL_LIGHTING作为参数。这调用告诉OpenGL在确定场景中每顶点的颜色时使用光照参数和材料属性。当然,如果我们没有...
    在OpenGL中给场景添加光照

         为了在OpenGL中使用光照计算,我们需要调用glEnable方法,并用GL_LIGHTING作为参数。这个调用告诉OpenGL在确定场景中每个顶点的颜色时使用光照参数和材料属性。当然,如果我们没有指定任何光照参数和材料属性,那么物体仍将会保持为黑暗的无光照状态。

         // 启用光照
         glEnable(GL_LIGHTING);

         一、设置环境光
         OpenGL提供了一个全局光源,它只发射环境光。这种光源很有用,它可以照射没有被其它光源直接照射的物体的背面,并且如果场景看上去太暗,可以调节这种全局环境光,以达到自己所需要的亮度。设置全局环境光的代码如下所示:

         // 指定环境光的RGBA强度值
         GLfloat ambientLight[] = {1.0f, 1.0f, 1.0f, 1.0f};
         // 设置光照模型,将ambientLight所指定的RGBA强度值应用到环境光
         glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);

         glLightModel方法使用指定的参数来设置光照模型。它的第一个参数是需要设置的光照模型,在这里我们指定的是环境光(ambient);接下来的一个参数包含了组成光源的RGBA强度值,也就是我们设置的ambientLight。
         全局环境光的默认RGBA值是(0.2, 0.2, 0.2, 1.0),这是一种较暗的光。其它光照模型参数允许我们指定多边形是正面还是背面被照射,或者是两面都被照射,以及指定如何计算镜面光的角度等。

         二、设置材料属性
         当有了环境光源之后,我们还需要设置材料属性,只有设置了材料属性,我们的多边形才可以反射光线。
         设置材料属性可以使用两种方法,第一种是在指定每个多边形或每组多边形之前使用glMaterial方法。代码如下所示:
         
           GLfloat gray[] = {0.75f, 0.75f, 0.75f, 1.0f};
         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);

         glBegin(GL_TRIANGLES);
              ...
         glEnd();

         glMaterial方法的第一个参数指定了材料属性是作用于正面、背面还是双面(GL_FRONT、GL_BACK、GL_FRONT_AND_BACK);第二个参数指定将要设置环境光和散射光的反射率,在这里它们被设置为相同的值;最后一个参数是数组,包含了构成材料属性的RGBA值。在大多数情况下,环境光和散射光成分是相同的。

         第二种设置材料属性的方法,称为颜色追踪。使用颜色追踪,可以告诉OpenGL仅仅通过调用glColor方法来设置材料属性。依旧使用glEnable方法来启用颜色追踪:

         // 启用颜色追踪
         glEnable(GL_COLOR_MATERIAL);
         // 设置多边形正面的环境光和散射光属性,追踪glColor方法所设置的颜色
         glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
     
         glColor(0.75f, 0.75f, 0.75f);
         glBegin(GL_TRIANGLES);
              ...
         glEnd();
         
         接着,glColorMaterial函数根据glColor所设置的颜色值来指定材料参数。这里有很重要的一点,那就是物体材料的颜色成分实际上决定了入射光的反射比例,正是这一点确保了颜色追踪的可行性。设置完整渲染状态的代码如下所示:
       
          void  SetupRC()
         {
              glEnable(GL_DEPTH_TEST); 
              glFrontFace(GL_CCW);
              glEnable(GL_CULL_FACE);
              // 启用光照计算
              glEnable(GL_LIGHTING);
              // 指定环境光强度(RGBA)
              GLfloat ambientLight[] = {1.0f, 1.0f, 1.0f, 1.0f};
              // 设置光照模型,将ambientLight所指定的RGBA强度值应用到环境光
              glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight);
              // 启用颜色追踪
              glEnable(GL_COLOR_MATERIAL);
              // 设置多边形正面的环境光和散射光材料属性,追踪glColor
              glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
              glClearColor(0.0f, 0.0f, 0.5f, 1.0f);
         }

         这一部分的示例程序完整代码已经放到了GitHub上,有需要的朋友可以参考一下(https://github.com/dxm3dp/OpenGL-05-Ambient点击打开链接)。


         本文出自杜晓萌的博客,请勿用于任何商业用途,转载请保持完整性并标明出处:http://blog.csdn.net/haohan_meng



    展开全文
  • OpenGl-OpenGL光照

    2019-12-06 15:35:48
    创建一个茶壶,并添加光照,观察光照和材质 #include <GL/glut.h> #include <stdlib.h> void init(void) { GLfloat mat_specular[] = { 1.0,1.0,1.0,1.0 }; GLfloat mat_shininess[] = { 50.0 }; ...

    创建一个茶壶,并添加光照,观察光照和材质

    来自徐文鹏版《计算机图形学基础》课后P330“实验7 OpenGL 光照”

    #include <GL/glut.h>
    #include <stdlib.h>
    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,0.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);
    	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)w / (GLfloat)h, -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);
    	glutInitWindowSize(100, 100);
    	glutCreateWindow(argv[0]);
    	init();
    	glutDisplayFunc(display);
    	glutReshapeFunc(reshape);
    	glutMainLoop();
    	return 0;
    }
    

    实验效果图·:
    OpenGL光照

    展开全文
  • opengl 光照模型和光照纹理贴图

    千次阅读 2019-03-26 15:56:46
    上篇文章我们讲到了 opengl的 mvp矩阵,以及在三维世界里漫游的方法,与实现,这篇讲解下,opengl光照模型。 光基础介绍 环境光ambient: 就是环境周边物体反射找到物体上的光 漫反射光diffuse: 物体表面漫...
  • OpenGL核心技术之光照技术

    千次阅读 2017-02-21 19:25:24
    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,CSDN...CSDN视频网址:http://edu.csdn.net/lecturer/144 光照模型在各大商业引擎中都会使用,而且光照的使用直接影响着场景的渲染,所以对于游戏品质的提升非常重
  • OpenGL:颜色和光照

    2019-04-06 15:31:56
    当我们在OpenGL中创建一个光源时,我们希望给光源一个颜色。当我们把光源的颜色与物体的颜色值相乘,所得到的就是这个物体所反射的颜色(也就是我们所感知到的颜色)。 glm::vec3 lightColor(1.0f, 1.0f, 1.0f); glm...
  • opengl光照

    2019-01-04 17:18:07
    其中一个模型被称为冯氏光照模型(Phong Lighting Model)。冯氏光照模型的主要结构由3个分量组成:环境(Ambient)、漫反射(Diffuse)和镜面(Specular)光照。下面这张图展示了这些光照分量看起来的样子: 环境光照...
  • OpenGL(七) 光照模型及设置

    万次阅读 多人点赞 2016-11-10 23:42:53
    OpenGL把现实世界中的光照系统近似归为三部分,分别是光源、材质和光照环境。 光源就是光的来源,是“光”这种物质的提供者; 材质是指被光源照射的物体的表面的反射、漫反射(OpenGL不考虑折射)特性; 材质...
  • OpenGL-7-光照

    2021-07-13 18:14:55
    目录光照模型光源 光照模型 最常见的光照模型称为“ADS”模型: 环境光反射(Ambient reflection)——模拟低级...场景的绘制最终由片段着色器为屏幕上的每像素输出颜色而实现。使用ADS光照模型需要指定由于像素的RGBA
  • OpenGL总结15-光照模型

    2020-08-17 10:30:05
    绘制地形图时发现图像看不出起伏,觉得应该是关照模型和法线的问题,所以查找了一些资料,这里做一个总结。 在查看计算机图形学的时候,书中提到光照模型与表面绘制,为了避免属于混乱,定义了光照模型和表面绘制的...
  • 之所以说光照比较复杂,主要是在物理和数学专业上的难度,光通常都不是来自于同一光源,而是来自散落于我们周围的很多光源,即使它们可能并不是那么显而易见,光的一个属性是,它可以向很多方向发散和反...
  • 、从VBO数据中读取贴图的uv坐标 //uv坐标 glVertexAttribPointer(7, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float))); glEnableVertexAttribArray(7); 二、在Material类中添加记录贴图ID...
  • OPENGL学习笔记——光照

    千次阅读 2015-08-31 09:51:26
    深度缓冲区的原理是把一个距离观察平面(通常是近侧裁剪平面)的深度值与窗口中的每一个像素相关联。首先使用glClear()函数,把所有像素的深度值设置为最大可能的距离,然后在场景中以任意顺序绘制所有的物体。深度...
  • 图形学中物体所呈现的颜色可以理解为光照射到该物体上后,该物体所反射出来的颜色,即物体从一个光源反射各个颜色分量的大小。 // 光的颜色*物体颜色 = 物体反射处的颜色 glm::vec3 lightColor(0.33f, 0.42f, 0.18f)...
  • OpenGL学习之基础光照

    2019-05-30 21:14:00
    使用叉乘对所有的立方体顶点计算法向量,但由于3D立方体不是一个复杂的形状,所以我们可以简单地把法向量数据手工添加到顶点数据中。 float vertices[] = { -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.5f, -...
  • OpenGL ES 3.0 中采用的光照模型相对现实世界进行了很大的简化,将光照分成了 3 种组成元素(也可以称为 3 通道),包括环境光、散射光 以及 镜面光。 1、散射光介绍 仅仅有环环境光的场景效果是很差的,没有层次...
  • opengl光照立方体

    2014-12-16 12:38:47
    opengl实心立方体,添加光照处理,可旋转

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,759
精华内容 1,903
关键字:

opengl添加一个光照