OpenGL 初步

2019-05-01  本文已影响0人  Nino_Lau

开发环境


OpenGL 简介

OpenGL是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口。这个接口由近350个不同的函数调用组成,用来从简单的图形比特绘制复杂的三维景象。而另一种程序接口系统是仅用于Microsoft Windows上的Direct3D。OpenGL常用于CAD、虚拟实境、科学可视化程序和电子游戏开发。


测试步骤

运行步骤如下:

  1. brew install cmake assimp glm glfw
  2. git clone https://github.com/LovelyBuggies/Blender_PAOGD_Homework.git
  3. cd ./Blender_PAOGD_Homework/PAOGD_HW3/src
  4. mkdir build
  5. cd build
  6. cmake ..
  7. make -j8
  8. cd ./bin
  9. ./PAOGD_HW3

运行可执行文件之后,我们可以看见如下画面:

image

CMake

模型是用C语言编写的,用CMake进行编译。src目录下CMakeLists.txt文件是用来进行CMake的文件,文件的主要构成如下。

  1. 首先设置 build CMake 的路径,并查找需求包:
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
link_directories(${CMAKE_SOURCE_DIR}/lib)

find_package(GLM REQUIRED)
message(STATUS "GLM included at ${GLM_INCLUDE_DIR}")
find_package(GLFW3 REQUIRED)
message(STATUS "Found GLFW3 in ${GLFW3_INCLUDE_DIR}")
find_package(ASSIMP REQUIRED)
message(STATUS "Found ASSIMP in ${ASSIMP_INCLUDE_DIR}")
  1. 查找相关的框架:
INCLUDE_DIRECTORIES(/System/Library/Frameworks)
FIND_LIBRARY(COCOA_LIBRARY Cocoa)
FIND_LIBRARY(OpenGL_LIBRARY OpenGL)
FIND_LIBRARY(IOKit_LIBRARY IOKit)
FIND_LIBRARY(CoreVideo_LIBRARY CoreVideo)
MARK_AS_ADVANCED(COCOA_LIBRARY OpenGL_LIBRARY)
SET(APPLE_LIBS ${COCOA_LIBRARY} ${IOKit_LIBRARY} ${OpenGL_LIBRARY} ${CoreVideo_LIBRARY})
SET(APPLE_LIBS ${APPLE_LIBS} ${GLFW3_LIBRARY} ${ASSIMP_LIBRARY})
set(LIBS ${LIBS} ${APPLE_LIBS})
  1. 设置 DEMOs:
set(DEMOS
    PAOGD_HW3
)   
  1. 为项目创建所需的静态库
add_library(STB_IMAGE "src/stb_image.cpp")
set(LIBS ${LIBS} STB_IMAGE)

add_library(GLAD "src/glad.c")
set(LIBS ${LIBS} GLAD)

macro(makeLink src dest target)
  add_custom_command(TARGET ${target} POST_BUILD COMMAND ${CMAKE_COMMAND} -E create_symlink ${src} ${dest}  DEPENDS  ${dest} COMMENT "mklink ${src} -> ${dest}")
endmacro()
  1. 为项目创建可执行文件,我们就可以在./build/bin中找到PAOGD_HW3.exec了。
    • 首先我们添加了源代码和库文件;
    • 然后我们复制着色器文件以构建目录;
    • 在每个着色器中,读取模型并为其创建链接。
foreach(DEMO ${DEMOS})
    file(GLOB SOURCE
        "src/${DEMO}/*.h"
        "src/${DEMO}/*.cpp"
        "src/${DEMO}/*.vs"
        "src/${DEMO}/*.fs"
        "src/${DEMO}/*.gs"
    )
    set(NAME "${DEMO}")
    add_executable(${NAME} ${SOURCE})
    target_link_libraries(${NAME} ${LIBS})

    set_target_properties(${NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/bin")
    set_target_properties(${NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}/bin")
    set_target_properties(${NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}/bin")

    file(GLOB SHADERS
             "src/${DEMO}/*.vs"
             "src/${DEMO}/*.fs"
             "src/${DEMO}/*.gs"
    )
    foreach(SHADER ${SHADERS})

        get_filename_component(SHADERNAME ${SHADER} NAME)
        makeLink(${SHADER} ${CMAKE_CURRENT_BINARY_DIR}/bin/${SHADERNAME} ${NAME})

    endforeach(SHADER)
    
endforeach(DEMO)

以上就是CMake生成可执行程序的过程。


OBJ文件

OBJ文件是一套基于工作站的3D建模和动画软件开发的一种标准3D模型文件格式,很适合用于3D软件模型之间的互导。Blender支持OBJ文件的读写。OBJ文件格式支持直线、多边形、表面和自由形态曲线。直线和多边形通过它们的点来描述,曲线和表面则根据它们的控制点和依附于曲线类型的额外信息来定义。


OpenGL & Blender

OpenGL 是一种渲染编程语言接口,有良好的通用型和渲染表现。Blender 是一款知名的三维动画制作软件,其中很多三维模型的制作和导出需要渲染功能。可以说,Blender是基于OpenGL进行开发的,当然它也包含一些其他的渲染引擎,比如cycle、eevee等。


OpenGL的坐标系统

OpenGL希望每次顶点着色后,我们的可见顶点都为标准化设备坐标。也就是说每个顶点的X、Y、Z都应该在−1 到1 之间,超出这个范围的顶点将是不可见的。通常情况下我们会自己设定一个坐标范围,之后再在顶点着色器中将这些坐标变换为表转化设备坐标。然后这些标化设备坐标传入光栅器,将它们变换为屏幕上的二维坐标和像素。

将坐标变换为标准化设备坐标,接着再转化为屏幕坐标的过程通常是分步进行的。物体的顶点在最终转化为屏幕坐标之前还会被变换到多个过渡坐标系统,使一些操作或运算更加方便和容易。一些常见的坐标系统包括:局部空间、世界空间、观察空间、裁剪空间、屏幕空间。

这就是一个顶点在最终被转化为片段之前需要经历的所有不同状态。为了将坐标从一个坐标系变换到另一个坐标系,我们需要用到几个变换矩阵,最重要的几个分别是模型、观察、投影三个矩阵。下面这张图阐释了流程以及各个变换的功能:

image

功能实现

首先设置基本变量:JKL布尔变量分别表示按键触发与否;浮点数ftfs分别表示变化度量;IO分别表示变化返回与否。

bool j = false;
bool k = false;
bool l = false;
float ft = 0.0f;
float fs = 0.1f;
bool i = true;
bool o = true;

processInput函数中,定义新的事件:

if (glfwGetKey(window, GLFW_KEY_J) == GLFW_PRESS)
    j = true;
if (glfwGetKey(window, GLFW_KEY_K) == GLFW_PRESS)
    k = true;
if (glfwGetKey(window, GLFW_KEY_L) == GLFW_PRESS)
    l = true;
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS){
    j = false;
    k = false;
    l = false;
}

在主函数增加一些新的选项(因为这次实验功能相对单一所以未设立新的函数):

// rotate option
if(j == true)
model = glm::rotate(model, (float)glfwGetTime(), glm::vec3(0.0f, 1.0f, 0.0f));

// translation option
if(k == true){
    if(ft < 12.0f && i == true){
        model = glm::translate(model, glm::vec3(ft, 0.0f, 0.0f));
        ft += 0.005f;        
    } else{
        i = false;
        model = glm::translate(model, glm::vec3(ft, 0.0f, 0.0f));
        ft -= 0.005f;
        if(ft < -12.0f)
            i=true;        
    }
}

// scale option
if(l == true){
    if(fs < 3.0f && o == true){
        model = glm::scale(model,glm::vec3(fs, fs, fs));
        fs += 0.001f;       
    } else{   
        o = false;
        model = glm::scale(model, glm::vec3(fs, fs, fs));
        fs -= 0.001f;
        if(fs < 0.1f)
            o = true;        
    }
}

将着色器添加进入模型,新版本的模型就建立好了。

ourShader.setMat4("model", model);
ourModel.Draw(ourShader);

目录文件

[图片上传失败...(image-f712fd-1556702039061)]

生成可执行文件后的目录如图所示:


效果展示

需求实现后的效果展示如下:

旋转

image

平移

image

缩放

scale.gif

同时

image

参考


上一篇 下一篇

猜你喜欢

热点阅读