计算机图形学:实验三 光照与阴影

一、程序功能设计

设置了一个3D渲染场景,支持通过键盘和鼠标控制交互,能够动态调整光源位置、物体材质参数等,具有光照、阴影和材质效果的场景渲染。 

OpenGL物体渲染和设置

  1. 创建3D物体:代码中通过 openGLObject 结构体表示一个3D物体,包含了顶点数据、着色器程序以及与物体的变换矩阵相关的信息。每个物体可以有多个顶点(如位置、颜色、法向量等),以及对应的材质、光源、阴影等属性。
  2. 绑定物体数据到OpenGL:bindObjectAndData 函数用于将物体的顶点、颜色、法线等数据传输给OpenGL。该函数使用 glGenVertexArrays 和 glGenBuffers 创建 VAO 和 VBO,并设置着色器的顶点属性(如位置、颜色、法向量等)。它还配置了物体的变换矩阵,使得物体可以在3D空间中进行旋转、缩放等操作。

 光照和材质管理

  1. 光源和材质传递到着色器:bindLightAndMaterial 函数将物体的光源信息(如环境光、漫反射光、镜面反射光)和材质信息(如物体的环境光、漫反射、镜面反射强度)传递到着色器中。通过设置光源的位置、颜色等,影响物体的渲染效果。每个物体在渲染时都可以拥有不同的材质参数,例如镜面反射的高光系数。
  2. 计算相机位置:该函数还将相机的位置传递给着色器,影响光照计算中的视角部分,从而可以实现如镜面反射等效果。

 渲染和变换矩阵处理

  1. 视图矩阵和投影矩阵:在 display 函数中,程序首先计算视图矩阵和投影矩阵,以确定摄像机的位置和视野范围。这些矩阵帮助实现3D物体的透视效果,并确定物体在屏幕上的位置。
  2. 变换操作:物体的变换(如旋转、缩放、平移)通过变换矩阵传递给着色器。着色器程序会使用这些变换矩阵来渲染物体的位置和方向。

 光照和阴影效果

  1. 动态调整光源:通过键盘或鼠标操作,用户可以动态调整光源的位置,从而影响光照效果。这意味着场景中的物体会随光源的移动而产生不同的阴影和光照效果。
  2. 阴影计算:在 display 函数中,还计算并渲染了光源的投影效果。通过光源与物体的关系,程序生成阴影效果,创建更加真实的视觉效果。

 交互功能

  1. 键盘交互:通过检测不同的按键和操作(按下、按住等),可以控制物体的颜色、材质、位置等。按键包括功能键(如 ESC、H、Q)和数字键(如 1、2、3 等),用于调整 ambient、diffuse 和 specular 的分量(RGB)以及物体的平移(通过 LEFT、RIGHT、UP、DOWN 控制)。
  2. 鼠标交互:鼠标左键按下时,可以获取当前鼠标的坐标,并根据这些坐标将光源的位置调整到与鼠标位置对应的屏幕坐标范围内。x 和 y 坐标转换为 -1 到 1 之间的值,并根据这个值设置光源位置。

 二、程序代码实现

绘制场景

使用一个灰色平面来对物体的黑色阴影进行呈现。

添加平面呈现阴影

  • 添加一个TriMesh*类型的plane:plane用作计算和展示物体阴影的投影平面。光源投射到该平面上的阴影通过投影矩阵计算,并渲染在平面上,同时plane通常位于场景的底部(如y=0平面)以便显示物体的阴影效果。
  • 添加一个openGLObject类型的plane_object:plane_object 可以应用平移、旋转、缩放等变换操作来调整平面在场景中的位置和方向。它与 plane紧密配合,用于正确呈现物体的阴影效果。

在init中生成平面

  • 生成平面并设置其变换:调用 plane->generateSquare() 方法生成一个平面(Square)。配置平面的位置(setTranslation)、旋转(setRotation)和缩放(setScale)。设置平面材质的环境光、漫反射、镜面反射和高光系数(为一个灰色平面)。
  • 将平面的顶点数据传递给着色器:使用 bindObjectAndData() 将 plane 对象的数据绑定到 plane_object,并传递给着色器程序。

在display中渲染平面

  • 使用 glBindVertexArray() 和 glUseProgram() 绑定 plane_object 对象的顶点数组对象(VAO)和着色器程序。
  • 调用 bindLightAndMaterial() 将光源和物体材质的数据传递给着色器。
  • 设置平面的变换矩阵 modelMatrix 并传递给着色器。
  • 设置 isShadow 参数为 0,表示平面正常渲染。
  • 最后绘制平面。

设置相机

设置相机并添加交互,实现从不同位置/角度、以正交或透视投影方式观察场景。

视图矩阵

getViewMatrix 方法通过调用 lookAt() 方法返回当前相机的视图矩阵。

lookAt() 方法使用了glm::lookAt()来根据相机的位置(eye)、目标点(at)和上方向(up)计算视图矩阵。通过 eye、at 和 up 向量来指定相机的方向和位置。

投影矩阵

getProjectionMatrix 方法根据isOrtho标志来选择不同的投影类型:

  1. 如果是正交投影(isOrtho为真),则调用 ortho() 方法。
  2. 如果是透视投影(isOrtho为假),则调用 perspective() 方法。

正交投影和透视投影的实现

  • ortho:实现正交投影矩阵。正交投影不考虑远近距离,因此物体的大小在视野中保持不变。

  • perspective:实现透视投影矩阵。透视投影模拟了相机视野中的深度感知,远离视点的物体看起来更小。

更新相机位置和视角

updateCamera:更新相机的位置和视角。通过rotateAngle和upAngle来调整相机的旋转角度,radius来控制相机与目标点(at)的距离。

  1. rotateAngle 控制相机绕目标点的水平旋转(水平视角)。
  2. upAngle 控制相机的俯仰角度(垂直视角)。
  3. radius 控制相机与目标点的距离。

键盘事件处理

keyboard:根据键盘输入来改变相机的状态(例如旋转、缩放、切换投影方式等)。

  1. U键:控制相机绕目标点的旋转(顺时针/逆时针)。
  2. I键:控制相机的俯仰角度(上下调整)。
  3. O键:控制相机与目标点的距离(放大/缩小)。
  4. P键:切换投影方式(透视/正交)。
  5. 空格键:将相机参数重置为默认值。

添加光照和材质效果

在init中设置光源参数

创建并配置光源 light 的位置和光照参数(环境光、漫反射、镜面反射),设置光源在三维空间中的位置 (0.0, 0.0, 2.0)。

在init中设置模型

  • 设置物体的变换:mesh(物体)对象的平移、旋转和缩放变换:平移设置为 (0.0, 0.0, 1.0),即物体在z轴上偏移。旋转和缩放设置为默认值 (0.0, 0.0, 0.0) 和 (1.0, 1.0, 1.0)。在这里需要注意的是,如果物体与平面太贴近无法正确观察阴影时,可以调整setTranslation的第三个参数来改变物体和平面的垂直距离,更好地观察阴影。
  • 设置物体的材质:配置 mesh 对象的环境光、漫反射、镜面反射和高光系数。
  • 绑定物体的顶点数据到着色器:使用 bindObjectAndData() 函数将 mesh 对象的数据传递给着色器程序。

在display中渲染模型

  • 使用 glBindVertexArray() 和 glUseProgram() 绑定 mesh_object 对象的顶点数组对象(VAO)和着色器程序。
  • 调用 bindLightAndMaterial() 将光源和物体材质的数据传递给着色器。
  • 创建物体的变换矩阵 modelMatrix 并将其传递给着色器,使用 glUniformMatrix4fv() 设置物体的变换矩阵、视图矩阵和投影矩阵。
  • 使用 glUniform1i() 设置着色器的 isShadow 参数为 0,表示物体不是阴影。
  • 绘制物体的三角形顶点。

添加阴影效果

光源的投影矩阵计算

getShadowProjectionMatrix()计算一个阴影投影矩阵,用于将光源的位置投影到一个平面上,通常是在 Y=0 平面上。

  • 获取光源的位置:首先,通过 getModelMatrix() 获取光源的模型矩阵。光源的位置存储在 translation 中。使用 modelMatrix * glm::vec4(this->translation, 1.0) 计算光源在世界坐标系中的位置,结果存储在 light_position 中。
  • 提取光源的坐标: lx, ly, lz 分别提取光源的世界坐标(light_position[0] 是 x 坐标,light_position[1] 是 y 坐标,light_position[2] 是 z 坐标)。
  • 构建阴影投影矩阵:构建一个矩阵用于将物体投影到Y=0平面上。具体来说,该矩阵通过把物体的 z 坐标值映射到 Y=0 平面,将物体位置与光源方向的关系映射出来。

在display中添加阴影

  • 计算阴影投影矩阵:将光源的投影矩阵getShadowProjectionMatrix()与物体的 modelMatrix 相乘,得到阴影的变换矩阵。
  • 更新变换矩阵并将 shadowLocation 设置为 1,表示这是阴影绘制。
  • 绘制阴影的三角形(GL_TRIANGLE_FAN)。

交互控制光源位置并更新阴影

mouse_button_callback 函数是处理鼠标按键事件的回调函数,主要功能是当鼠标左键按下时,获取鼠标的位置并将其映射到标准化设备坐标系,然后更新光源的位置。

  • glfwGetCursorPos 用于获取当前鼠标在窗口中的像素位置。
  • half_winx 和 half_winy 是窗口宽高的一半,用于将屏幕坐标转换成标准化坐标(NDC)。标准化坐标系的范围是 [-1, 1],其中 (0, 0) 是屏幕中心。
  • lx 和 ly 将鼠标的屏幕坐标(像素)转换为标准化坐标,lx 和 ly 的值会在 [-1, 1] 范围内变化。这里需要注意的是ly 需要做反转处理(HEIGHT - y),因为在屏幕坐标系中,y 坐标的原点通常位于左上角,而标准化坐标系中的 y 原点通常在中心,且 y 坐标值是递增的
  • 光源的位置通过 light->getTranslation() 获取,并通过 light->setTranslation() 设置新的位置。这里只更新光源的 x 和 y 坐标,z 坐标保持不变。

三、程序运行结果

运行程序初始界面

调整光源位置

点击鼠标左键,改变光源位置,观察阴影的形成。效果图如下图所示。

观察不同物体形成的阴影

分别点击A、W、S、Q键,改变物体模型,观察不同物体的阴影形成。

调整物体的材质

点击0-9改变物体的材质:

  1. (shift) + 1/2/3:改变环境光的参数。
  2. (shift) + 4/5/6:改变漫反射的参数。
  3. (shift) + 7/8/9:改变镜面反射的参数。
  4. (shift) + 0:改变光泽度参数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/959175.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

22_解析XML配置文件_List列表

解析XML文件 需要先 1.【加载XML文件】 而 【加载XML】文件有两种方式 【第一种 —— 使用Unity资源系统加载文件】 TextAsset xml Resources.Load<TextAsset>(filePath); XmlDocument doc new XmlDocument(); doc.LoadXml(xml.text); 【第二种 —— 在C#文件IO…

JavaScript 数组的map和join方法、延迟函数、location对象、本地存储、正则表达式、箭头函数

数组处理方法 map方法 map方法的作用是遍历数组所有元素&#xff0c;然后执行处理操作&#xff0c;最后返回一个新的数组 语法格式&#xff1a;新数组 原来数组.map(function(ele,index){ ele是数组元素&#xff0c;index是下标 执行完操作之后使用return 返回一个…

物联网网关Web服务器--CGI开发实例BMI计算

本例子通一个计算体重指数的程序来演示Web服务器CGI开发。 硬件环境&#xff1a;飞腾派开发板&#xff08;国产E2000处理器&#xff09; 软件环境&#xff1a;飞腾派OS&#xff08;Phytium Pi OS&#xff09; 硬件平台参考另一篇博客&#xff1a;国产化ARM平台-飞腾派开发板…

【论文+源码】diffuseq使用扩散模型和diffuseq-v2的序列文本生成序列,并且桥接离散和连续的文本空间,用于加速SEQ2SEQ扩散模型。

这篇论文介绍了一种名为DIFFUSEQ的新型扩散模型&#xff0c;专门针对序列到序列&#xff08;SEQ2SEQ&#xff09;文本生成任务进行设计。尽管扩散模型在视觉和音频等连续信号领域取得了成功&#xff0c;但在自然语言处理特别是条件生成方面的适应仍然未被广泛探索。通过广泛的评…

2024年度总结:技术探索与个人成长的交织

文章目录 前言年度创作回顾&#xff1a;技术深耕与分享数据库技术&#xff1a;MySQL 与 MyBatisJava 及相关技术栈计算机网络&#xff1a;构建网络知识体系思维方式的转变&#xff1a;构建技术知识体系的桥梁 项目实践&#xff1a;人工智能与智慧医疗的碰撞生活与博客的融合与平…

如何使用LDAP-Monitoring-Watchdog实时监控 LDAP 目录中记录修改

关于LDAP-Monitoring-Watchdog LDAP-Monitoring-Watchdog是一种用于实时监控 LDAP 目录中记录更改的工具&#xff0c;该工具能够与Linux兼容&#xff0c;用于检测目录变化&#xff0c;为管理员和安全研究人员提供对添加、修改和删除的可见性。 该工具提供了一种机制来跟踪和可…

Cloudflare通过代理服务器绕过 CORS 限制:原理、实现场景解析

第一部分&#xff1a;问题背景 1.1 错误现象复现 // 浏览器控制台报错示例 Access to fetch at https://chat.qwenlm.ai/api/v1/files/ from origin https://ocr.doublefenzhuan.me has been blocked by CORS policy: Response to preflight request doesnt pass access con…

深入理解动态规划(dp)--(提前要对dfs有了解)

前言&#xff1a;对于动态规划&#xff1a;该算法思维是在dfs基础上演化发展来的&#xff0c;所以我不想讲的是看到一个题怎样直接用动态规划来解决&#xff0c;而是说先用dfs搜索&#xff0c;一步步优化&#xff0c;这个过程叫做动态规划。&#xff08;该文章教你怎样一步步的…

速通Docker === Docker Compose

目录 Docker Compose 简介 Docker Compose 常用命令 使用 Docker Compose 启动 WordPress 普通启动方式&#xff08;使用 Docker 命令&#xff09; 使用 Docker Compose 启动 Docker Compose 的特性 Docker Compose 简介 Docker Compose 是一个用于定义和运行多容器 Dock…

知识体系_统计学_03_描述性统计_概括性度量

对数据的概括性度量可从三方面进行测量和描述&#xff1a;集中趋势、离中趋势和分布形态。 集中趋势&#xff0c;反映的是各数据向其中心值靠拢或聚集的程度&#xff1b;离中趋势&#xff0c;反映的是数据的离散程度&#xff0c;远离中心值的趋势&#xff1b;分布形态反映的是…

HackTheBox靶机:Sightless;NodeJS模板注入漏洞,盲XSS跨站脚本攻击漏洞实战

HackTheBox靶机&#xff1a;Sightless 渗透过程1. 信息收集常规探测深入分析 2. 漏洞利用&#xff08;CVE-2022-0944&#xff09;3. 从Docker中提权4. 信息收集&#xff08;michael用户&#xff09;5. 漏洞利用 Froxlor6. 解密Keepass文件 漏洞分析SQLPad CVE-2022-0944 靶机介…

Qt Creator 15.0.0如何更换主题和字体

1.打开Qt Creator 15.0.0 (Community)&#xff0c; 2.点击编辑栏3.点击Preferences... 4.修改主题&#xff0c;点击环境&#xff0c;修改Theme:栏 5.修改字体大小&#xff0c;点击文本编辑器&#xff0c;修改字号栏。&#xff0c;修改Theme:栏

深度强化学习:PPO

深度强化学习算法&#xff1a;PPO 1. Importance Sampling 先说一下什么是采样&#xff1a;对于一个随机变量&#xff0c;我们通常用概率密度函数来描述该变量的概率分布特性。具体来说&#xff0c;给定随机变量的一个取值&#xff0c;可以根据概率密度函数来计算该值对应的概…

亚博microros小车-原生ubuntu支持系列:11手指控制与手势识别

识别框架还是沿用之前的了MediaPipe Hand。 背景知识不摘重复&#xff0c;参见之前的&#xff1a;亚博microros小车-原生ubuntu支持系列&#xff1a;10-画笔-CSDN博客 手指控制 src/yahboom_esp32_mediapipe/yahboom_esp32_mediapipe/目录下新建文件10_HandCtrl.py&#xff…

OpenCV:在图像中添加高斯噪声、胡椒噪声

目录 在图像中添加高斯噪声 高斯噪声的特性 添加高斯噪声的实现 给图像添加胡椒噪声 实现胡椒噪声的步骤 相关阅读 OpenCV&#xff1a;图像处理中的低通滤波-CSDN博客 OpenCV&#xff1a;高通滤波之索贝尔、沙尔和拉普拉斯-CSDN博客 OpenCV&#xff1a;图像滤波、卷积与…

【模拟集成电路】锁相环(phase-locked loops,PLL)设计_环形振荡器相关(简)

0. 前言 未来将会不定时更新PLL相关的文章&#xff0c;主要目的是作为个人的学习笔记&#xff0c;关于锁相环的基础&#xff0c;可以参考《模拟CMOS集成电路设计_Behzad Razavi》后面几章的内容&#xff0c;下面的文章主要参考书籍是的英文书籍《DESIGN OF CMOS PHASE‑LOCKED …

Qt简单迷宫游戏

目录 你将学到你将准备你将改变你将设计你将编程开始界面游玩界面胜利界面其它bug修复 你可扩展下一篇博客要说的东西 你将学到 Qt中QKeySequence对象的基本创建Qt中QShortcut对象的基本应用Qt中QSoundEffect对象的基本应用 你将准备 在开始制作Qt简单迷宫游戏之前&#xff…

SSM电子商城系统

&#x1f345;点赞收藏关注 → 添加文档最下方联系方式咨询本源代码、数据库&#x1f345; 本人在Java毕业设计领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目希望你能有所收获&#xff0c;少走一些弯路。&#x1f345;关注我不迷路&#x1f345; 项目视频 电…

springboot3 集成 knife4j(接口文档)

提示&#xff1a;文章是集成 knife4j&#xff0c;而非 swagger2 或者 swagger3&#xff0c;效果如图 文章目录 前言一、添加依赖二、如何集成1.配置文件2.注解部分1.Tag2.Operation3.Parameter4.Schema 3.使用 总结 前言 提示&#xff1a;&#xff1a;大家在开发阶段&#xff…

亚博microros小车-原生ubuntu支持系列:7-脸部检测

背景知识 官网介绍&#xff1a; Face Mesh - mediapipe mpFaceMesh.FaceMesh() 类的参数有&#xff1a;self.staticMode, self.maxFaces, self.minDetectionCon, self.minTrackCon staticMode:是否将每帧图像作为静态图像处理。如果为 True&#xff0c;每帧都会进行人脸检测…