GAMES101 作业7 Path Tracing路线追踪
冰月旋律
编辑于 2021年08月07日 04:26
收录于文集
共10篇

直接上伪代码:

代码块
C++
自动换行
复制代码
castRay (){ 
	//Vector 值1 值2;
	//生成 镜头射线于物体的交点
	//pdf
    If  镜头射线正好交于光源   则:
  		阿巴阿巴阿巴
	If  镜头射线于物体的交点   则:
		交点和光源之间的距离
		交点到光源方向 和交点坐标作为参数 再生成一次镜头射线于物体的交点 查找物体 然后对比深度;
		If( 物体距离  >光源距离):
			值1 +=   L_烈度 *BRDF *cos(入射线于,交点法线)  *  cos(光源射线,光源面法线)   /  (两点距离^2)  / pdf    
		否则:
			pass
		设定一个枪毙函数的概率值 p  例5/6
		If ( 随机值1~6整数  > p ) 则{
			值2 = 0;
		否则:
			生成随机射入光线wi.  
			//If  wi.这个射线如果能照射到光源则: 
				Pass
			Else if  wi. 这个射线如果能照射到 物体则:
				 值2 =   调用函数castRay() *BRDF *cos法线  /pdf  / p
	镜头射线于物体的交点 没有则:
		Return {}
	Return  值1+值2;
}
复制成功

大致代码逻辑这样子;  视频里P16  63m 时候有说

需要之前作业的粘贴和修改内容:

代码块
C++
自动换行
复制代码
inline Intersection Triangle::getIntersection(Ray ray)
{
    Intersection inter;

    if (dotProduct(ray.direction, normal) > 0)
        return inter;
    double u, v, t_tmp = 0;
    
    Vector3f s1 = crossProduct(ray.direction, e2);
    double det = dotProduct(e1, s1);
    if (fabs(det) < EPSILON)
        return inter;

    double det_inv = 1. / det;
    Vector3f s = ray.origin - v0;
    u = dotProduct(s, s1) * det_inv;
    if (u < 0 || u > 1)
        return inter;
    Vector3f s2 = crossProduct(s, e1);
    v = dotProduct(ray.direction, s2) * det_inv;
    if (v < 0 || u + v > 1)
        return inter;

        
    t_tmp = dotProduct(e2, s2) * det_inv;
    if(t_tmp < 0)
    {
        return inter;
    }
    inter.happened = true;
    inter.coords = ray.origin+ t_tmp* ray.direction;
    inter.normal = normal;
    //Vector3f p_inter = ray.origin-inter.coords;
    //inter.distance = sqrt( (double)(p_inter.x*p_inter.x + p_inter.y*p_inter.y+ p_inter.z*p_inter.z) );
    inter.distance = t_tmp;
    inter.obj = this;
    inter.m = m;

    return inter;
    
}




inline bool Bounds3::IntersectP(const Ray& ray, const Vector3f& invDir,
                                const std::array<int, 3>& dirIsNeg) const
{   float t_inX,t_outX,t_inY,t_outY,t_inZ,t_outZ;
    if (ray.direction.x >0 ){
        t_inX = (pMin.x - ray.origin.x) * invDir.x;
        t_outX = (pMax.x - ray.origin.x) * invDir.x;
        
    }else if (ray.direction.x ==0.0 ){
        t_inX = __FLT_MAX__;
        t_outX = __FLT_MAX__;
        
    }else {
        t_outX = (pMin.x - ray.origin.x) * invDir.x;
        t_inX = (pMax.x - ray.origin.x) * invDir.x;
    }

    if (ray.direction.y >0){
        t_inY = (pMin.y - ray.origin.y) * invDir.y;
        t_outY = (pMax.y - ray.origin.y) * invDir.y;
        
    }else if (ray.direction.y ==0.0 ){
        t_inY = __FLT_MAX__;
        t_outY = __FLT_MAX__;
        
    }else{
        t_outY = (pMin.y - ray.origin.y) * invDir.y;
        t_inY = (pMax.y - ray.origin.y) * invDir.y;
    }

    if (ray.direction.z >0 ){
        t_inZ = (pMin.z - ray.origin.z) * invDir.z;
        t_outZ = (pMax.z - ray.origin.z) * invDir.z;
        
    }else if (ray.direction.z ==0.0 ){
        t_inZ = __FLT_MAX__;
        t_outZ = __FLT_MAX__;
        
    }else{
        t_outZ = (pMin.z - ray.origin.z) * invDir.z;
        t_inZ = (pMax.z - ray.origin.z) * invDir.z;
    }
    float t_min = std::max(std::max(t_inX,t_inY),t_inZ);
    float t_max = std::min(std::min(t_outX,t_outY),t_outZ);
    
    if ( t_max >= t_min &&t_max >= 0 )
        return true;
    return false;
}



Intersection BVHAccel::getIntersection(BVHBuildNode* node, const Ray& ray) const
{
    Vector3f invDir (1.0/ray.direction.x, 1.0/ray.direction.y, 1.0/ray.direction.z );
    std::array<int,3> int3arr = {0,0,0};
    if (node->bounds.IntersectP(ray, invDir, int3arr ) ){
        if( node->left==nullptr  && node->right==nullptr){
            return node->object->getIntersection(ray);
        }else{
        Intersection inter1 = BVHAccel::getIntersection( node->left, ray);
        Intersection inter2 = BVHAccel::getIntersection( node->right, ray);
        return inter1.distance > inter2.distance ? inter2 : inter1;
        }
    }else{
        return {};
    }
}
复制成功

要写内容:Scene::castRay 实现:

代码块
C++
自动换行
复制代码
Vector3f Scene::castRay(const Ray &ray, int depth) const
{
    float pdf;
    Vector3f color1 ={.0,.0,.0},color2={.0,.0,.0};
    Intersection intersection = Scene::intersect(ray);
    //找不到这个投射点.
    if (!intersection.happened ){
        return {};
    }
	//这里想不通如何判断是否是光的看的别人 
	//如果射线打到光   //hasEmission函数m->m_emission向量的距离是否大于0.00001}
	//在main中定义了光材质Material* light = new Material(DIFFUSE, Vector3f(0.747f+0.058f, 0.747f+0.258f, 0.747f)....);
	//其他材质创建时 第二个传参值都是Vector3f(0.0f);
	// 第二传参值定义了m->m_emission也就是说除了光其他 调用 hasEmission函数都是false
	if ( intersection.m->hasEmission()  ){
        return intersection.m->m_emission;
	}//之后的都是 有投射点且不是光
    Material *mater = intersection.m;
    Intersection light_inter;
    sampleLight(light_inter, pdf);
    Vector3f light_point_v3 = light_inter.coords - intersection.coords;
    Vector3f point_light_dir = light_point_v3.normalized();
    float point_light_dis_pow2 = light_point_v3.x *light_point_v3.x + light_point_v3.y * light_point_v3.y + light_point_v3.z *light_point_v3. z ;
    float point_light_dis = std::sqrt(point_light_dis_pow2);
    //光比物体近   还要考虑物体和光距离一样的情况  这里还是看别人写的才发现的 的确考虑不周
		//进度问题 这里写成了>= -0.00005f  写小了就会有横条
    if ( (intersect( Ray( intersection.coords, point_light_dir) ).distance - point_light_dis )
         >= -0.00005f){  
        //需知 光源烈度 * BRDF * cos(交点法线,交点到光方向) * cos(光源法线,-交点到光方向)  / PDF / 距离^2
        color1 = light_inter.emit 
                * mater->eval(ray.direction, point_light_dir, intersection.normal)
                * dotProduct(intersection.normal,point_light_dir)
                * dotProduct(light_inter.normal, -point_light_dir) 
                / pdf  
                / point_light_dis_pow2 ;
    }
    float p = (float)(rand() % 100) /100;
    if(p > RussianRoulette){
        return color1;
    }
    Vector3f l_exit_dir = mater->sample(ray.direction, intersection.normal);
    Ray l_exit = Ray( intersection.coords, l_exit_dir);
    Intersection inter_sequel = intersect( l_exit);
    //如何判断这个射线射没射到光源? 
    if( inter_sequel.happened && !inter_sequel.m->hasEmission() ){
        color2 = castRay( l_exit, depth+1)
                * mater->eval(ray.direction, l_exit_dir, intersection.normal)
                * dotProduct(intersection.normal,l_exit_dir)
                / mater->pdf(ray.direction, l_exit_dir, intersection.normal)
                / RussianRoulette;
    }
    return color1 + color2;
}
复制成功

写的时候想半天急躁了 结果写错好几个地方 检查n遍 我吐了.越急写错概率越高,别学我

如果你图形是这样 恭喜你Scene::castRay 内容有错

不要怀疑黑屏是程序问题 绝对是代码有问题

注: 如果长时间启动了ide 试着重新打开. 或许能好  (极小部分情况)

两个错误问题的解决方法

Cpp3    RussianRoulette=0.8

手动修改 Renderer::Render 里spp 参数(也就是每个像素采样次数) 我直接设置成3    递归枪毙率RussianRoulette可改   要不然太慢了….. 就这样一张图2m…

Cpp=20  一张图直接37m 搞不起

修复后大致效果