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.源碼
源碼還在整理,有些地方改動比較多,需要後面發佈。