问题四十五:怎么画ray tracing图形中的blending and joining surface

本文介绍了一种在两个曲面相交处添加四通接口的方法,并通过C++代码实现了一个具体的例子。该方法适用于需要在空间中平滑连接两个相互垂直柱面的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当两个曲面在空间相交时,怎么连接相交处?

比如,两个相互垂直的柱面在空间相交如下:


怎么将黑色圈内的相交处画得平滑些?也就是将相交处包起来,添加一个类似水管的四通接口。

45.1 数学推导






45.2 看C++代码实现


----------------------------------------------quartic_blend_cylinder.h ------------------------------------------

quartic_blend_cylinder.h

#ifndef QUARTIC_BLEND_CYLINDER_H
#define QUARTIC_BLEND_CYLINDER_H

#include <hitable.h>
#include "material.h"
#include "log.h"

class quartic_blend_cylinder : public hitable
{
    public:
        quartic_blend_cylinder() {}
        quartic_blend_cylinder(vec3 cen1, float a1, float b1, float lh1, vec3 cen2, float a2, float b2, float lh2, float a3, float b3, material *m) {
            center1 = cen1;
            intercept_x1 = a1;
            intercept_z1 = b1;
            length_half_y1 = lh1;//这个参数无实际用途,只是为了切割看其内部结构
            center2 = cen2;
            intercept_y2 = a2;
            intercept_z2 = b2;
            length_half_x2 = lh2; //这个参数无实际用途,只是为了切割看其内部结构
            intercept_s1 = a3;
            intercept_s2 = b3;
            ma = m;
        }

        virtual bool hit(const ray& r, float tmin, float tmax, hit_record& rec) const;

        vec3 center1;
        float intercept_x1, intercept_z1, length_half_y1;
        vec3 center2;
        float intercept_y2, intercept_z2, length_half_x2, intercept_s1, intercept_s2;
        material *ma;
};

#endif // QUARTIC_BLEND_CYLINDER_H

----------------------------------------------quartic_blend_cylinder.cpp ------------------------------------------

quartic_blend_cylinder.cpp

#include "quartic_blend_cylinder.h"

#include <iostream>
using namespace std;

bool quartic_blend_cylinder::hit(const ray& r, float t_min, float t_max, hit_record& rec) const {
#if QUARTIC_BLEND_CYLINDER_LOG == 1
        std::cout << "-------------quartic_blend_cylinder::hit----------------" << endl;
#endif // QUARTIC_BLEND_CYLINDER_LOG
        float a1_square = intercept_x1*intercept_x1;
        float b1_square = intercept_z1*intercept_z1;
        float a1b1_square_a3 = a1_square*b1_square+intercept_s1;
        float a2_square = intercept_y2*intercept_y2;
        float b2_square = intercept_z2*intercept_z2;
        float a2b2_square_b3 = a2_square*b2_square+intercept_s2;
        float a3_square = intercept_s1*intercept_s1;
        float b3_square = intercept_s2*intercept_s2;
        float a3b3_sqare = a3_square*b3_square;
        float xd = r.direction().x();
        float yd = r.direction().y();
        float zd = r.direction().z();
        float xoc1 = r.origin().x() - center1.x();
        float zoc1 = r.origin().z() - center1.z();
        float yoc2 = r.origin().y() - center2.y();
        float zoc2 = r.origin().z() - center2.z();

        float A1 = b1_square*xd*xd + a1_square*zd*zd;
        float B1 = 2*b1_square*xd*xoc1 + 2*a1_square*zd*zoc1;
        float C1 = b1_square*xoc1*xoc1 + a1_square*zoc1*zoc1;

        float A2 = A1*A1*b3_square;
        float B2 = 2*A1*B1*b3_square;
        float C2 = (B1*B1 + 2*A1*C1 - 2*a1b1_square_a3*A1)*b3_square;
        float D2 = (2*B1*C1 - 2*a1b1_square_a3*B1)*b3_square;
        float E2 = (C1*C1 - 2*a1b1_square_a3*C1 + a1b1_square_a3*a1b1_square_a3)*b3_square;

        float A3 = b2_square*yd*yd + a2_square*zd*zd;
        float B3 = 2*b2_square*yd*yoc2 + 2*a2_square*zd*zoc2;
        float C3 = b2_square*yoc2*yoc2 + a2_square*zoc2*zoc2;

        float A4 = A3*A3*a3_square;
        float B4 = 2*A3*B3*a3_square;
        float C4 = (B3*B3 + 2*A3*C3 - 2*a2b2_square_b3*A3)*a3_square;
        float D4 = (2*B3*C3 - 2*a2b2_square_b3*B3)*a3_square;
        float E4 = (C3*C3 - 2*a2b2_square_b3*C3 + a2b2_square_b3*a2b2_square_b3)*a3_square - a3b3_sqare;


        float roots[5];
        roots_quartic_equation2(A2+A4, B2+B4, C2+C4, D2+D4, E2+E4, roots);

        float temp;
        if (roots[0] > 0.0001) {
            for (int i=1; i<int(roots[0]); i++) {
                for (int j=i+1; j<int(roots[0])+1; j++) {
                    if (roots[i] > roots[j]) {
                        temp = roots[i];
                        roots[i] = roots[j];
                        roots[j] = temp;
                    }
                }
            }//对所有实根从小到大排序
            for (int k=1; k<int(roots[0])+1; k++) {
                if (roots[k] < t_max && roots[k] > t_min) {
                    rec.t = roots[k];
                    rec.p = r.point_at_parameter(rec.t);
                    vec3 pc1 = rec.p - center1;
                    vec3 pc2 = rec.p - center2;
                    if (((pc1.y()>= -length_half_y1) && (pc1.y() <= length_half_y1)) && ((pc2.x() >= -length_half_x2) && (pc2.x() <= length_half_x2))) {
                        float nx = 2*b3_square*(b1_square*pc1.x()*pc1.x() + a1_square*pc1.z()*pc1.z() - a1b1_square_a3)*2*b1_square*pc1.x();
                        float ny = 2*a3_square*(b2_square*pc2.y()*pc2.y() + a2_square*pc2.z()*pc2.z() - a2b2_square_b3)*2*b2_square*pc2.y();
                        float nz = 2*b3_square*(b1_square*pc1.x()*pc1.x() + a1_square*pc1.z()*pc1.z() - a1b1_square_a3)*2*a1_square*pc1.z()
                                    + 2*a3_square*(b2_square*pc2.y()*pc2.y() + a2_square*pc2.z()*pc2.z() - a2b2_square_b3)*2*a2_square*pc2.z();
                        rec.normal = unit_vector(vec3(nx, ny, nz));
                        if(dot(r.direction(), rec.normal) > 0) {
                            rec.normal = - rec.normal;
                        }
                        rec.mat_ptr = ma;
                        rec.u = -1.0;
                        rec.v = -1.0;
                        return true;
                    }
                }
            }
        }
        return false;
}

----------------------------------------------main.cpp------------------------------------------

main.cpp

        hitable *list[3];
        list[0] = new quadratic_cylinder_all(vec3(0, 3, 0), 1, 1, 1.00001, 3,
                                             new lambertian(vec3(0.0, 1.0, 0.0)), vec3(0, 1, 0), 0);
        list[1] = new quadratic_cylinder_all(vec3(0, 3, 0), 1, 1, 1.00001, 3,
                                             new lambertian(vec3(0.0, 1.0, 0.0)), vec3(1, 0, 0), 0);
        list[2] = new quartic_blend_cylinder(vec3(0, 3, 0), 1, 1, 3, vec3(0, 3, 0), 1, 1, 3, 0.5, 0.5, new lambertian(vec3(0.0, 1.0, 0.0)));

        hitable *world = new hitable_list(list,3);

        vec3 lookfrom(-1.5, 4, 5);
        vec3 lookat(0, 3, 0);
        float dist_to_focus = (lookfrom - lookat).length();
        float aperture = 0.0;
        camera cam(lookfrom, lookat, vec3(0,1,0), 80, float(nx)/float(ny), aperture, 0.7*dist_to_focus);

输出图片如下:



换个角度看看:

       vec3 lookfrom(0.0001, 8, 0);

       vec3 lookat(0, 3, 0);


        vec3 lookfrom(5, 3, 0);

       vec3 lookat(0, 3, 0);



45.3 blending surface的结构图

       vec3 lookfrom(0, 3, 5);

       vec3 lookat(0, 3, 0);



        vec3 lookfrom(0.0001, 8, 0);

       vec3 lookat(0, 3, 0);



        vec3 lookfrom(5, 3, 0);

       vec3 lookat(0, 3, 0);



        vec3 lookfrom(0, 6, 3);

       vec3 lookat(0, 3, 0);



        vec3 lookfrom(3, 6, 3);

       vec3 lookat(0, 3, 0);




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值