13事例十三:光源例子:环绕二次曲面球体的光源

Posted lotuses

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了13事例十三:光源例子:环绕二次曲面球体的光源相关的知识,希望对你有一定的参考价值。

namespace sharpGLTest13

    public partial class Form1 : Form
    
        private float rotation = 0.0f;
        float m_bReadX, m_bReadY;
        float m_bGreenX, m_bGreenY;
        float m_bBlueX, m_bBlueY;

        //3个光源位置
        float[] lightPosR = new float[]  0f, 0f, 2f, 1f ;
        float[] lightPosG = new float[]  0f, 0f, 2f, 1f ;
        float[] lightPosB = new float[]  0f, 0f, 2f, 1f ;

        //3个光源漫射光
        float[] diffLightR =  1f, 0f, 0f, 1f ;
        float[] diffLightG =  0f, 1f, 0f, 1f ;
        float[] diffLightB =  0f, 0f, 1f, 1f ;

        //定义3个光源我镜面光
        float[] specLightR =  1f, 0f, 0f, 1f ;
        float[] specLightG =  0f, 1f, 0f, 1f ;
        float[] specLightB =  0f, 0f, 1f, 1f ;

        //默认的光源, 灰色光源,用于默认照明
        float[] defDiffLight = new float[]  0.8f, 0.8f, 0.8f, 1f ;
        float[] defSpecLight = new float[]  1f, 1f, 1f, 1f ;
        float[] defLightPos = new float[]  0f, 0f, 10f, 1f ;

        public Form1()
        
            InitializeComponent();
        

        private void openGLControl_OpenGLInitialized(object sender, EventArgs e)
        
            OpenGL gl = openGLControl.OpenGL;
            setLight(gl);
            //gl.Enable(OpenGL.GL_NORMALIZE);
            gl.ClearColor(0, 0, 0, 0);
        
        private void setLight(OpenGL gl)
        
            //0号灯光,默认灯光
            gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_DIFFUSE, defDiffLight);
            gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_SPECULAR, defSpecLight);
            gl.Light(OpenGL.GL_LIGHT0, OpenGL.GL_POSITION, defLightPos);

            //1号灯光
            gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_DIFFUSE, diffLightR);
            gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_SPECULAR, specLightR);
            gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_POSITION, lightPosR);

            //2号灯光
            gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_DIFFUSE, diffLightG);
            gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_SPECULAR, specLightG);
            gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_POSITION, lightPosG);

            //3号灯光
            gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_DIFFUSE, diffLightB);
            gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_SPECULAR, specLightB);
            gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_POSITION, lightPosB);

            gl.Enable(OpenGL.GL_LIGHTING);
            gl.Enable(OpenGL.GL_LIGHT0);  //启用默认光源

        

        private void openGLControl_Resized(object sender, EventArgs e)
        
            OpenGL gl = openGLControl.OpenGL;
            gl.MatrixMode(OpenGL.GL_PROJECTION);
            gl.LoadIdentity();
            gl.Perspective(70.0f, (double)Width / (double)Height, 0.01, 100.0);
            gl.LookAt(-5, 5, -5, 0, 0, 0, 0, 1, 0);
            gl.MatrixMode(OpenGL.GL_MODELVIEW);
        

        private void openGLControl_OpenGLDraw(object sender, PaintEventArgs e)
        
            OpenGL gl = openGLControl.OpenGL;
            gl.Clear(OpenGL.GL_COLOR_BUFFER_BIT | OpenGL.GL_DEPTH_BUFFER_BIT);
            gl.LoadIdentity();
            gl.Rotate(rotation, 0.0f, 1.0f, 0.0f);

            draw(gl);
            rotation += 3.0f;

            update(gl);
        

        void update(OpenGL gl)
        
            gl.Enable(OpenGL.GL_LIGHT1);
            m_bReadX += 16;
            m_bReadY += 12;
            gl.Enable(OpenGL.GL_LIGHT2);
            m_bGreenX += 10;
            m_bGreenY += 6;
            gl.Enable(OpenGL.GL_LIGHT3);
            m_bBlueX += 2;
            m_bBlueY += 4;
        

        void draw(OpenGL gl)
        
            gl.PushMatrix();
            //旋转红光
            gl.Rotate(m_bReadX, 1f, 0f, 0f);
            gl.Rotate(m_bReadY, 0f, 1f, 0f);
            //设置红光的位置
            gl.Light(OpenGL.GL_LIGHT1, OpenGL.GL_POSITION, lightPosR);
            //绘制光球
            gl.Translate(lightPosR[0], lightPosR[1], lightPosR[2]);
            gl.Color(1f, 0f, 0f);
            gl.PushAttrib(OpenGL.GL_LIGHTING_BIT);
            gl.Disable(OpenGL.GL_LIGHTING);
            drawSphere(gl, lightPosR[0], lightPosR[1], lightPosR[2], 0.2f, 10, 10, false);
            gl.Enable(OpenGL.GL_LIGHTING);
            gl.PopAttrib();
            gl.PopMatrix();


            gl.PushMatrix();
            //旋转绿光
            gl.Rotate(m_bGreenX, 1f, 0f, 0f);
            gl.Rotate(m_bGreenY, 0f, 1f, 0f);
            //设置绿光的位置
            gl.Light(OpenGL.GL_LIGHT2, OpenGL.GL_POSITION, lightPosG);
            //绘制光球
            gl.Translate(lightPosG[0], lightPosG[1], lightPosG[2]);
            gl.Color(0f, 1f, 0f);
            gl.PushAttrib(OpenGL.GL_LIGHTING_BIT);
            gl.Disable(OpenGL.GL_LIGHTING);
            drawSphere(gl, lightPosG[0], lightPosG[1], lightPosG[2], 0.2f, 10, 10, false);
            gl.Enable(OpenGL.GL_LIGHTING);
            gl.PopAttrib();
            gl.PopMatrix();


            gl.PushMatrix();
            //旋转蓝光
            gl.Rotate(m_bBlueX, 1f, 0f, 0f);
            gl.Rotate(m_bBlueY, 0f, 1f, 0f);
            //设置蓝光的位置
            gl.Light(OpenGL.GL_LIGHT3, OpenGL.GL_POSITION, lightPosB);
            //绘制光球
            gl.Translate(lightPosB[0], lightPosB[1], lightPosB[2]);
            gl.Color(0f, 0f, 1f);
            gl.PushAttrib(OpenGL.GL_LIGHTING_BIT);
            gl.Disable(OpenGL.GL_LIGHTING);
            drawSphere(gl, lightPosB[0], lightPosB[1], lightPosB[2], 0.2f, 10, 10, false);
            gl.Enable(OpenGL.GL_LIGHTING);
            gl.PopAttrib();
            gl.PopMatrix();


            //绘制球体
            gl.PushMatrix();
            gl.Rotate(rotation, 1f, 0f, 0f);
            gl.Rotate(rotation, 0f, 1f, 0f);
            gl.Rotate(rotation, 0f, 0f, 1f);
            drawSphere(gl, 0, 0, 0, 3, 40, 40, false);

            gl.PopMatrix();

            gl.Flush();

        
        //二次曲面球体
        void drawSphere(OpenGL gl, float x, float y, float z, double radius, int segx, int segy, bool isLines)
        
            gl.PushMatrix();
            gl.Translate(x, y, z);
            var sphere = gl.NewQuadric();

            /*
             * QuadricDrawStyle(IntPtr quadObject, uint drawStyle);
             * 第一个参数是二次方程对象状态的指针
             * 第二个参数的枚举值:GLU_FILL(二次方程对象画成实体)、GLU_LINE(二次方程对象画成线框)
             *      GLU_POINT(二次方程对象画成一组顶点的集合)、GLU_SILHOUETTE(类似于线框,但相邻的多边形的边不被绘制)
             * */
            if (isLines)
                gl.QuadricDrawStyle(sphere, OpenGL.GL_LINES);
            else
                gl.QuadricDrawStyle(sphere, OpenGL.GL_QUADS);

            /*
             * QuadricNormals(IntPtr quadricObject, uint normals);
             * 这个函数指定二次方程对象如何生成法线。
             * 第二个参数可以是:GLU_NONE不生成法线,GLU_FLAT扁平法线,GLU_SMOOTH平滑法线。
             * 
             * */
            gl.QuadricNormals(sphere, OpenGL.GLU_NONE);   //GLU_NONE,GLU_FLAT,GLU_SMOOTH

            /*
             * QuadricOrientation(IntPtr quadricObject, int orientation);
             * 这个函数可以指定法线的朝向,指向外面还是只想里面。
             * orientation可以是GLU_OUTSIDE或者是GLU_INSIDE这两个值。
             * OpenGL默认是以GL_CCW逆时针为正方向的
             * 
             * */
            gl.QuadricOrientation(sphere, (int)OpenGL.GLU_OUTSIDE);  //GLU_OUTSIDE,GLU_INSIDE

            /*
             * QuadricTexture(IntPtr quadricObject, int textureCoords)
             * 这个函数可以指定二次方程表面的纹理坐标
             * textureCoords这个参数可以是GL_TRUE或者GL_FALSE.
             * 当为球体和圆柱体生成纹理坐标时,纹理是对称地环绕在球体和圆柱体的表面的
             * 如果应用到圆盘上,那么纹理的中心就是圆盘的中心,然后以线性插值的方式扩展到圆盘的边界
             * 
             * */
            gl.QuadricTexture(sphere, (int)OpenGL.GLU_FALSE);  //GL_TRUE,GLU_FALSE
            gl.Sphere(sphere, radius, segx, segy);
            gl.DeleteQuadric(sphere);
            gl.PopMatrix();
        

        /*
         * 以点画圆
         * 
         * */
        //球心坐标为(x,y,z),球的半径为radius,M,N分别表示球体的横纵向被分成多少份
        void drawSphere1(OpenGL gl, float xx, float yy, float zz, float radius, float M, float N, bool isLines)
        
            const float PI = 3.1415926f;
            float step_z = (float)Math.PI / M;
            float step_xy = 2 * PI / N;
            float[] x = new float[4]  0, 0, 0, 0 ;
            float[] y = new float[4]  0, 0, 0, 0 ;
            float[] z = new float[4]  0, 0, 0, 0 ;

            float angle_z = 0.0f;
            float angle_xy = 0.0f;
            int i = 0, j = 0;
            gl.Begin(OpenGL.GL_QUADS);
            for (i = 0; i < M; i++)
            
                angle_z = i * step_z;
                for (j = 0; j < N; j++)
                
                    angle_xy = j * step_xy;

                    x[0] = (float)(radius * Math.Sin(angle_z) * Math.Cos(angle_xy));
                    y[0] = (float)(radius * Math.Sin(angle_z) * Math.Sin(angle_xy));
                    z[0] = (float)(radius * Math.Cos(angle_z));

                    x[1] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Cos(angle_xy));
                    y[1] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Sin(angle_xy));
                    z[1] = (float)(radius * Math.Cos(angle_z + step_z));

                    x[2] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Cos(angle_xy + step_xy));
                    y[2] = (float)(radius * Math.Sin(angle_z + step_z) * Math.Sin(angle_xy + step_xy));
                    z[2] = (float)(radius * Math.Cos(angle_z + step_z));

                    x[3] = (float)(radius * Math.Sin(angle_z) * Math.Cos(angle_xy + step_xy));
                    y[3] = (float)(radius * Math.Sin(angle_z) * Math.Sin(angle_xy + step_xy));
                    z[3] = (float)(radius * Math.Cos(angle_z));

                    for (int k = 0; k < 4; k++)
                    
                        gl.Vertex(xx + x[k], yy + y[k], zz + z[k]);
                    
                
            
            gl.End();
        
    

 

以上是关于13事例十三:光源例子:环绕二次曲面球体的光源的主要内容,如果未能解决你的问题,请参考以下文章

5 光线/二次曲面 相交和映射

如何在 3D 对象(如球体)上绘制文本

2.3 代数解和几何解的比较

球体表面(经度,纬度)点的凸包

IfcLightSourcePositional

Unity3D中怎么实现摄像机环绕角色和跟随角色的切换?