C#+OpenGL编程之OpenGL 光照

  • Post author:
  • Post category:其他



本文基础:


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 来关闭相应灯查看灯光颜色叠加效果。



版权声明:本文为luozhuang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。