学习光线追踪(19)---光源[2]

0.简介

上次解决了光源问题,下面我们解决透明物体透光问题。

注:贴出源码与最终源码可能有所不同,以最终源码为准。

1.透明物体

透明物体受到光照,比较直直观的就是透镜效果,放大镜聚焦这类的,我是这么考虑的,透明物体也相当于一种光源,只是这种光源和真正的光源不同,真正的光源发光点就是某个中心点,例如球形光源就是球的中心,但是透镜不是,透镜是透镜上所有点都有发光的可能,因为透镜"发"出的光是别的光源或者物体发射过来的光,这些光来的方向不一定,所以对于透镜所产生的阴影下的某一点来说,可能会受到透镜多个角度透过来的光的影响,而真正的光源是从一点发出光,那么某一点受光照影响的话,也只是受到某一条光源方向来的光(这里假设场景中只有一个光源),所以在采用与光源类似的方法同时,也要有所变动,就是当计算物体是否与光源直接能联通的同时,如果中间有物体格挡,这个物体若是光源,则直接生成与光源连接的光线,若不是光源的情况下,如果如果是不透明物体,就不去计算,然后就会留下阴影,如果是透明物体,那么在透明物体上采样几十个点,然后对这几十个点光追,最后求一个平均值,这就是透明物体阴影下光线计算。

2.实现

	for (auto obj : s)
	{
		vec3 color = vec3(0, 0, 0);
		float light = 0;
		int count = 0;

		//能发光的话,单个物体
		if (!obj->isSet && (obj->m->light > 0.0f))
		{
			//for (int i = 0; i < 5; i++)
			{
				if (((Polygon*)(r.polygon))->m != nullptr && ((Polygon*)(r.polygon))->m->light > 0&&(r.polygon!=obj))
					break;
					//获取光源上随机一点
				vec3 point = obj->getLightCenter();
				//构造光线,光源与当前物体的直接连线
				lightRay = Ray(normalize(point - r.end.position), r.end.position, r.intensity, r.color, nullptr);
				//计算光碰撞的颜色,
				minDistance = FLT_MAX;
				for (int i = 0; i < s.size(); i++)
				{
					Ray t = s[i]->intersect(lightRay);
					if (t.polygon != nullptr && t.distance < minDistance)
					{
						minDistance = t.distance;
						lightRay = t;
					}
				}
				//如果物体是直接对着光源,获取光源的信息
				if (lightRay.polygon == obj)
				{
					light += lightRay.intensity;
					color += lightRay.color;
					count++;
				}
				else
				{
					//这里是处理阴影部分,如果是透明材质的阴影,则继续计算
					if (lightRay.polygon!=nullptr && ((Polygon*)(lightRay.polygon))->m != nullptr && ((Polygon*)(lightRay.polygon))->m->transparent > 0)
					{
						Ray tranRay;
						for (int j = 0; j < 100; j++)
						{
							//如果自身是透镜就不用计算了
							if (lightRay.polygon == r.polygon)
								break;
							//获取光源上随机一点
							vec3 point = ((Polygon*)(lightRay.polygon))->getRandomPoint();
							//vec3 point = obj->getRandomPoint();
							//构造光线,光源与当前物体的直接连线
							tranRay = Ray(normalize(point - r.end.position), r.end.position, r.intensity, r.color, nullptr);
							//计算光碰撞的颜色,
							minDistance = FLT_MAX;
							for (int k = 0; k < s.size(); k++)
							{
								Ray t = s[k]->intersect(tranRay);
								if (t.polygon != nullptr && t.distance < minDistance)
								{
									minDistance = t.distance;
									tranRay = t;
								}
							}
							//如果物体是直接对着透明物体
							if (lightRay.polygon == tranRay.polygon)
							{
								Ray rt = rayTrac(tranRay, s, times - 1);
								light += rt.intensity;
								color += rt.color;
								count++;
							}
						}
					}
				}
			}
			if (count == 0)
			{
				color = vec3(0, 0, 0);
				light = 0;
				//continue;
			}
			else
			{
				light /= count;
				color /= (count * 1.0);
			}
			lightRay.intensity = light;
			lightRay.color = color;
			lightsRay.push_back(lightRay);
		}
	}

这个里就是之前处理光源光线的,在else情况里,就是物体与光源中间有其他物体的情况下,如果中间物体是透明物体,则进行光追。这里要注意,如果计算中透镜遇到了自身,则不进行计算,跳过进行别的物体计算,不然会非常慢,就是当前物体是透镜,那么中间物体又遇到了透镜自身,这种情况不用计算,上一篇中光源也是,不和自身进行重复计算。

在球和平面等类中加入了随机获取点的函数,目的就是为了采样计算透镜透光产生阴影的效果。

vec3 Sphere::getRandomPoint()
{
	//生成一个随机方向
	vec3 direct = normalize(vec3(sgn(rand() % 100,50)*rand() % 1000, sgn(rand() % 100, 50) * rand() % 1000, sgn(rand() % 100, 50) * rand() % 1000));
	//球心加上半径*direct
	return center + direct * radius;
}

这里就贴出球类的代码。

3.效果

透明效果

可以看到透明球和透明方块的阴影部分效果还不错。

4.源码

源码还在整理,有些地方改动比较多,需要后面发布。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值