第七课:纹理滤波、光源和键盘控制



  • 纹理滤波

    在纹理映射的过程中,如果图元的大小不等于纹理的大小,OpenGL便会对纹理进行缩放以适应图元的尺寸。我们可以通过设置纹理滤镜来决定OpenGL对某个纹理采用的放大、缩小的算法

    滤镜 描述
    GL_NEAREST 取最邻近像素
    GL_LINEAR 线性内部插值
    GL_NEAREST_MIPMAP_NEAREST 最近多贴图等级的最邻近像素
    GL_NEAREST_MIPMAP_LINEAR 在最近多贴图等级的内部线性插值
    GL_LINEAR_MIPMAP_NEAREST 在最近多贴图等级的外部线性插值
    GL_LINEAR_MIPMAP_LINEAR 在最近多贴图等级的外部和内部线性插值

    光源

    环境光

    因为我们使用的OpenGL 3.x API,使用可编程管线,不使用glLightfv

    修改着色器代码

    • 颜色=环境光强度(0.5)* 环境光颜色 * 物体本身颜色
    static const char *vertexShaderSource =
        "attribute highp vec4 posAttr;\n"
        "attribute lowp vec3 colAttr;\n"
        "varying lowp vec3 col;\n"
        "uniform highp mat4 projection;\n"
        "uniform highp mat4 view;\n"
        "uniform highp mat4 model;\n"
        "attribute vec2 a_texcoord;\n"
        "varying highp vec2 v_texcoord;\n"
        "void main() {\n"
        "   gl_Position = projection * view * model * posAttr;\n"
        "   v_texcoord = a_texcoord;\n"
        "   col = colAttr;\n"
        "}\n";
    
    static const char *fragmentShaderSource =
        "varying lowp vec3 col;\n"
        "uniform sampler2D texture;\n"
        "uniform lowp vec3 ambientColAttr;\n"
        "varying highp vec2 v_texcoord;\n"
        "void main() {\n"
        "   float ambientStrength = 0.5f;\n"
        "   gl_FragColor = vec4(ambientStrength * ambientColAttr * col, 1.0f);\n"
        "}\n";
    

    获取 环境光属性

    //环境光属性
    m_ambientColAttr = m_program->uniformLocation("ambientColAttr");
    

    绘制时候设置环境光

    QVector3D ambient(1.0f, 1.0f, 1.0f);
    m_program->setUniformValue(m_ambientColAttr, ambient);
    

    效果

    之所以有这样的效果,是因为左上角白色受环境光影响,反射了环境光颜色

    • 白色环境光
      0_1526954839519_f40f63b4-9d0a-46c9-a505-a98451d42c33-image.png
    • 红色环境光
      0_1526954873463_d6a83b40-63bb-4986-8a4f-d5df3a1475a4-image.png
    • 绿色环境光
      0_1526954902270_14818a8e-daf4-4f8c-8563-2c711e200dbf-image.png
    • 蓝色环境光
      0_1526954923358_7a242e55-54fe-4108-9d41-d39813facab2-image.png

    点光源-漫反射

    修改着色器代码

    我们追加了点光源颜色,光源位置,物体的法线(实际具有增幅/衰减光亮的效果)

    static const char *vertexShaderSource =
        "attribute highp vec3 posAttr;\n"
        "attribute lowp vec3 colAttr;\n"
        "varying lowp vec3 col;\n"
        "uniform lowp vec3 aNormal;\n"
        "uniform highp mat4 projection;\n"
        "uniform highp mat4 view;\n"
        "uniform highp mat4 model;\n"
        "attribute vec2 a_texcoord;\n"
    
        "varying highp vec2 v_texcoord;\n"
        "varying vec3 Normal;\n"
        "varying vec3 FragPos;\n"
    
        "void main() {\n"
        "   gl_Position = projection * view * model * vec4(posAttr, 1.0);\n"
        "   FragPos = vec3(model * vec4(posAttr, 1.0));\n"
        "   v_texcoord = a_texcoord;\n"
        "   Normal = mat3(transpose(inverse(model))) * aNormal;\n"
        "   col = colAttr;\n"
        "}\n";
    
    static const char *fragmentShaderSource =
        "varying lowp vec3 col;\n"
        "uniform sampler2D texture;\n"
        "uniform lowp vec3 ambientColAttr;\n"
        "uniform lowp vec3 lightColAttr;\n"
        "uniform lowp vec3 lightPosAttr;\n"
    
        "varying highp vec2 v_texcoord;\n"
        "varying vec3 Normal;\n"
        "varying vec3 FragPos;\n"
    
        "void main() {\n"
        "   vec3 norm = normalize(Normal);\n"
        "   vec3 lightDir = normalize(lightPosAttr - FragPos);\n"
        "   float ambientStrength = 0.1;\n"
        "   float diffuse = max(dot(norm, lightDir), 0.0);\n"
        "   gl_FragColor = vec4((ambientStrength + diffuse) * lightColAttr * col, 1.0);\n"
        "}\n";
    

    获取 点光源属性

    //点光源属性
        m_lightColAttr = m_program->uniformLocation("lightColAttr");
        m_lightPosAttr = m_program->uniformLocation("lightPosAttr");
        m_aNormal = m_program->uniformLocation("aNormal");
    

    绘制时候设置点光

    //环境光
        QVector3D ambient(1.0f, 1.0f, 1.0f);
        m_program->setUniformValue(m_ambientColAttr, ambient);
    
        //点光源-漫反射
        QVector3D pointLightCol(1.0f, 1.0f, 1.0f);
        m_program->setUniformValue(m_lightColAttr, pointLightCol);
    
        QVector3D pointLightPos(2.0f, 0.0f, 2.0f);
        m_program->setUniformValue(m_lightPosAttr, pointLightPos);
    
        //法线=强度
        QVector3D objNormal(0.0f, 1.0f, 1.0f);
        m_program->setUniformValue(m_aNormal, objNormal);
    

    效果

    0_1526965557596_20180522_125850.gif

    高光-镜面反射

    光源照射到物体然后反射到人的眼睛里时,物体上最亮的那个点就是高光,
    所以我们需要知道眼睛(摄像机)的位置,然后根据光的方向,法线求出反射

    修改着色器代码

    static const char *vertexShaderSource =
        "attribute highp vec3 posAttr;\n"
        "attribute lowp vec3 colAttr;\n"
        "varying lowp vec3 col;\n"
        "uniform lowp vec3 aNormal;\n"
        "uniform highp mat4 projection;\n"
        "uniform highp mat4 view;\n"
        "uniform highp mat4 model;\n"
        "attribute vec2 a_texcoord;\n"
    
        "varying highp vec2 v_texcoord;\n"
        "varying vec3 Normal;\n"
        "varying vec3 FragPos;\n"
    
        "void main() {\n"
        "   gl_Position = projection * view * model * vec4(posAttr, 1.0);\n"
        "   FragPos = vec3(model * vec4(posAttr, 1.0));\n"
        "   v_texcoord = a_texcoord;\n"
        "   Normal = mat3(transpose(inverse(model))) * aNormal;\n"
        "   col = colAttr;\n"
        "}\n";
    
    static const char *fragmentShaderSource =
        "varying lowp vec3 col;\n"
        "uniform sampler2D texture;\n"
        "uniform lowp vec3 ambientColAttr;\n"
        "uniform lowp vec3 lightColAttr;\n"
        "uniform lowp vec3 lightPosAttr;\n"
        "uniform lowp vec3 viewPosAttr;\n"
    
        "varying highp vec2 v_texcoord;\n"
        "varying vec3 Normal;\n"
        "varying vec3 FragPos;\n"
    
        "void main() {\n"
        //漫反射
        "   vec3 norm = normalize(Normal);\n"
        "   vec3 lightDir = normalize(lightPosAttr - FragPos);\n"
        "   float ambientStrength = 0.1;\n"
        "   float diffuse = max(dot(norm, lightDir), 0.0);\n"
    
        //高光
        "   vec3 viewDir = normalize(viewPosAttr - FragPos);\n"
        "   vec3 reflecDir = reflect(-lightDir, norm);\n"
        "   float specularStrength = 0.5;\n"
        "   float specular = pow(max(dot(viewDir, reflecDir), 0.0), 64) * specularStrength;\n"
        "   gl_FragColor = vec4((ambientStrength + diffuse + specular) * lightColAttr * col, 1.0);\n"
        "}\n";
    

    获取 视点属性

    //视点属性
        m_viewPosAttr = m_program->uniformLocation("viewPosAttr");
    

    绘制时候设置视点

    //视点为摄像机位置
        m_program->setUniformValue(m_viewPosAttr, camera);
    

    效果

    仔细看,有高光
    0_1526968253241_20180522_134903.gif

    源代码

    https://gitee.com/chen227/opengl_OpenGLFunctions7



  • @青山白云 纹理滤波的选择,可以让纹理放大或者缩小的时候避免失真。还有一个叫做Anisotropic的扩展,中文名是各向异性采样,是更高级也是更好看的一个。


Log in to reply
 

走马观花

最近的回复

  • C

    Qt for MCU需要商业授权的

    read more
  • Qt for MCUs

    搭建Qt for MCUs PC端开发环境。qt for mcus提供了一个完整的图形框架和工具包,包含了在MCUs上设计、开发和部署gui所需的一切。它允许您在裸机或实时操作系统上运行应用程序。

    先决条件

    开发主机环境支持仅限于Windows 10

    MSVC compiler v19.16 (Visual Studio 2017 15.9.9 or newer) x64

    CMake v3.13 or newer (you can install it using the Qt Online installer) x64

    使用Qt联机安装程序安装Qt for MCUs,该安装程序可通过Qt帐户下载

    安装Qt 5.14和Qt Creator 4.11 or higher

    安装链接

    › Qt: https://account.qt.io/downloads
    › CMake: https://cmake.org/download/
    › Python 2.7 32-bit: https://www.python.org/downloads/release/python-2716/
    › Arm GCC: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnutoolchain/gnu-rm/downloads
    › J-Link Software Pack: https://www.segger.com/downloads/jlink/JLink_Windows.exe
    › J-Link OpenSDA Firmware: https://www.segger.com/downloads/jlink/OpenSDA_MIMXRT1050-EVKHyperflash
    › STM32CubeProgrammer: https://www.st.com/en/development-tools/stm32cubeprog.html
    › STM32 ST-LINK Utility: https://www.st.com/en/development-tools/stsw-link004.html​​​​​​​

    Qt Creator设置 启用Qt Creator插件 选择“帮助>关于插件”,然后从列表中选择“MCU支持(实验性)”插件,重新启动Qt Creator以应用更改
    替代文字 为MCU创建Qt工具包

    选择工具>选项>设备>MCU

    选择Qt for MCUs-Desktop 32bpp作为目标

    如果尚未设置,请提供Qt for MCUs安装目录的路径。

    单击Apply应用。

    替代文字

    替代文字
    替代文字

    注意:

    编译器要选X64,Qt版本要选64bit,CMake Tool选x64

    打开恒温器项目demo

    选择文件>打开文件或项目。。。

    打开CMakefiles.txt文件来自thermo文件夹的文件。

    选择Qt作为MCU-桌面32bpp套件。

    单击“配置项目”以完成。

    替代文字

    问题

    开发主机环境支持仅限于Windows 10

    C++编译失败,文本大字体.pixelSize.

    文本类型无法正确呈现需要复杂文本布局的unicode序列。对复杂文本使用StaticText

    read more
  • H

    hi 有问题请教你,方便加个联系方式吗

    read more
  • boost.asio是一个很棒的网络库,这回儿我也开始系统地学习起来了。想想当年接触boost,也有八年多了。这次开始接触boost,觉得既熟悉又陌生。熟悉的是小写字母+下划线的命名方式、晦涩的模板、很慢的编译速度以及较大的程序体积,陌生的是asio的各种概念:io服务、接收器、套接字等等:我之前对网络编程不是非常了解。

    于是根据我的理解,参考《Boost.Asio C++网络编程》实现了这样一个简单的客户端和服务端通信的例子,例子非常简单,还不完善,但是幸运的是,可以在本机上互通了。
    下面是客户端的代码:

    #include <iostream> #include <boost/asio.hpp> #include <boost/proto/detail/ignore_unused.hpp> using namespace std; using namespace boost::asio; using namespace boost::system; using namespace boost::proto::detail;// 提供ignore_unused方法 void writeHandler( const boost::system::error_code& ec, size_t bytesTransferred ) { if ( ec ) { cout << "Write data error, code: " << ec.value( ) << "transferred: " << bytesTransferred << endl; } else { cout << "OK! " << bytesTransferred << "bytes written. " << endl; } } int main(int argc, char *argv[]) { ignore_unused( argc ); ignore_unused( argv ); io_service service; ip::tcp::socket sock( service ); ip::tcp::endpoint ep( ip::address::from_string( "127.0.0.1" ), 6545 ); boost::system::error_code ec; sock.connect( ep, ec ); if ( ec ) { cout << "Connect error, code: " << ec.value( ) << ", We will exit." << endl; return ec.value( ); } else { char buf[1024] = "Hello world!"; sock.async_write_some( buffer( buf ), writeHandler ); sock.close( ); } return service.run( ); }

    下面是服务端的代码:

    #include <iostream> #include <boost/asio.hpp> #include <boost/proto/detail/ignore_unused.hpp> using namespace std; using namespace boost::asio; using namespace boost::system; using namespace boost::proto::detail;// 提供ignore_unused方法 void acceptHandle( const boost::system::error_code& code ) { cout << "Accepted." << endl; } int main(int argc, char *argv[]) { ignore_unused( argc ); ignore_unused( argv ); io_service service; ip::tcp::endpoint ep( ip::address::from_string( "127.0.0.1" ), 6545 ); boost::system::error_code ec; ip::tcp::socket sock( service ); ip::tcp::acceptor acceptor( service, ep ); acceptor.async_accept( sock, acceptHandle ); if ( ec ) { cout << "There is an error in server. code: " << ec.value( ) << endl; } return service.run( );// 阻塞运行 }

    运行结果是这样的:
    78448d7b-b3ae-42fc-9e2e-4dd2fbdac2c2-image.png

    我对boost.asio中几个概念的理解:

    io_service,这就是一个类似事件循环的东西,它为io设备提供服务,故名。不管是套接字、文件还是串口设备,都要使用它的服务。它的run()函数相当于启动了一个事件循环。一旦有消息了,即进行响应。这也是实现异步编程的重要基础。 socket,这个类则是套接字,可以处理TCP或者是UDP请求。有同步以及异步的处理方式,也有带异常以及不带异常的处理方式。 acceptor,接收器,仅仅是服务端使用。相当于其余框架中的listener,作接收用的。

    比较浅显,如果有不当之处,敬请指正。

    read more

关注我们

微博
QQ群