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

0.简介

目前我们的程序能模拟一些反射和折射的效果,但是,目前物体可见主要还是由于物体自身发光,也就是材质的light属性不为0,从这里开始,要彻底的实现光源发光,其余物体依靠光源的光反射光线的方法显示。

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

1.光源

定义一个光源很简单,就是将光源材质的light设置一个大于0的数字,这就是光源,其余的等于0的都是非光源。

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++;
				}
			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);
		}
		
	}

目前的光源是球形光源,球形光源的中,光发出中心就是球心,那么每个物体上表面的点与球形光源的球心直接连线形成光线,这样就可以实现光照效果。上述代码中,先从物体集合中找到光源,然后计算构造好的指向光源的光线中途有没有其余物体遮挡,由于场景中的光源不一定只有一个,所以将构造的指向不同光源的光线最后都存储到数组中。

3.光线颜色和强度计算


Ray Polygon::sample(Ray out, Ray reflect, Ray refract, vector<Ray> lightsRay)
{
	Ray res(out.direction, out.position, 0, vec3(0, 0, 0), out.polygon);
	if (m->light > 0)
	{
		res.intensity = (m->light);
		res.color = m->getColor(out.end.textureUV);
		return res;
	}
	//out光线带的是对应物体的法向量值
	float cosa = abs(dot(out.normal,-out.direction));//光线入射角和面法向量的cos值
	for (auto lightRay : lightsRay)
	{
		float cosl = abs(dot(out.normal, -lightRay.direction));
		//计算光源的发出中心
		//float cosl = abs(dot(out.normal, -normalize(((Polygon*)(lightRay.polygon))->getLightCenter()-lightRay.position)));
		res.color += (m->getColor(out.end.textureUV)*0.6f+lightRay.color*0.4f) * (m->light + std::fmaxf(cosl, 0) * lightRay.intensity * (1.0f - m->transparent)) * std::fmaxf(cosa, 0);
		res.intensity += std::fmaxf(cosl, 0) * lightRay.intensity * (1.0f - m->transparent)* std::fmaxf(cosa, 0);
	}
	res.intensity += reflect.intensity * m->getSpecular(out.end.textureUV);
	res.intensity += refract.intensity * m->transparent;

	if(reflect.polygon)
		res.color += reflect.color * m->getSpecular(out.end.textureUV);
	if (refract.polygon)
		res.color += refract.color * m->transparent;
	
	return res;
}

这里新添加了一个函数参数,就是光线,现在一个物体的一个点接受来自反射,折射,和光源的光线,这里把光线的强度添加了进来,还有光源的颜色也添加了进来。还要注意光线强度还要乘以光线与被照到表面的法向量的cos值,这样能体现出离光源近亮,离光源远就暗。

Ray Sphere::intersect(Ray & ray)
{
	Ray result(ray.direction,ray.position,ray.intensity, vec3(0,0,0), nullptr);
	//计算球和光线的向量
	vec3 v = ray.position - center;
	//如果光源在球体表面或者内部,要专门注意这种情况
	if (abs(length(v) - radius) < 0.001 && dot(normalize(v) , ray.direction) <= 0)
	{
		result.polygon = this;	
		float cosa = glm::dot(normalize((center - ray.position)), normalize(ray.direction));//normalize(abs((center - ray.position))*normalize(ray.direction));
		result.distance = 2 * radius * abs(cosa);
		result.end = ray.getEndPoint(result.distance);
		result.normal = -normalize(result.end.position - center);
		result.intensity = m->light;
		result.color = m->getColor(result.end.position);
		return result;
	}
	float disSubR = dot(v , v) - (radius * radius);
	float ray_v_dot = dot(ray.direction , v);

	if (ray_v_dot <= 0)
	{
		float discr = ray_v_dot * ray_v_dot - disSubR;
		if (discr >= 0)
		{
			result.polygon = this;
			result.distance = -ray_v_dot - sqrt(discr);
			result.end = ray.getEndPoint(result.distance);
			result.normal = normalize(result.end.position - center);
			result.intensity = m->light;
			result.color = m->getColor(result.end.position);
			return result;
		}
	}
	return result;
}

在球形和平面的这个碰撞检测函数中,返回的光线结果带有光源信息,就是直接将是否有光强,和物体表面颜色返回,这样可以在与光线连接计算中直接获得光线信息。函数参数也变成了引用,因为我在程序性能检测中发现函数传参数占用了不少时间。

4.效果

光源和阴影效果

5.源码

由于这次和上次的源码差距比较多,所以最后给出源码。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值