基本光线追踪软件的设计与实现

参考文章:http://www.cnblogs.com/miloyip/archive/2010/03/29/1698953.html

这篇文章做的是计算机图形学中传统的光线追踪渲染,用的递归,最大反射次数为3,phong材料。

(上图 1024* 1024) 运行测速 = 0.09帧/秒

流程:

1.建立场景

2.相机发出射线

3.追踪该射线

4.根据光照模型和光照方向渲染

代码中的特点:

1.找到的这份代码,用的是结构体struct来定义的用于计算的数据,搜索了下C++里面的struct和class基本差别不大,最本质的一个是访问控制,struct默认访问控制是private,其实也就是说,在这份代码里面把每一个struct改为class也是同样可以运行的。

2.在这份代码里面大量的使用了inline内联函数,内联函数用法类似于#define ,省去了函数在寄存器中的反复调用,这样效率会更高的。

核心的结构体:

Vector , Color ,IGeometry , IMaterial , IntersectResult , PerspectiveCamera , Ray

同样有保存出渲染结果为找的类。

整个流程:

通过给一个test函数传值,test名称,函数的名字,运行次数这三个信息,如:test("rayTraceRecursive", rayTraceRecursive, 50);

test函数框架,先定义一个pixels32的图片变量,设置好大小, 在一个for循环里面,循环传入的运行次数这么多次,开始计时。

这个时候传入的函数名字,函数名字是const T_proc类型变量(T_proc的定义 typedef void(*T_proc)(const TPixels32Ref& dst);),用来直接作为函数的名字的变量,以运行相应的函数。

当执行for次数完成的时候,运行次数/经过的时间,得到渲染的fps值。

最后以 TFileOutputStream 获取图片输出的数据变量,TBmpFile::save的方式保存出照片。

画板测试部分:

void canvasTest(const TPixels32Ref& ctx) {
	if (ctx.getIsEmpty())
		return;

	long w = ctx.width;
	long h = ctx.height;
	ctx.fillColor(Color32(0, 0, 0, 0));

	Color32* pixels = ctx.pdata;

	for (long y = 0; y < h; ++y){
		for (long x = 0; x < w; ++x){
			pixels[x].r = (UInt8)(x * 255 / w);
			pixels[x].g = (UInt8)(y * 255 / h);
			pixels[x].b = 0;
			pixels[x].a = 255;
		}
		(UInt8*&)pixels += ctx.byte_width;
	}
}

  

渲染深度测试部分:

void renderDepth(const TPixels32Ref& ctx) {
	if (ctx.getIsEmpty())
		return;

	Union scene;
	scene.push(new Sphere(Vector3(0, 10, -10), 10));
	scene.push(new Plane(Vector3(0, 1, 0), 0));

	PerspectiveCamera camera(Vector3(0, 10, 10), Vector3(0, 0, -1), Vector3(0, 1, 0), 90);
	long maxDepth = 20;

	long w = ctx.width;
	long h = ctx.height;
	ctx.fillColor(Color32(0, 0, 0, 0));

	Color32* pixels = ctx.pdata;

	scene.initialize();
	camera.initialize();

	float dx = 1.0f / w;
	float dy = 1.0f / h;
	float dD = 255.0f / maxDepth;
	for (long y = 0; y < h; ++y){
		float sy = 1 - dy*y;
		for (long x = 0; x < w; ++x){
			float sx = dx*x;
			Ray3 ray(camera.generateRay(sx, sy));
			IntersectResult result = scene.intersect(ray);
			if (result.geometry) {
				UInt8 depth = (UInt8)(255 - std::min(result.distance*dD, 255.0f));
				pixels[x].r = depth;
				pixels[x].g = depth;
				pixels[x].b = depth;
				pixels[x].a = 255;
			}
		}
		(UInt8*&)pixels += ctx.byte_width;
	}
}

渲染法线测试部分:

void renderNormal(const TPixels32Ref& ctx) {
	if (ctx.getIsEmpty())
		return;

	Sphere scene(Vector3(0, 10, -10), 10);
	PerspectiveCamera camera(Vector3(0, 10, 10), Vector3(0, 0, -1), Vector3(0, 1, 0), 90);
	long maxDepth = 20;

	long w = ctx.width;
	long h = ctx.height;
	ctx.fillColor(Color32(0, 0, 0, 0));

	Color32* pixels = ctx.pdata;

	scene.initialize();
	camera.initialize();

	float dx = 1.0f / w;
	float dy = 1.0f / h;
	float dD = 255.0f / maxDepth;
	for (long y = 0; y < h; ++y){
		float sy = 1 - dy*y;
		for (long x = 0; x < w; ++x){
			float sx = dx*x;
			Ray3 ray(camera.generateRay(sx, sy));
			IntersectResult result = scene.intersect(ray);
			if (result.geometry) {
				pixels[x].r = (UInt8)((result.normal.x + 1) * 128);
				pixels[x].g = (UInt8)((result.normal.y + 1) * 128);
				pixels[x].b = (UInt8)((result.normal.z + 1) * 128);
				pixels[x].a = 255;
			}
		}
		(UInt8*&)pixels += ctx.byte_width;
	}
}

  

光线追踪部分:

void rayTrace(const TPixels32Ref& ctx) {
	if (ctx.getIsEmpty())
		return;

	Plane*  plane = new Plane(Vector3(0, 1, 0), 0);
	Sphere* sphere1 = new Sphere(Vector3(-10, 10, -10), 10);
	Sphere* sphere2 = new Sphere(Vector3(10, 10, -10), 10);
	plane->material = new CheckerMaterial(0.1f);
	sphere1->material = new PhongMaterial(Color::red(), Color::white(), 16);
	sphere2->material = new PhongMaterial(Color::blue(), Color::white(), 16);
	Union scene;
	scene.push(plane);
	scene.push(sphere1);
	scene.push(sphere2);
	PerspectiveCamera camera(Vector3(0, 5, 15), Vector3(0, 0, -1), Vector3(0, 1, 0), 90);

	long w = ctx.width;
	long h = ctx.height;
	ctx.fillColor(Color32(0, 0, 0, 0));

	Color32* pixels = ctx.pdata;

	scene.initialize();
	camera.initialize();

	float dx = 1.0f / w;
	float dy = 1.0f / h;
	for (long y = 0; y < h; ++y){
		float sy = 1 - dy*y;
		for (long x = 0; x < w; ++x){
			float sx = dx*x;
			Ray3 ray(camera.generateRay(sx, sy));
			IntersectResult result = scene.intersect(ray);
			if (result.geometry) {
				Color color = result.geometry->material->sample(ray, result.position, result.normal);
				color.saturate();
				pixels[x].r = (UInt8)(color.r * 255);
				pixels[x].g = (UInt8)(color.g * 255);
				pixels[x].b = (UInt8)(color.b * 255);
				pixels[x].a = 255;
			}
		}
		(UInt8*&)pixels += ctx.byte_width;
	}
}

  

递归光照追踪部分:

Color rayTraceRecursive(IGeometry* scene, const Ray3& ray, long maxReflect) {
	IntersectResult result = scene->intersect(ray);

	if (result.geometry){
		float reflectiveness = result.geometry->material->reflectiveness;
		Color color = result.geometry->material->sample(ray, result.position, result.normal);
		color = color.multiply(1 - reflectiveness);

		if ((reflectiveness > 0) && (maxReflect > 0)) {
			Vector3 r = result.normal.multiply(-2 * result.normal.dot(ray.direction)).add(ray.direction);
			Ray3 ray = Ray3(result.position, r);
			Color reflectedColor = rayTraceRecursive(scene, ray, maxReflect - 1);
			color = color.add(reflectedColor.multiply(reflectiveness));
		}
		return color;
	}
	else
		return Color::black();
}

void rayTraceRecursive(const TPixels32Ref& ctx) {
	if (ctx.getIsEmpty())
		return;

	Plane*  plane = new Plane(Vector3(0, 1, 0), 0);
	Sphere* sphere1 = new Sphere(Vector3(-10, 10, -10), 10);
	Sphere* sphere2 = new Sphere(Vector3(10, 10, -10), 10);
	plane->material = new CheckerMaterial(0.1f, 0.5);
	sphere1->material = new PhongMaterial(Color::red(), Color::white(), 16, 0.25);
	sphere2->material = new PhongMaterial(Color::blue(), Color::white(), 16, 0.25);
	Union scene;
	scene.push(plane);
	scene.push(sphere1);
	scene.push(sphere2);
	PerspectiveCamera camera(Vector3(0, 5, 15), Vector3(0, 0, -1), Vector3(0, 1, 0), 90);
	long maxReflect = 3;

	long w = ctx.width;
	long h = ctx.height;
	ctx.fillColor(Color32(0, 0, 0, 0));

	Color32* pixels = ctx.pdata;

	scene.initialize();
	camera.initialize();

	float dx = 1.0f / w;
	float dy = 1.0f / h;
	for (long y = 0; y < h; ++y){
		float sy = 1 - dy*y;
		for (long x = 0; x < w; ++x){
			float sx = dx*x;
			Ray3 ray(camera.generateRay(sx, sy));
			Color color = rayTraceRecursive(&scene, ray, maxReflect);
			color.saturate();
			pixels[x].r = (UInt8)(color.r * 255);
			pixels[x].g = (UInt8)(color.g * 255);
			pixels[x].b = (UInt8)(color.b * 255);
			pixels[x].a = 255;
		}
		(UInt8*&)pixels += ctx.byte_width;
	}
}

  主函数实现测试:

int main(){

	std::cout << " 请输入回车键开始测试(可以把进程优先级设置为“实时”)> ";
	waitInputChar();
	std::cout << std::endl;

	test("canvasTest", canvasTest, 2000);
	test("renderDepth", renderDepth, 100);
	test("renderNormal", renderNormal, 200);
	test("rayTrace", rayTrace, 50);
	test("rayTraceRecursive", rayTraceRecursive, 50);

	std::cout << std::endl << " 测试完成. ";
	waitInputChar();
	return 0;
}

  

时间: 2024-11-05 10:47:58

基本光线追踪软件的设计与实现的相关文章

基于ARM处理器的反汇编器软件简单设计及实现

写在前面 2012年写的,仅供参考 反汇编的目的 缺乏某些必要的说明资料的情况下, 想获得某些软件系统的源代码.设计思想及理念, 以便复制, 改造.移植和发展: 从源码上对软件的可靠性和安全性进行验证,对那些直接与CPU 相关的目标代码进行安全性分析: 涉及的主要内容 分析ARM处理器指令的特点,以及编译以后可执行的二进制文件代码的特征: 将二进制机器代码经过指令和数据分开模块的加工处理: 分解标识出指令代码和数据代码: 然后将指令代码反汇编并加工成易于阅读的汇编指令形式的文件: 下面给出个示例

敏捷开发下, 如何将需求分析,架构(软件)设计,开发与测试,一气呵成式的结合且高效的完成 ?

产品开发中,时常会发生类似如图中 "削马铃薯"的悲剧. 悲剧的发生,往往是由于我们只传递了 "要作什么功能"给开发人员.却缺乏了一个有效的且轻量级的实践,能在正式进入迭代开发前,确认开发人员是否真有能力,能将 "使用者的需求"转化为 "可执行的代码"? "场景树" 便是一结合Use Case, Domain Driven Design, UML 的轻量级可视化的敏捷实践. 经由场景树,可确认开发人员,是否已

平台化软件的设计与应用前景分析

平台化软件的设计与应用前景分析 http://www.cnblogs.com/spring_wang/p/3344305.html 1.背景描述 近年来,在政策和市场的双重拉动下,中国软件市场保持了持续快速的增长.2002年,中国软件市场实现了21.1%的增长率,销售额达到345 亿元.2003年,中国软件市场销售额达到400亿元左右,软件市场进一步升温.在几百亿元的市场规模下,掩盖了这样一个事实:软件项目成功率非常低.根据统计,超过80%的项目不能在最初估计的预算和进度内成功交付.这对用户和厂

软件课程设计报告

南 京 理 工 大 学 课程设计说明书 组员 : 刘雨薇 学 号: 914106840606   张钰 914106840310   张欢欢 914106840509   彭姿容 914106840501 学院(系): 计算机科学与工程学院 专业 计算机科学与技术专业 题目 计算机网络课程测试系统       2016 年   11 月 目录 一.概述 ·················································3 二.需求分析···············

软件测试用例设计 0620

入职基础培训课程系列 软件测试概述 软件测试用例设计 软件测试缺陷管理 软件系统测试 培训目标:1 明确测试用例在软件中的重要性 2 掌握测试用例设计的基本思路 3 了解并熟悉测试用例的要素和编写方法 课程内容: 1基本定义 要素和作用概念 2测试用例设计过程 3测试用例设计思路实例分析 用户登录:性能测试 安全性测试 文档测试 功能测试 界面测试 兼容性测试 什么是用例:用例是输入输出对,输出描述的是对输入数据的预期结果 用例是一组操作序列与数据的集合,这个集合通常具有业务或操作上的意义,一般

排水管设计软件,能设计复杂的排水网络 MIDUSS v2.25 rev 473 1CD

排水管设计软件,能设计复杂的排水网络 MIDUSS v2.25 rev 473 1CDAAS MIDUSS V2.2 (排水管设计软件) AAS MIDUSS 它是一种windows下的排水管设计软件.能帮助你设计复杂的排水网络. CAE.Datamine.Studio.v3.23.52.0 1CD 矿山软件CAE.NPV.Scheduler.v4.22.250.0 1CD(原名Datamine)矿山开采优化软件 LARS Bridge 06.00.01.07 Win32_64 2CD Ment

连载00:推荐:软件体系设计新方向:数学抽象、设计模式、系统架构与方案设计(简化版)(袁晓河著)

我正在推出本人的心得体会<软件体系设计新方向:数学抽象.设计模式.系统架构与方案设计(袁晓河著)>,由于我从未进行过相关的推广,所以经验欠缺,希望各位给出宝贵意见,谢谢!软件设计正在迈入一个瓶颈时代,软件设计正在越来越衰老!越来越无法推陈出新!设计模式.架构模式.重构.面向对象.AOP.等等一切,我无法忍受这样的陈词滥调,无法忍受这样的似是而非,是什么阻挡我们前进的步伐,是我们不够努力,是我们不思进取,好像都不是.对,都不是!其实这都是我们的思维定势,我们一直以来都是以一种模糊的方式来推进软件

基于安卓的个人理财软件的设计与实现--项目心得

首先,你在往下看时,我必须先说一句,我是小白.所以,作为小白,我的app可以不去适配各种分辨率,可以有各种傻x才写的代码. 第一次做app,个人理财软件,我第一个想法就是随手记还有挖财.刚开始说安卓app只是有很多想法,但是不知道怎么实现.为了学习安卓基础,下了xx安卓视频教程,然后又发现了幕课网,幕课网很多大牛,而且课程说得不错.不过在做项目的时候,发现很多都忘记了,又不想回去看视频了,一般是直接百度找解决方案,最开心的就是有demo,源代码直接下载复制. 而且我很赞成要避免重复造轮子,如果有

软件UI设计二

接上篇博客 UI设计一 二.如何设计UI--大道至简 如何设计UI,四个字足矣:大道至简. 2.1 原则 1.搜索--模糊到极致 这不是我说的,是老师说的,是百度说的,是谷歌说的,看证据就在这里: 一个搜索框,解决所有问题.看看我们是怎么设计的:  一个查询页面有两个以上的查询条件,让用户去填写,美其名曰是"精确查询"其实,是我们设计人员错了,这样方便的不是用户,而是我们开发人员,方便了我们编程,并没有方便用户,用户要是知道那么精确,就不必使用系统了,就是用户不清楚,我们要做到,在用户