三维旋转球0.0.0版

三维旋转球

三维的东西在要在二维上显示,这点点内容说不明,所涉及很多,不单图形学,还有数学知识,这里仅仅做个最基本的
简单讲一下:
关于一个点,一定要有一个三维坐标,程序中的结构体 POINT3D 就是;
点的初始化由函数 InitPoint() 实现,该函数产生了 n 个半径为 1 的点;
点的运动,是在三维坐标内运动的,包括平移、缩放、旋转等。这个程序只涉及到了旋转,定义了三个方法:RotateX()、RotateY()、RotateZ(),分别实现绕三个轴旋转;
最后需要将三维世界呈现出来,这里用到一个术语:投影,就是将三维的画面投影到二维上。投影有多种方法,这个球体用一点透视就可以。还需要一个“观察点”,程序中用 viewZ 定义,具体的观察点坐标是:(0, 0, viewZ)。函数 Projection() 负责实现这些功能。

通常都会用矩阵来实现 3D 转换运算,在这里我将矩阵运算展开来写了,用最简单直接的三角函数来计算。

后续继续补充
完整代码如下

// 程序名称:三维旋转球
// 编译环境:Visual Studio 2013,EasyX 2017-9-19
// 最后更新:2018-12-8
//作者:鼠瓜
#include <graphics.h>
#include <time.h>
#include <math.h>
#include <conio.h>

#define MAXPOINT	2000			//最大允许点的数量
#define	PI			3.1415926536

// 定义三维点
struct POINT3D
{
	double x;
	double y;
	double z;
};

POINT3D p3d[MAXPOINT];		// 所有的三维点
double viewZ = 2.1;			// 视点 z 轴坐标

// 初始化三维点
void InitPoint()
{
	// 产生随机种子
	srand(time(NULL));

	// 产生球体表面的随机点(根据球体面积与其外切圆柱面积的关系)
	double rxy, a;
	for (int i = 0; i<MAXPOINT; i++)
	{
		p3d[i].z = 2.0 * rand() / RAND_MAX - 1;	// 求随机 z 坐标 ,RAND_MAX  可由RAND函数返回的最大值  0x7fff=32767;
												//p3d[i].z值得区间:[-1,1]
		rxy = sqrt(1 - p3d[i].z * p3d[i].z);	// 计算三维矢量在 xoy 平面的投影长度
		a = 2 * PI * rand() / RAND_MAX;			// 产生随机角度  a值得区间:[0,2*pi]
		p3d[i].x = cos(a) * rxy;			//x=cos(a)*√(1-z*z)
		p3d[i].y = sin(a) * rxy;			//y=sin(a)*√(1-z*z)
	}
}

// 使三维点按 x 轴旋转指定角度
void RotateX(POINT3D &p, double angle)
{
	double y = p.y;
	p.y = p.y * cos(angle) + p.z * sin(-angle);	//y=y·cos(α)+z·sin(-α)
	p.z = y * sin(angle) + p.z * cos(angle);	//z=y·sin(α)+z·cos(α)
}

// 使三维点按 y 轴旋转指定角度
void RotateY(POINT3D &p, double angle)
{
	double x = p.x;
	p.x = p.x * cos(angle) + p.z * sin(-angle);	//x=x·cos(α)+z·sin(α)
	p.z = x * sin(angle) + p.z * cos(angle);	//z=x·sin(α)+z·cos(α)
}

// 使三维点按 z 轴旋转指定角度
void RotateZ(POINT3D &p, double angle)
{
	double x = p.x;
	p.x = p.x * cos(angle) + p.y * sin(-angle);	//x=x·cos(α)+y·sin(-α)
	p.y = x * sin(angle) + p.y * cos(angle);	//y = x·sin(α) + y·cos(α)
}

// 将三维点投影到二维屏幕上(单点透视)
POINT Projection(POINT3D p)
{
	POINT p2d;
	p2d.x = (int)(p.x * (viewZ / (viewZ - p.z)) * 200 + 0.5) + 320;		
	p2d.y = (int)(p.y * (viewZ / (viewZ - p.z)) * 200 + 0.5) + 240;
	return p2d;
}

void main()
{
	initgraph(640, 480);
	InitPoint();
	BeginBatchDraw();

	int c;
	POINT p2d;
	while (!_kbhit())
	{
		cleardevice();		// 清除屏幕

		for (int i = 0; i<MAXPOINT; i++)
		{
			// 使该点围绕三个坐标轴做旋转运动
			RotateX(p3d[i], PI / 180);
			RotateY(p3d[i], PI / 180);
			RotateZ(p3d[i], PI / 180);

			// 根据点的深度,产生相应灰度的颜色
			c = (int)(p3d[i].z * 100) + 155;	//c的区间:[155,255]

			// 投影该点到屏幕上
			p2d = Projection(p3d[i]);		

			// 画点
			putpixel(p2d.x, p2d.y, RGB(c, c, c));	
		}

		FlushBatchDraw();
		Sleep(10);			// 延时 10 毫秒
	}

	EndBatchDraw();
	closegraph();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Hwang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值