raylib绘图库--瞿华
2022.7.1
知乎 1、raylib绘图库简介

知乎 2、raylib 2d动画/游戏教程(1)动画基本原理

知乎 3、raylib 2d动画/游戏教程(2)坐标系与颜色系统

知乎 4、raylib 2d动画/游戏教程(3)图像文件与图层

知乎 5、raylib 2d动画/游戏教程(4)raylib-drawing库

知乎 6、raylib 2d动画/游戏教程(5)键盘与鼠标输入

知乎 7、raylib 2d动画/游戏教程(6)游戏手柄输入

知乎 8、raylib 2d动画/游戏教程(7)音乐和音效

知乎 9、raylib绘制中文内容

知乎 10、使用raygui绘制控件

知乎 11、raylib 3d绘图基础教程(1)坐标系和摄像机

知乎 12、raylib 3d绘图基础教程(2)网格(Mesh)

知乎 13、raylib 3d绘图基础教程(3)几何变换

知乎 14、raylib 3d绘图基础教程(4)3d模型的载入与绘制

raylib 3d绘图基础教程(2)网格(Mesh)

细心的读者可能已经注意到了,我们在教程(1)的示例程序中使用了raylib的DrawCube、DrawSphere等函数来绘制基础的几何体。这些函数用起来很方便,但是无法实现更复杂的绘图功能。比如说,换个纯色之外的材质贴图?对集合体进行旋转或者其他变形?它们都做不到。

本节介绍raylib的网格(Mesh)功能,用它我们能够实现更复杂的3d物体绘制。所谓网格,就是三维空间中的若干个点(顶点,vertex),这些点的连线围起来的空间就构成了要绘制的3d物体。

下面的示例程序绘制了一个一边旋转,一边不断改变颜色的长方体:

#include <raylib.h>
#include <raymath.h>
int main(void)
{
	//初始化
	const int screenWidth = 640;
	const int screenHeight = 480;
	//启用反锯齿
	SetConfigFlags(FLAG_MSAA_4X_HINT);
	//初始化窗口
	InitWindow(screenWidth, screenHeight, "Sample");
	//初始化摄像机
	Camera3D camera = { 0 };
	camera.position = (Vector3){ 40.0f, 20.0f, 0.0f };//相机所在位置{x,y,z}
	camera.target = (Vector3){ 0.0f, 0.0f, 0.0f };//相机朝向位置{x,y,z}
	camera.up = (Vector3){ 0.0f, 1.0f, 0.0f };//相机正上方朝向矢量
	camera.fovy = 40;//相机视野宽度
	camera.projection = CAMERA_PERSPECTIVE;//采用透视投影
	//创建几何体
	Mesh mesh = GenMeshCube(5,5,15);
	//设置动画帧率(刷新率,fps)为30帧/秒
	SetTargetFPS(30);
	//-----
	int angle=0;//多边形旋转角度
	int colorHue = 0;
	//主游戏循环
	while (!WindowShouldClose())//关闭窗口或者按ESC键时返回true
	{
		//每次循环更新一帧
		double time = GetTime();
		double rotateAngle = time*0.3;
		colorHue++;
		colorHue%=360;
		//创建贴图
		Image checked = GenImageChecked(2,2,1,1,ColorFromHSV(colorHue,1,1),LIGHTGRAY);
		Texture2D texture = LoadTextureFromImage(checked);
		UnloadImage(checked);
		//基于贴图创建材质
		Material material=LoadMaterialDefault();
		material.maps[MATERIAL_MAP_DIFFUSE].texture = texture;
		//创建几何变换矩阵
		Matrix transform =MatrixRotateY(rotateAngle);
		BeginDrawing();
			ClearBackground(WHITE);
			//以摄像机视角绘制3d内容
			BeginMode3D(camera);
				//绘制网格
				DrawMesh(mesh,material,transform);
			EndMode3D();
		EndDrawing();
		//释放材质和贴图
		UnloadMaterial(material);
		UnloadTexture(texture);
	}
	//释放网格
	UnloadMesh(mesh);
	//关闭窗口
	CloseWindow();
	return 0;
}


接下来,我们来详细介绍一下代码中各主要部分的功能:

1 创建网格
raylib中提供了若干GenMesh开头的函数,用来创建基本的几何体网格。本例使用GenMeshCube来创建一个长方体的网格。

//创建几何体
Mesh mesh = GenMeshCube(5,5,15);
2 创建材质
材质(material)决定着3d物体绘制时的外观。最常见的材质是贴图(texture)材质,即直接将二维图片显示为3d物体的外观。

在本例中,我们每次绘制长方体网格前,首先创建一张图片贴图,然后用这个贴图创建一个材质:

//创建贴图
Image checked =GenImageChecked(2,2,1,1,ColorFromHSV(colorHue,1,1),LIGHTGRAY);
Texture2D texture =LoadTextureFromImage(checked);
UnloadImage(checked);
因为Image对象会占用内存资源,所以在使用完之后要记得用UnloadImage函数释放它。

创建材质

//基于贴图创建材质
Material material=LoadMaterialDefault();
material.maps[MATERIAL_MAP_DIFFUSE].texture = texture;
3 计算图像变形
和大多数3d绘图库一样,raylib使用一个4x4的矩阵来计算3维空间中物体的变形,称为变换矩阵。为了方便使用,raylib在raymath.h提供了一系列Matrix开头的函数,用来生成变换矩阵。我们需要让几何体绕y轴旋转,所以使用MatrixRotateY函数:

//计算网格物体变形(绕y轴旋转)
Matrix transform =MatrixRotateY(rotateAngle);
4 绘制网格
最后,直接使用DrawMesh函数绘制:

BeginMode3D(camera);
	//绘制网格
	DrawMesh(mesh,material,MatrixRotateY(rotateAngle));
EndMode3D();
5 资源的释放
我们在绘制时创建的贴图、材质和网格都会占用计算机显存,因此在使用完之后一定要记得释放它们:

//释放材质和贴图
UnloadMaterial(material);
UnloadTexture(texture);
//释放网格
UnloadMesh(mesh);