在显示屏上使用多个着色器

时间:2014-05-20 08:52:37

标签: c# opengl shader

这个问题是基于关于OpenGL的Giawa教程。我已经完成了tut6& tut9分开,但现在我想把两者结合起来。即我希望那个立方体旋转,而一堆星星漂浮在周围。但是,我是两个很新的OpenGL,但看起来他们使用不同类型的着色器。所以我写了两个着色器,但现在当我尝试运行它时,我的立方体是透明的,星星不显示。是否可以在屏幕上同时正确显示?以下是我的代码。

using System;
using Tao.FreeGlut;
using OpenGL;
using System.Windows;
using System.Windows.Forms;
using System.Collections.Generic;

namespace OpenGLTutorial6
{
    class Program
    {
        private static int width = 1280, height = 720;
        private static ShaderProgram program, program_2;
        private static VBO<Vector3> cube, top_pyramid, bottom_pyramid, cubeNormals, bottom_pyramidNormals, top_pyramidNormals, star;
        private static VBO<Vector2> cubeUV, top_pyramidUV, bottom_pyramidUV, starUV;
        private static VBO<int> cubeQuads, top_pyramidTrianlges, bottom_pyramidTrianlges, starQuads;
        private static bool fullscreen = false;
        private static bool left, right, up, down;
        private static List<Star> stars = new List<Star>();
        private static Random generator = new Random(Environment.TickCount);
        private static float theta = (float)Math.PI / 2, phi = (float)Math.PI / 2;

        private static Texture crateTexture, 
            brickTexture,
            cracked_glassTexture,
            desert_surfaceTexture,
            numbersTexture,
            ziggyTexture,
            starTexture;

        private static System.Diagnostics.Stopwatch watch;
        private static float angle;
        private static int rotate = 1;
        private static bool lighting = true;

        private class Star
        {
            public float angle;
            public float dist;
            public Vector3 color;

            public Star(float Angle, float Distance, Vector3 Color)
            {
                this.angle = Angle;
                this.dist = Distance;
                this.color = Color;
            }
        }

        static void Main(string[] args)
        {
            // create an OpenGL window
            Glut.glutInit();
            Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | Glut.GLUT_DEPTH);
            Glut.glutInitWindowSize(width, height);
            Glut.glutCreateWindow("SCREENSAVER");

            // provide the Glut callbacks that are necessary for running this tutorial
            Glut.glutIdleFunc(OnRenderFrame);
            //Glut.glutIdleFunc(OnRenderFrame_2);
            Glut.glutDisplayFunc(OnDisplay);
            //<<<<<<<<<<<<< KEYBOARD FUNCTIONS
            Glut.glutSpecialFunc(new Glut.SpecialCallback(OnKeyPress));
            Glut.glutKeyboardFunc(OnKeyboardDown);
            Glut.glutKeyboardUpFunc(OnKeyboardUp);
            //<<<<<<<<<<<<< DISPOSE
            Glut.glutCloseFunc(OnClose);

            // enable depth testing to ensure correct z-ordering of our fragments
            Gl.Enable(EnableCap.DepthTest);
            Gl.Disable(EnableCap.DepthTest);
            Gl.Enable(EnableCap.Blend);
            Gl.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.One);

            //<<<<<<<<<<<   COMPILE SHADER PROGRAMS
            program = new ShaderProgram(VertexShader, FragmentShader);
            program_2 = new ShaderProgram(VertexShader_2, FragmentShader_2);

            //set the view and projection matrix, which are static throughout this tutorial
            program.Use();
            program["projection_matrix"].SetValue(Matrix4.CreatePerspectiveFieldOfView(0.45f, (float)width / height, 0.1f, 1000f));
            program["view_matrix"].SetValue(Matrix4.LookAt(new Vector3(0, 0, 10), Vector3.Zero, Vector3.Up));
            program["light_direction"].SetValue(new Vector3(1, 1, 1));
            program["enable_lighting"].SetValue(lighting);


            program_2.Use();
            program_2["projection_matrix"].SetValue(Matrix4.CreatePerspectiveFieldOfView(0.45f, (float)width / height, 0.1f, 1000f));
            program_2["view_matrix"].SetValue(Matrix4.LookAt(new Vector3(0, 0, 20), Vector3.Zero, Vector3.Up));

            //<<<<<<<<<     LOAD TEXTURES
            crateTexture = new Texture("crate.jpg");
            brickTexture = new Texture("bricks.jpg");
            cracked_glassTexture = new Texture("crack.jpg");
            desert_surfaceTexture = new Texture("desert.jpg");
            numbersTexture = new Texture("numbers.jpg");
            ziggyTexture = new Texture("ziggy.jpg");
            starTexture = new Texture("star.bmp");

            // each star is simply a quad
            star = new VBO<Vector3>(new Vector3[] { new Vector3(-1, -1, 0), new Vector3(1, -1, 0), new Vector3(1, 1, 0), new Vector3(-1, 1, 0) });
            starUV = new VBO<Vector2>(new Vector2[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) });
            starQuads = new VBO<int>(new int[] { 0, 1, 2, 3 }, BufferTarget.ElementArrayBuffer);

            // create 50 stars for this tutorial
            int numStars = 50;
            for (int i = 0; i < numStars; i++)
            {
                stars.Add(new Star(0, (float)i / numStars * 4f, new Vector3(generator.NextDouble(), generator.NextDouble(), generator.NextDouble())));
            }


            // create a crate with vertices and UV coordinates
            cube = new VBO<Vector3>(new Vector3[]
            {
                new Vector3(-1.5, 0, -0.5), new Vector3(-0.5, 1, -0.5), new Vector3(-0.5, 1, 0.5), new Vector3(-1.5, 0, 0.5),
                new Vector3(-0.5, 1, -0.5), new Vector3(0.5, 1, -0.5), new Vector3(0.5, 1, 0.5), new Vector3(-0.5, 1, 0.5),
                new Vector3(0.5, 1, -0.5), new Vector3(1.5, 0, -0.5), new Vector3(1.5, 0, 0.5), new Vector3(0.5, 1, 0.5),
                new Vector3(1.5, 0, -0.5), new Vector3(1.5, 0, 0.5), new Vector3(0.5, -1, 0.5), new Vector3(0.5, -1, -0.5),
                new Vector3(0.5, -1, 0.5), new Vector3(0.5, -1, -0.5), new Vector3(-0.5, -1, -0.5), new Vector3(-0.5, -1, 0.5),
                new Vector3(-0.5, -1, -0.5), new Vector3(-0.5, -1, 0.5), new Vector3(-1.5, 0, 0.5), new Vector3(-1.5, 0, -0.5)
             });
            cubeUV = new VBO<Vector2>(new Vector2[] {
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) });

            top_pyramid = new VBO<Vector3>(new Vector3[] 
            {
                new Vector3(-1.5, 0, -0.5), new Vector3(-0.5, 1, -0.5), new Vector3(0, 0, -1.5),
                new Vector3(-0.5, 1, -0.5), new Vector3(0.5, 1, -0.5), new Vector3(0, 0, -1.5),
                new Vector3(0.5, 1, -0.5), new Vector3(1.5, 0, -0.5), new Vector3(0, 0, -1.5),
                new Vector3(1.5, 0, -0.5), new Vector3(0.5, -1, -0.5), new Vector3(0, 0, -1.5),
                new Vector3(0.5, -1, -0.5), new Vector3(-0.5, -1, -0.5), new Vector3(0, 0, -1.5),
                new Vector3(-0.5, -1, -0.5), new Vector3(-1.5, 0, -0.5), new Vector3(0, 0, -1.5)
            });
            top_pyramidUV = new VBO<Vector2>(new Vector2[] {
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1)});

            bottom_pyramid = new VBO<Vector3>(new Vector3[]
            {
                new Vector3(-1.5, 0, 0.5), new Vector3(-0.5, 1, 0.5), new Vector3(0, 0, 1.5),
                new Vector3(-0.5, 1, 0.5), new Vector3(0.5, 1, 0.5), new Vector3(0, 0, 1.5),
                new Vector3(0.5, 1, 0.5), new Vector3(1.5, 0, 0.5), new Vector3(0, 0, 1.5),
                new Vector3(1.5, 0, 0.5), new Vector3(0.5, -1, 0.5), new Vector3(0, 0, 1.5),
                new Vector3(0.5, -1, 0.5), new Vector3(-0.5, -1, 0.5), new Vector3(0, 0, 1.5),
                new Vector3(-0.5, -1, 0.5), new Vector3(-1.5, 0, 0.5), new Vector3(0, 0, 1.5)
            });

            bottom_pyramidUV = new VBO<Vector2>(new Vector2[] {
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1),
                new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1)});

            cubeNormals = new VBO<Vector3>(new Vector3[] {
                new Vector3(0, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 1, 0), new Vector3(0, 1, 0), 
                new Vector3(0, -1, 0), new Vector3(0, -1, 0), new Vector3(0, -1, 0), new Vector3(0, -1, 0), 
                new Vector3(0, 0, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 1), 
                new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1), 
                new Vector3(-1, 0, 0), new Vector3(-1, 0, 0), new Vector3(-1, 0, 0), new Vector3(-1, 0, 0), 
                new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0) 
            });
            top_pyramidNormals = new VBO<Vector3>(new Vector3[]{
                new Vector3(0,1,0), new Vector3(0,1,0), new Vector3(0,1,0), new Vector3(0,1,0),
                new Vector3(0, -1, 0), new Vector3(0, -1, 0), new Vector3(0, -1, 0),
                new Vector3(0, 0, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 1),
                new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1),
                new Vector3(-1, 0, 0), new Vector3(-1, 0, 0), new Vector3(-1, 0, 0),
                new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0)
            });
            bottom_pyramidNormals = new VBO<Vector3>(new Vector3[]{
                new Vector3(0,1,0), new Vector3(0,1,0), new Vector3(0,1,0), new Vector3(0,1,0),
                new Vector3(0, -1, 0), new Vector3(0, -1, 0), new Vector3(0, -1, 0),
                new Vector3(0, 0, 1), new Vector3(0, 0, 1), new Vector3(0, 0, 1),
                new Vector3(0, 0, -1), new Vector3(0, 0, -1), new Vector3(0, 0, -1),
                new Vector3(-1, 0, 0), new Vector3(-1, 0, 0), new Vector3(-1, 0, 0),
                new Vector3(1, 0, 0), new Vector3(1, 0, 0), new Vector3(1, 0, 0)
            });


            cubeQuads = new VBO<int>(new int[] { 0, 1, 2, 3, 
                4, 5, 6, 7, 
                8, 9, 10, 11, 
                12, 13, 14, 15, 
                16, 17, 18, 19, 
                20, 21, 22, 23 }, BufferTarget.ElementArrayBuffer);

            top_pyramidTrianlges = new VBO<int>(new int[] { 
                0,1,2, 
                3,4,5,
                6,7,8,
                9,10,11,
                12,13,14, 
                15,16,17}, BufferTarget.ElementArrayBuffer);

            bottom_pyramidTrianlges = new VBO<int>(new int[] { 
                0,1,2, 
                3,4,5,
                6,7,8,
                9,10,11,
                12,13,14, 
                15,16,17}, BufferTarget.ElementArrayBuffer);

            watch = System.Diagnostics.Stopwatch.StartNew();

            Gl.BindTexture(desert_surfaceTexture);
            Glut.glutMainLoop();
        }

        private static void OnClose()
        {
            // dispose of all of the resources that were created
            //must still update
            cube.Dispose();
            cubeUV.Dispose();
            top_pyramid.Dispose();
            top_pyramidTrianlges.Dispose();
            cubeQuads.Dispose();
            crateTexture.Dispose();
            program.DisposeChildren = true;
            program.Dispose();
        }

        private static void OnDisplay()
        {

        }

        private static void OnRenderFrame()
        {
            // calculate how much time has elapsed since the last frame
            watch.Stop();
            float deltaTime = (float)watch.ElapsedTicks / System.Diagnostics.Stopwatch.Frequency;
            watch.Restart();

            // use the deltaTime to adjust the angle of the cube
            angle += deltaTime;

            // set up the OpenGL viewport and clear both the color and depth bits
            Gl.Viewport(0, 0, width, height);
            Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            // use our shader program and bind the crate texture
            Gl.UseProgram(program);

            //<<<<<<<<<<<<   TOP PYRAMID
            // set the transformation of the top_pyramid
            program["model_matrix"].SetValue(Matrix4.CreateRotationY(angle * rotate));
            program["enable_lighting"].SetValue(lighting);
            // bind the vertex positions, UV coordinates and element array
            Gl.BindBufferToShaderAttribute(top_pyramid, program, "vertexPosition");
            Gl.BindBufferToShaderAttribute(top_pyramidNormals, program, "vertexNormal");
            Gl.BindBufferToShaderAttribute(top_pyramidUV, program, "vertexUV");
            Gl.BindBuffer(top_pyramidTrianlges);
            // draw the textured top_pyramid
            Gl.DrawElements(BeginMode.Triangles, top_pyramidTrianlges.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);


            //<<<<<<<<<<    CUBE
            // set the transformation of the cube
            program["model_matrix"].SetValue(Matrix4.CreateRotationY(angle *rotate));
            program["enable_lighting"].SetValue(lighting);
            // bind the vertex positions, UV coordinates and element array
            Gl.BindBufferToShaderAttribute(cube, program, "vertexPosition");
            Gl.BindBufferToShaderAttribute(cubeNormals, program, "vertexNormal");
            Gl.BindBufferToShaderAttribute(cubeUV, program, "vertexUV");
            Gl.BindBuffer(cubeQuads);
           // draw the textured cube
           Gl.DrawElements(BeginMode.Quads, cubeQuads.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);

           //<<<<<<<<<<<<   BOTTOM PYRAMID
           // set the transformation of the bottom_pyramid
           program["model_matrix"].SetValue(Matrix4.CreateRotationY(angle * rotate));
           program["enable_lighting"].SetValue(lighting);
           // bind the vertex positions, UV coordinates and element array
           Gl.BindBufferToShaderAttribute(bottom_pyramid, program, "vertexPosition");
           Gl.BindBufferToShaderAttribute(bottom_pyramidNormals, program, "vertexNormal");
           Gl.BindBufferToShaderAttribute(bottom_pyramidUV, program, "vertexUV");
           Gl.BindBuffer(bottom_pyramidTrianlges);
           // draw the textured bottom_pyramid
           Gl.DrawElements(BeginMode.Triangles, bottom_pyramidTrianlges.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);

            Glut.glutSwapBuffers();
        }

        private static void OnRenderFrame_2()
        {
            watch.Stop();
            float deltaTime = (float)watch.ElapsedTicks / System.Diagnostics.Stopwatch.Frequency;
            watch.Restart();

            // perform rotation of the scene depending on keyboard input
            if (right) phi += deltaTime;
            if (left) phi -= deltaTime;
            if (up) theta += deltaTime;
            if (down) theta -= deltaTime;
            if (theta < 0) theta += (float)Math.PI * 2;


            // set up the OpenGL viewport and clear both the color and depth bits
            Gl.Viewport(0, 0, width, height);
            Gl.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

            //<<<<<<<<<      STARS
            // make sure the shader program and texture are being used
            Gl.UseProgram(program_2);
            Gl.BindTexture(starTexture);
            // calculate the camera position using some fancy polar co-ordinates
            Vector3 position = 20 * new Vector3(Math.Cos(phi) * Math.Sin(theta), Math.Cos(theta), Math.Sin(phi) * Math.Sin(theta));
            Vector3 upVector = ((theta % (Math.PI * 2)) > Math.PI) ? Vector3.Up : Vector3.Down;
            program_2["view_matrix"].SetValue(Matrix4.LookAt(position, Vector3.Zero, upVector));

            // loop through the stars, drawing each one
            for (int i = 0; i < stars.Count; i++)
            {
                // set the position and color of this star
                program_2["model_matrix"].SetValue(Matrix4.CreateTranslation(new Vector3(stars[i].dist, 0, 0)) * Matrix4.CreateRotationZ(stars[i].angle));
                program_2["color"].SetValue(stars[i].color);

                Gl.BindBufferToShaderAttribute(star, program_2, "vertexPosition");
                Gl.BindBufferToShaderAttribute(starUV, program_2, "vertexUV");
                Gl.BindBuffer(starQuads);

                Gl.DrawElements(BeginMode.Quads, starQuads.Count, DrawElementsType.UnsignedInt, IntPtr.Zero);

                // update the position of the star
                stars[i].angle += (float)i / stars.Count * deltaTime * 2;
                stars[i].dist -= 0.2f * deltaTime;

                // if we've reached the center then move this star outwards and give it a new color
                if (stars[i].dist < 0f)
                {
                    stars[i].dist += 5f;
                    stars[i].color = new Vector3(generator.NextDouble(), generator.NextDouble(), generator.NextDouble());
                }
            }

            Glut.glutSwapBuffers();
        }
        public static void OnKeyPress(int theKey, int x, int y)
        {
            switch (theKey)
            {
                //<<<<<<<   ROTATE
                case Glut.GLUT_KEY_F5:
                    {
                        rotate += 1;
                        Console.WriteLine("Hallo!");
                    }
                    break;
                case Glut.GLUT_KEY_F6:
                    {
                        rotate -= 1;
                    }
                    break;

                //<<<<<<<<<<    TEXTURES
                case Glut.GLUT_KEY_F7:
                    {
                        Gl.BindTexture(cracked_glassTexture);
                    }
                    break;
                case Glut.GLUT_KEY_F8:
                    {
                        Gl.BindTexture(desert_surfaceTexture);
                    }
                    break;
                case Glut.GLUT_KEY_F9:
                    {
                        Gl.BindTexture(brickTexture);
                    }
                    break;
                case Glut.GLUT_KEY_F10:
                    {
                        Gl.BindTexture(ziggyTexture);
                    }
                    break;
                case Glut.GLUT_KEY_F11:
                    {
                        Gl.BindTexture(numbersTexture);
                    }
                    break;
            }
            Glut.glutPostRedisplay();
        }


        private static void OnKeyboardDown(byte key, int x, int y)
        {
            if (key == 'w') up = true;
            else if (key == 's') down = true;
            else if (key == 'd') right = true;
            else if (key == 'a') left = true;
            else if (key == 27) Glut.glutLeaveMainLoop();
        }

        private static void OnKeyboardUp(byte key, int x, int y)
        {
            if (key == 'w') up = false;
            else if (key == 's') down = false;
            else if (key == 'd') right = false;
            else if (key == 'a') left = false;
            else if (key == 'f')
            {
                fullscreen = !fullscreen;
                if (fullscreen) Glut.glutFullScreen();
                else
                {
                    Glut.glutPositionWindow(0, 0);
                    Glut.glutReshapeWindow(1280, 720);
                }
            }
        }
        public static string VertexShader = @"
#version 130

in vec3 vertexPosition;
in vec3 vertexNormal;
in vec2 vertexUV;

out vec3 normal;
out vec2 uv;

uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;

void main(void)
{
    normal = normalize((model_matrix * vec4(floor(vertexNormal), 0)).xyz);
    uv = vertexUV;

    gl_Position = projection_matrix * view_matrix * model_matrix * vec4(vertexPosition, 1);
}
";

        public static string FragmentShader = @"
#version 130

uniform sampler2D texture;
uniform vec3 light_direction;
uniform bool enable_lighting;

in vec3 normal;
in vec2 uv;

out vec4 fragment;

void main(void)
{
    float diffuse = max(dot(normal, light_direction), 0);
    float ambient = 0.2;
    float lighting = (enable_lighting ? max(diffuse, ambient) : 1);

    fragment = lighting * texture2D(texture, uv);
}
";

        public static string VertexShader_2 = @"
#version 130

in vec3 vertexPosition;
in vec2 vertexUV;

out vec2 uv;

uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform mat4 model_matrix;

void main(void)
{
    uv = vertexUV;

    gl_Position = projection_matrix * (view_matrix * model_matrix * vec4(0, 0, 0, 1) + vec4(vertexPosition.x, vertexPosition.y, vertexPosition.z, 0));
    //gl_Position = projection_matrix * view_matrix * model_matrix * vec4(vertexPosition, 1);
}
";

        public static string FragmentShader_2 = @"
#version 130

uniform sampler2D texture;
uniform vec3 color;

in vec2 uv;

out vec4 fragment;

void main(void)
{
    fragment = vec4(color * texture2D(texture, uv).xyz, 1);
}
";
    }
}

此外,我还添加了原始教程中没有的其他纹理

1 个答案:

答案 0 :(得分:0)

从扫描代码开始,您似乎拥有了所需的大部分内容。要同时呈现这两个项目,您基本上必须将OnRenderFrame_2()中当前拥有的呈现代码添加到OnRenderFrame()。确保您一开始只有一个glClear(),最后只有一个glutSwapBuffers()

如果您的代码大纲目前如下所示:

OnRenderFrame
    prepare rendering of Item 1
    glViewport
    glClear
    glUseProgram(program1)
    render Item 1
    glutSwapBuffers

OnRenderFrame_2
    prepare rendering of Item 2
    glViewport
    glClear
    glUseProgram(program2)
    render Item 2
    glutSwapBuffers

像这样重新排列:

OnRenderFrame
    prepare rendering of Item 1
    prepare rendering of Item 2
    glViewport
    glClear
    glUseProgram(program1)
    render Item 1
    glUseProgram(program2)
    render Item 2
    glutSwapBuffers