學習光線追蹤(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.源碼

源碼還在整理,有些地方改動比較多,需要後面發佈。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章