OpenGL实现3D游戏编程【连载3】——3D空间模型光照初步

news/2024/9/17 19:03:31/ 标签: 3d, 游戏, c++, 开发语言, 游戏程序, 游戏策划

1、本节实现的内容

上一节课,我们建立了简单的坐标系,同时也显示了一个正方体,但正方体的颜色为纯红色,好像一个平面物体一样,我们这节课就可以加一些光照,并创建更多的模型,使这些物体变得更加立体一些。更多详见https://blog.csdn.net/zhooyu主页内容。

在这里插入图片描述

2、光照的认识

在OpenGL中光的种类大致可以分为平行光源、点光源和聚光灯光源三种。

2.1、平行光

从他们的名字也很好理解,平行光是从远方照射过来的光,有点类似咱们现实生活中,太阳从远处照过来的光,可以简单的理解为太阳光的每一条光线都是平行照射过来的。平行光最主要的特点,就是在一个场景中多个物体,平行光折射他们的角度基本保持一致,光照面的方向也就一致。

3dd86a4c169dc8c8aa313dfe64.png#pic_center" alt="在这里插入图片描述" />

2.2、点光源

点光源,有点类似于现实生活中的蜡烛🕯,它照射出来的是散射的光,在一个场景中的多个物体,我的位置不同,照射的光面角度也不同,而且会根据与蜡烛的远近距离不同,光线照射的明暗程度也不一样。类似的还有山洞中的火把的效果,人物在黑夜里出行的时候,随着伙伴位置的不停改变,正为物体的光照面也会不停的发生改变,同时火把只能照射到人物周围的物体,离人物距离越近光照效果就越强,离人物距离越远光照强度就越差。

在这里插入图片描述

2.3、聚光灯

聚光灯有点类似于我们现实生活中的手电筒,手电筒照出去的是一个范围光,光照出去只能照到一个大致圆环范围内的物体,而且手电筒的光是有方向的,人们可以不断改变手电筒光照射的方向。同时我们手电筒可以调整光圈的大小,像我们旋转手电筒头,可以让光圈放大或者缩小。

在这里插入图片描述

3、简单平行光的设置

首先我们可以先加一个平行光,当然,这个光可以有不同的颜色,我们这里暂时模拟太阳光,让它产生一个简单白色光。这里要注意一点,GL_POSITION属性的值(x,y,z,w),w为零表示无限远,x/w,y/w,z/w分别表示光源位置。同时,我们这里使用的是GL_LIGHT0号光源,系统默认定义了GL_LIGHT0至GL_LIGHT7号光源供用户使用。


//设置并打开自定义光源void	OpenLightExample()
{//GL_POSITION属性的值(x,y,z,w),w为零表示无限远,x/w,y/w,z/w表示光源位置GLfloat user_light_position[]={1.0f,1.0f,-1.0f,0.0f};//GL_AMBIENT光源发出的光,经过非常多次反射,遗留在整个光照环境中的强度(RGBA)GLfloat user_light_ambient[]={0.2f,0.2f,0.2f,1.0f};//GL_DIFFUSE光源发出的光,照射到粗糙表面时,经过漫反射所得到的光强度(RGBA)GLfloat user_light_diffuse[]={1.0f,1.0f,1.0f,1.0f};//GL_DIFFUSE光源发出的光,照射到光滑表面时,经过镜面反射所得到的光强度(RGBA)GLfloat user_light_specular[]={1.0f,1.0f,1.0f,1.0f};//加载设置glLightfv(GL_LIGHT0,GL_POSITION,user_light_position);glLightfv(GL_LIGHT0,GL_AMBIENT,user_light_ambient);glLightfv(GL_LIGHT0,GL_DIFFUSE,user_light_diffuse);glLightfv(GL_LIGHT0,GL_SPECULAR,user_light_specular);//开启光源和光照处理功能glEnable(GL_LIGHT0);glEnable(GL_LIGHTING);}

//关闭光源和光照处理功能void	CloseLightExample()
{glDisable(GL_LIGHT0);glDisable(GL_LIGHTING);}

4、添加平行光

在定义了以上光线操作函数后,我们就可以在任何需要添加光照的地方添加以下代码,由于Opengl是状态机,因此,光照打开后会一直生效,直到关闭相应的光源为止。

//打开自定义平行光OpenLightExample();//在此显示的物体将会收到光照影响......//关闭自定义平行光源CloseLightExample();

当我们添加我们太阳光后,发现我们的立方体并没有产生背光照的效果,我们的立体模型都变成了灰白色,这主要是我们没有设定物体的材质。就好比我们告诉计算机现在有了光线,但是没有告诉计算机你现在显示的立方体对光照的效果怎样,就是说你的立方体是一个金属反光材质,还是一个毛绒玩具的不反光材质?如果反光材质,它的反光程度有多少,是闪眼睛的那种反光,还是只有轻微反光的效果。

在这里插入图片描述

5、材质问题简单的解决办法

我们这里鉴于让大家能很容易的上手,就先暂时不研究具体的材质问题(嗯,复杂的材质设置会给我们带来更多的光照效果,功能非常强大,我们后期再根据需要进行阐述),我们这里就力求用最简单的语言,最容易理解的方式,去了解整个游戏程序设计的思路,需要更多还可以了解我的主页https://blog.csdn.net/zhooyu。

			//默认打开颜色材质glEnable(GL_COLOR_MATERIAL);//添加显示3D场景物体,如立方体等......//默认打开颜色材质glDisable(GL_COLOR_MATERIAL);

至此,我们的立方体显示出了应该有的光照效果,立方体各个平面之间产生了比较分明的棱线,圆也出现了渐变的关照效果,特别是正二十面体的不同面效果更漂亮。当然,我们这里并没有介绍法线的概念,光照和法线离不开,但是系统自带的以上模型已经自带法线设置,我们后期遇到具体问题在描述法线的设置和作用。

在这里插入图片描述

我们已经多添加了几个系统自带图形查看光照效果,包括一个圆球体、正二十面体和环状体,这样光照效果就好了很多。以下补充其他立体模型的生成代码:

	//显示球体glPushMatrix();glTranslatef(-5,5,0);glColor3f(0.0f,0.0f,1.0f);glutSolidSphere(2.0f,30.0f,30.0f);glPopMatrix();//显示圆环体glPushMatrix();glTranslatef(-3,2,5);glRotatef(90,1.0f,0.0f,0.0f);glColor3f(1.0f,0.0f,1.0f);glutSolidTorus(0.5f,1.0f,30.0f,30.0f);glPopMatrix();//显示二十面体glPushMatrix();glTranslatef(0,2,0);glColor3f(0.0f,0.6f,1.0f);glutSolidIcosahedron();glPopMatrix();

6、长方体地面的添加

我们显示了以上物体后,总是没有脚踏实地的,虽然现在有了三维的坐标参照,但是总感觉脚下悬空的。我们还是去创建一个地面,这样可以感觉心里踏实,这里由于没有系统自带的长方体,要自定义创建一个长方体。当然,我们现在加的只是一个感官上的地面,后期还要添加玩家在地面上的碰撞检查,我落在地面上,可以顺着地形的不同不断改变能力的高度,遇到障碍物我无法通过,如果遇到了峡谷,人物也可以自由落体势掉落到峡谷底部,但不会掉落无尽深渊的效果。更多详见https://blog.csdn.net/zhooyu主页内容。

//显示地面if(true){//长方体的八个顶点坐标int	vertices[8][4]={{-10,-1,-10},{-10,-1,+10},{+10,-1,+10},{+10,-1,-10},{-10,-5,-10},{-10,-5,+10},{+10,-5,+10},{+10,-5,-10},};//长方体六个面上顶点显示顺序int	indices[6][4]={{3,2,1,0},{0,1,5,4},{1,2,6,5},{2,3,7,6},{3,0,4,7},{4,5,6,7}};//逐个显示面长方体六个面for(int i=0;i<6;i++){//设置各个面的颜色if(i==0){glColor3f(0.0f,1.0f,0.0f);}else{glColor3f(0.8f,0.5f,0.0f);}//显示各个面glBegin(GL_QUADS);//显示各个顶点for(int j=0;j<4;j++){glVertex3f(vertices[indices[i][j]][0],vertices[indices[i][j]][1],vertices[indices[i][j]][2]);}glEnd();}}

这里我们需要显示一个底面积很大,高度不高的长方体,并放置到我们大致脚下的位置。我们先不用VAO和VBO的高级方式,这些高级操作方式可以更有效的操作GPU显存,对我们后期的性能非常重要,随后再详细说明,我们现在用最简单的方式显示。这更多的是为了方便大家查看。

在这里插入图片描述

我们的游戏画面稍微不那么单调,但是我们还需要添加后期的纹理,物体材质,加载上下起伏但平滑的地图模型,加载3D建模制作各种物体模型,操作界面的各种按键、窗口控件,来丰富我们的游戏内容。


http://www.ppmy.cn/news/1507326.html

相关文章

Flink 当下的趋势

Flink介绍 Apache Flink 是一个开源的分布式处理引擎&#xff0c;用于对有界和无界数据流进行有状态的计算。它在所有常见集群环境中运行&#xff0c;并能以内存速度和任意规模处理数据 。Flink 支持多种API&#xff0c;包括DataStream API、DataSet API、Table API & SQL…

对 Go 语言中循环屏障 CyclicBarrier 的理解

同步屏障 (Barrier) 是并发编程中的一种同步方法。对于一组 goroutine ,程序中的一个同步屏障意味着任何 goroutine 执行到此后都必须等待,直到所有的 goroutine 都达到此点才可继续执行下文。 Barrier 无论是翻译成屏障、障碍还是栅栏,都很形象,就是一道拦截坝,拦截一组对…

【nginx 第一篇章】认识一下 NGINX 服务器

一、简介 Nginx (engine x) 是一个高性能的 HTTP 和反向代理服务器&#xff0c;也是一个 IMAP/POP3/SMTP 代理服务器。由俄罗斯程序员 Igor Sysoev 开发&#xff0c;并在2004年首次公开发布。Nginx 以其高并发处理能力、低内存消耗、稳定性、丰富的功能集、简单的配置以及低学…

【系统分析师】-综合知识-软件工程与项目管理

1、按照成本性态分类&#xff0c;可以分为固定成本、变动成本和混合成本。 &#xff08;1&#xff09;固定成本。管理人员的工资、办公费、固定资产折旧费、员工培训费、广告费、员工培训费、技术开发经费、办公场地及机器设备的折旧费、房屋及设备租金、管理人员的工资等。 …

LeetCode-day35-3131. 找出与数组相加的整数 I

LeetCode-day35-3131. 找出与数组相加的整数 I 题目描述示例示例1&#xff1a;示例2&#xff1a;示例3&#xff1a; 思路代码 题目描述 给你两个长度相等的数组 nums1 和 nums2。 数组 nums1 中的每个元素都与变量 x 所表示的整数相加。如果 x 为负数&#xff0c;则表现为元素…

提高组织绩效的战略方法 —— 目标管理(MBO)

注&#xff1a;机翻&#xff0c;未校。 Management by Objectives (MBO) 目标管理&#xff08;MBO&#xff09; A strategic approach to enhance the performance of an organization 提高组织绩效的战略方法 Written by CFI Team What is Management by Objectives (MBO)?…

vscode下新建 virtualenv

1. 先进入一个目录&#xff0c;该目录下建议该虚拟环境。 2. virtualenv env-name 建议env环境 3. 激活env环境 D:\2024> .\autogen-env\Scripts\activate 4. 安装环境 (autogen-env) PS D:\2024> pip install pyautogen 5. 在vscode中选择python interpreter 6. 退…

sql注入CMSeasy

一&#xff0c;实验环境 MySQL5.7.26及以上版本 PHP 5.6.9及以上版本 Apache2.4.39 Vscode phpstudy 二&#xff0c;实验步骤 代码审计&#xff0c;未授权访问 可以看到构造函数ip是通过X_FORWARDED_FOR来获取的&#xff0c;而这个刚好可以伪造&#xff0c;那我们再加着i…

C语言中常用的函数

处理字符串常用的函数 size_t strspn(const char *s, const char *accept); 函数参数说明&#xff1a; s是被查找的字符串 accepct是要匹配的字符串函数功能说明&#xff1a; 它返回s字符串起始部分中&#xff0c;完全由accept字符串中的字符组成的子字符串的长度函数返回值…

使用Gitlab实现monorepo多项目CICD

CI/CD是什么 CI/CD&#xff08;Continuous Intergration/Continuous Delpoy&#xff09;&#xff0c;即持续集成/持续部署&#xff0c;或称为持续集成/持续交付&#xff0c;作为一套面向开发和运维团队的解决方案&#xff0c;CI/CD 主要解决集成新代码和向用户频繁交付应用的问…

【LeetCode 1991 找到数组的中间位置 / LeetCode 724 寻找数组的中心下标】中间索引问题

1991 题目描述 暴力解法1&#xff1a; 思路&#xff1a; 遍历下标&#xff0c;求出左边和和右边和比较两边是否相等相等直接返回值没有符合的返回 -1 class Solution {public int findMiddleIndex(int[] nums) {int lennums.length;//初始化一个变量 midIndex 为 -1&#xff…

学单片机怎么在3-5个月内找到工作?

每个初学者&#xff0c;都如履薄冰&#xff0c;10几年前&#xff0c;我自学单片机时&#xff0c;也一样。 想通过学习&#xff0c;找一份体面点的工作&#xff0c;又害怕辛辛苦苦学出来&#xff0c;找不到工作。 好在&#xff0c;当初执行力&#xff0c;还算可以&#xff0c;自…

Docker快速入门指南

&#x1f6e0;️ Docker 应用场景 Docker 是一个开源的平台&#xff0c;旨在简化应用程序的开发、部署和管理。它通过容器技术&#xff0c;将应用及其所有依赖打包在一个标准化的环境中&#xff0c;从而确保应用在不同环境中的一致性和可移植性。在 Python 爬虫的场景中&#…

【云原生】听说大家跟着学haproxy,都成大佬了(实验篇)

PS&#xff1a;想了解haproxy理论知识&#xff0c;请移步haproxy理论篇 一、实验环境 主机名角色IP地址haproxy172.25.254.100web1RS1172.25.254.10web2RS2172.25.254.20client客户机172.25.254.254 二、haproxy的基本部署 1、安装nginx服务&#xff08;web1、web2&#xf…

PHP MySQL 读取数据

PHP MySQL 读取数据 PHP和MySQL是Web开发中的经典组合,广泛用于创建动态网站和应用程序。在PHP中读取MySQL数据库中的数据是一项基本技能,涉及到连接数据库、执行查询以及处理结果集。本文将详细介绍如何使用PHP从MySQL数据库中读取数据。 1. 环境准备 在开始之前,请确保…

虚拟机centos9搭建wordpress

目录 安装环境和搭建简介 1. 更换yum源更新系统软件包&#xff1a; 1.1备份yum源 1.1.1创建备份目录&#xff1a; 1.1.2移动现有仓库配置文件到备份目录&#xff1a; 1.1.3验证备份&#xff1a; 1.2更换yum源 1.2.1添加yum源 1.2.2删除和建立yum缓存 1.3更新系统软件…

《深入浅出WPF》学习笔记七.使用Prism实现点单系统

《深入浅出WPF》学习笔记七.使用Prism实现Mvvm点单系统 背景 深入浅出Wpf系列视频的最后一个demo,使用Prism、Mvvm实现点单系统。demo并不复杂&#xff0c;但是涉及的面广&#xff0c;方便更好的理解wpf。代码在下面自取。后续会把git地址补充上来。 代码 项目层级 command …

Multisim 用LM358 运放模拟线性稳压器 - 运放输出饱和 - 前馈电容

就是拿运放搭一个可调的LDO 稳压器&#xff0c;类似下面这个功能框图里的感觉。本来应该非常简单&#xff0c;没什么好说的&#xff0c;没想到遇到了两个问题。 原理 - 理想运放 我用PNP 三极管Q2 作为输出&#xff0c;运放输出电压升高时&#xff0c;流过PNP 三极管BE 的电流变…

云服务器部署Java+Vue前后端分离项目

1、申请一个云服务器 选择云服务器&#xff1a;阿里云、腾讯云、百度云、京东云、华为云等等&#xff0c;我使用的是阿里云服务器。 2、远程链接服务器 使用FinalShell工具或者其他远程工具&#xff0c;使用SSH链接&#xff0c;主机地址要填写阿里云服务的公网ip&#xff0c;如…

Redis的String类型常用命令总结

1. set 设置一个键的值。 set key value示例&#xff1a; set username "alice"2. get 获取一个键的值。 get key示例&#xff1a; get username3. getset 设置键的值&#xff0c;并返回键的旧值。 getset key value示例&#xff1a; getset username "…