zoukankan      html  css  js  c++  java
  • OpenGL代码学习(20)--光源的使用

    注意:需要在配置好OpenGL的编程环境中运行下列代码,环境配置文章可参考:

    OpenGL在Mac项目上的配置

    下面的代码,直接放置在main.cpp文件中即可:

    #include "GLTools.h"
    #include "GLShaderManager.h"
    #include "GLFrustum.h"
    #include "GLBatch.h"
    #include "GLFrame.h"
    #include "GLMatrixStack.h"
    #include "GLGeometryTransform.h"
    #include "StopWatch.h"
    
    #include <math.h>
    #include <stdio.h>
    
    #ifdef __APPLE__
    #include <glut/glut.h>
    #else
    #define FREEGLUT_STATIC
    #include <GL/glut.h>
    #endif
    
    // 着色器
    GLShaderManager shaderManager;
    // 视图矩阵堆栈
    GLMatrixStack modelViewMatrix;
    // 投影矩阵堆栈
    GLMatrixStack projectionMatrix;
    // 视景体
    GLFrustum viewFrustum;
    // 照相机角色【Lv2 增加的代码】
    GLFrame cameraFrame;
    // 变换管线
    GLGeometryTransform transformPipeline;
    // 花托批次
    GLTriangleBatch torusBatch;
    // 地板批次
    GLBatch floorBatch;
    // 旋转小球批次【Lv2 增加的代码】
    GLTriangleBatch sphereBatch;
    // 地板颜色,绿色
    GLfloat vFloorColor[] = { 0.0f, 1.0f, 0.0f, 1.0f};
    // 花托线颜色,红色
    GLfloat vTorusColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    // 旋转小球颜色,蓝色【Lv2 增加的代码】
    GLfloat vSphereColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };
    
    // 随机小球群
    #define NUM_SPHERES 50
    GLFrame spheres[NUM_SPHERES];
    
    // 程序初始化
    void SetupRC() {
        
        // 设置窗口背景颜色为黑色
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        
        // 初始化着色器
        shaderManager.InitializeStockShaders();
        
        // 开启深度测试
        glEnable(GL_DEPTH_TEST);
        
        // 设置多边形模式为前后面线段模式【Lv4 删除的代码】
    //    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        
        // 得到花托批次数据
        gltMakeTorus(torusBatch, 0.4f, 0.15f, 30, 30);
        
        // 得到旋转小球批次数据【Lv2 增加的代码】
        gltMakeSphere(sphereBatch, 0.1f, 26, 13);
        
        // 得到方格地板批次数据
        floorBatch.Begin(GL_LINES, 324);
        for(GLfloat x = -20.0; x <= 20.0f; x+= 0.5) {
            floorBatch.Vertex3f(x, -0.55f, 20.0f);
            floorBatch.Vertex3f(x, -0.55f, -20.0f);
            floorBatch.Vertex3f(20.0f, -0.55f, x);
            floorBatch.Vertex3f(-20.0f, -0.55f, x);
        }
        floorBatch.End();
        
        // 随机小球群位置数据生成【Lv3 增加的代码】
        for(int i = 0; i < NUM_SPHERES; i++) {
            GLfloat x = ((GLfloat)((rand() % 400) - 200) * 0.1f);
            GLfloat z = ((GLfloat)((rand() % 400) - 200) * 0.1f);
            spheres[i].SetOrigin(x, 0.0f, z);
        }
    }
    
    // 窗口渲染回调
    void RenderScene(void) {
        
        // 获取2次渲染之间的时间间隔
        static CStopWatch    rotTimer;
        float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
        
        // 清空缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        // 原来是没法移动所以压入原始矩阵,但现在角色可以移动通过角色帧获取照相机矩阵,并压入栈中【Lv2 修改的代码块】
        M3DMatrix44f mCamera;
        cameraFrame.GetCameraMatrix(mCamera);
        modelViewMatrix.PushMatrix(mCamera);
        
        // 得到点光源位置 【Lv4 增加的代码】
        M3DVector4f vLightPos = { 0.0f, 10.0f, 5.0f, 1.0f };
        M3DVector4f vLightEyePos;
        m3dTransformVector4(vLightEyePos, vLightPos, mCamera);
        
        // 绘制地板
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vFloorColor);
        floorBatch.Draw();
        
        // 绘制随机小球群,这里的做法是瞬间切换当前角色位置并开始绘制小球,然后切换回原来角色位置【Lv3 增加的代码】
        for(int i = 0; i < NUM_SPHERES; i++) {
            // 保存当前矩阵状态,为了能切换回原来的角色位置
            modelViewMatrix.PushMatrix();
            // 调整当前角色位置为随机生成小球的位置
            modelViewMatrix.MultMatrix(spheres[i]);
            // 绘制蓝色小球
            // 设置着色器为点光源着色器【Lv4 调整的代码】
            shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
                                         transformPipeline.GetProjectionMatrix(), vLightEyePos, vSphereColor);
    //        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vSphereColor);
            sphereBatch.Draw();
            // 还原矩阵状态,切换为原来角色位置
            modelViewMatrix.PopMatrix();
        }
        
        // 视图矩阵进行平移
        modelViewMatrix.Translate(0.0f, 0.0f, -2.5f);
        
        // 保持旋转前的视图矩阵,因为如果不在旋转前保存,会导致旋转小球也会带上花托的旋转【Lv2 增加的代码】
        modelViewMatrix.PushMatrix();
        
        // 继续进行旋转并进行绘制花托
        modelViewMatrix.Rotate(yRot, 0.0f, 1.0f, 0.0f);
        // 设置着色器为点光源着色器【Lv4 调整的代码】
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
                                     transformPipeline.GetProjectionMatrix(), vLightEyePos, vTorusColor);
    //    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vTorusColor);
        torusBatch.Draw();
        
        // 恢复到旋转前的视图矩阵【Lv2 增加的代码】
        modelViewMatrix.PopMatrix();
        
        // 绘制旋转小球【Lv2 增加的代码】
        modelViewMatrix.Rotate(yRot * -2.0f, 0.0f, 1.0f, 0.0f);
        modelViewMatrix.Translate(0.8f, 0.0f, 0.0f);
        // 设置着色器为点光源着色器【Lv4 调整的代码】
        shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(),
                                     transformPipeline.GetProjectionMatrix(), vLightEyePos, vSphereColor);
    //    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vSphereColor);
        sphereBatch.Draw();
        
        // 出栈,恢复成原始矩阵
        modelViewMatrix.PopMatrix();
        
        // 因为是双缓冲区模式,后台缓冲区替换到前台缓存区进行显示
        glutSwapBuffers();
        
        // 自动触发渲染,达到动画效果
        glutPostRedisplay();
    }
    
    // 特殊按键点击回调【Lv2 增加的代码】
    void SpecialKeys(int key, int x, int y) {
        float linear = 0.1f;
        float angular = float(m3dDegToRad(5.0f));
        
        // 控制角色向前后移动
        if(key == GLUT_KEY_UP)
            cameraFrame.MoveForward(linear);
        
        if(key == GLUT_KEY_DOWN)
            cameraFrame.MoveForward(-linear);
        
        // 控制角色向左右旋转
        if(key == GLUT_KEY_LEFT)
            cameraFrame.RotateWorld(angular, 0.0f, 1.0f, 0.0f);
        
        if(key == GLUT_KEY_RIGHT)
            cameraFrame.RotateWorld(-angular, 0.0f, 1.0f, 0.0f);
    }
    
    // 窗口变换回调
    void ChangeSize(int width, int height) {
        
        // 防止除数为0
        if(height == 0)
            height = 1;
        
        // 设置视口
        glViewport(0, 0, width, height);
        
        // 设置透视投影
        viewFrustum.SetPerspective(35.0f, float(width)/float(height), 1.0f, 100.0f);
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        
        // 设置变换管线的矩阵堆栈
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    }
    
    // 程序入口
    int main(int argc, char* argv[]) {
        // 设置 Mac OS 工作目录路径
        gltSetWorkingDirectory(argv[0]);
        
        // GLUT初始化
        glutInit(&argc, argv);
        
        // 设置渲染模式
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
        
        // 初始化窗口大小
        glutInitWindowSize(800, 720);
        
        // 创建窗口并命名
        glutCreateWindow("OpenGL SphereWorld");
        
        // 判断驱动程序是否初始化完毕
        GLenum err = glewInit();
        if (GLEW_OK != err) {
            fprintf(stderr, "Error: %s
    ", glewGetErrorString(err));
            return 1;
        }
        
        // 窗口变化回调函数设置
        glutReshapeFunc(ChangeSize);
        
        // 窗口渲染回调函数设置
        glutDisplayFunc(RenderScene);
        
        // 特殊按键回调函数设置【Lv2 增加的代码】
        glutSpecialFunc(SpecialKeys);
        
        // 初始化环境
        SetupRC();
        
        // 主消息循环
        glutMainLoop();
        
        return 0;
    }

    效果图:

  • 相关阅读:
    Oracle基础知识整理
    linux下yum安装redis以及使用
    mybatis 学习四 源码分析 mybatis如何执行的一条sql
    mybatis 学习三 mapper xml 配置信息
    mybatis 学习二 conf xml 配置信息
    mybatis 学习一 总体概述
    oracle sql 语句 示例
    jdbc 新认识
    eclipse tomcat 无法加载导入的web项目,There are no resources that can be added or removed from the server. .
    一些常用算法(持续更新)
  • 原文地址:https://www.cnblogs.com/cchHers/p/14726815.html
Copyright © 2011-2022 走看看