博客
关于我
NeHe OpenGL教程 第四十四课:3D光晕
阅读量:795 次
发布时间:2023-02-14

本文共 2759 字,大约阅读时间需要 9 分钟。

NeHe OpenGL教程第四十四课:3D光晕

3D光晕效果实现

当镜头对准光源时,我们会观察到强烈的光晕效果。通过简单的数学计算和纹理贴图,可以很好地模拟这种效果。本文将介绍如何在OpenGL程序中实现这一效果。

实现思路

为了实现光晕效果,我们需要以下几个关键步骤:

  • 获取视景体数据:首先,我们需要了解当前视点的位置和方向。这可以通过计算视图矩阵和投影矩阵来实现。
  • 光源检测:检测光源是否在视点的可见范围内。这可以通过点是否在视景体内来判断。
  • 光晕渲染:当光源可见时,我们需要绘制光晕效果。这通常涉及到多个纹理贴图的拼接,模拟光线的扩散和折射效果。
  • 下面,我们将详细介绍光源检测和光晕渲染的实现方法。


    光源检测

    为了判断光源是否在视点的可见范围内,我们需要以下函数:

  • 获取视景体的平面方程:通过计算投影矩阵和模型视图矩阵的乘积,得到剪切矩阵。剪切矩阵可以用来确定点是否在视景体内。
  • 点是否在视景体内:通过将点坐标代入剪切矩阵方程,判断点是否满足视景体的条件。
  • 以下是光源检测的关键代码片段:

    BOOL glCamera::PointInFrustum(glPoint p) {    int i;    for(i = 0; i < 6; i++) {        if(m_Frustum[i][0] * p.x + m_Frustum[i][1] * p.y +            m_Frustum[i][2] * p.z + m_Frustum[i][3] <= 0) {            return FALSE;        }    }    return TRUE;}

    光晕渲染

    当光源可见时,我们需要绘制光晕效果。光晕的绘制通常包括以下步骤:

  • 计算光源到摄像头的距离:通过光源位置和视点位置的向量,计算光源与视点之间的距离。
  • 确定光晕的绘制位置:根据光源到视点的距离,计算光晕的绘制位置。通常,我们会绘制多个光晕,模拟光线的扩散效果。
  • 使用纹理贴图:通过不同的纹理贴图(如Halo、Glow、BigGlow、Streaks等),绘制多种光晕效果。
  • 以下是光晕渲染的关键代码片段:

    void glCamera::RenderLensFlare() {    GLfloat Length = 0.0f;    if(SphereInFrustum(m_LightSourcePos, 1.0f) == TRUE) {        // 计算光源到摄像头的距离        vLightSourceToCamera = m_Position - m_LightSourcePos;        Length = vLightSourceToCamera.Magnitude();        // 绘制光晕        RenderBigGlow(0.60f, 0.60f, 0.8f, 1.0f, m_LightSourcePos, 16.0f);        RenderStreaks(0.60f, 0.60f, 0.8f, 1.0f, m_LightSourcePos, 16.0f);        RenderGlow(0.8f, 0.8f, 1.0f, 0.5f, m_LightSourcePos, 3.5f);        // ... 其他光晕绘制函数 ...    }    glDisable(GL_BLEND);    glEnable(GL_DEPTH_TEST);    glDisable(GL_TEXTURE_2D);}

    纹理贴图的使用

    为了实现光晕效果,我们需要以下四种纹理贴图:

  • Halo形光晕:用于模拟光线的圆形扩散效果。
  • Glow形光晕:用于模拟光线的流动效果。
  • BigGlow形光晕:用于模拟光线的扩散效果。
  • Streaks形光晕:用于模拟光线的折射效果。
  • 以下是绘制Halo形光晕的关键代码片段:

    void glCamera::RenderHalo(GLfloat r, GLfloat g, GLfloat b, GLfloat a, glPoint p, GLfloat scale) {    glPoint q[4];    q[0].x = (p.x - scale);    q[0].y = (p.y - scale);    q[1].x = (p.x - scale);    q[1].y = (p.y + scale);    q[2].x = (p.x + scale);    q[2].y = (p.y - scale);    q[3].x = (p.x + scale);    q[3].y = (p.y + scale);    glPushMatrix();    glTranslatef(p.x, p.y, p.z);    glRotatef(-m_HeadingDegrees, 0.0f, 1.0f, 0.0f);    glRotatef(-m_PitchDegrees, 1.0f, 0.0f, 0.0f);    glBindTexture(GL_TEXTURE_2D, m_HaloTexture);    glColor4f(r, g, b, a);    glBegin(GL_TRIANGLE_STRIP);    glTexCoord2f(0.0f, 0.0f);    glVertex2f(q[0].x, q[0].y);    glTexCoord2f(0.0f, 1.0f);    glVertex2f(q[1].x, q[1].y);    glTexCoord2f(1.0f, 0.0f);    glVertex2f(q[2].x, q[2].y);    glTexCoord2f(1.0f, 1.0f);    glVertex2f(q[3].x, q[3].y);    glEnd();    glPopMatrix();}

    整体实现流程

  • 初始化:在程序开始时,初始化光源的位置和方向。
  • 更新视景体:通过计算投影矩阵和模型视图矩阵,更新视景体的平面方程。
  • 光源检测:判断光源是否在视点的可见范围内。
  • 光晕渲染:如果光源可见,绘制光晕效果。通过多个纹理贴图,模拟光线的扩散和折射效果。
  • 渲染完成:绘制完成后,恢复默认的GL状态。

  • 通过以上方法,我们可以在OpenGL程序中实现逼真的3D光晕效果。光晕的实现主要依赖于视图矩阵、投影矩阵和纹理贴图的结合。通过合理设计和优化光晕绘制函数,可以实现多种不同风格的光晕效果,丰富3D场景的视觉效果。

    转载地址:http://ffcfk.baihongyu.com/

    你可能感兴趣的文章
    Netty工作笔记0062---WebSocket长连接开发
    查看>>
    Netty工作笔记0063---WebSocket长连接开发2
    查看>>
    vue样式穿透 ::v-deep的具体使用
    查看>>
    Netty工作笔记0065---WebSocket长连接开发4
    查看>>
    Netty工作笔记0066---Netty核心模块内容梳理
    查看>>
    Vue基本使用---vue工作笔记0002
    查看>>
    Netty工作笔记0068---Protobuf机制简述
    查看>>
    Netty工作笔记0069---Protobuf使用案例
    查看>>
    Netty工作笔记0070---Protobuf使用案例Codec使用
    查看>>
    Netty工作笔记0071---Protobuf传输多种类型
    查看>>
    Netty工作笔记0072---Protobuf内容小结
    查看>>
    Netty工作笔记0073---Neety的出站和入站机制
    查看>>
    Netty工作笔记0074---handler链调用机制实例1
    查看>>
    Netty工作笔记0075---handler链调用机制实例1
    查看>>
    Netty工作笔记0076---handler链调用机制实例3
    查看>>
    Netty工作笔记0077---handler链调用机制实例4
    查看>>
    Netty工作笔记0078---Netty其他常用编解码器
    查看>>
    Netty工作笔记0079---Log4j整合到Netty
    查看>>
    Netty工作笔记0080---编解码器和处理器链梳理
    查看>>
    Netty工作笔记0081---编解码器和处理器链梳理
    查看>>