public override bool Hit(Ray ray, float t_min, float t_max, ref HitRecord record) { //平面的隐式方程 p·n = d //射线方程 p = o + t·dir //代入有 t = (d - o·n)/(dir·n) //考虑到只有射向平面才叫相交(射出不算),所以必须满足 Vec.dot(dir, normal) < 0 float dir_dot_normal = Vec3.dot(ray.Direction, normal); if (dir_dot_normal < 0) { float t = (d - Vec3.dot(ray.Origin, normal)) / dir_dot_normal; if (t > t_min && t < t_max) { if (record == null) { record = new HitRecord(); } record.t = t; record.hit_point = ray.GetPoint(t); record.normal = normal; record.material = material; return(true); } } return(false); }
public override Ray GetScatteredRay(Ray ray_in, HitRecord record) { //镜面反射... Vec3 scattered_dir = ray_in.Direction - 2 * Vec3.dot(ray_in.Direction, record.normal) * record.normal; return(new Ray(record.hit_point, scattered_dir, ray_in.DeltaTime)); }
public override Vec3 GetColor(BaseLight light, Ray view_ray, HitRecord record, float depth) { //Phong公式: L = Kd * I * max(0, n·l) + Ks * I * max(0, n·h)^p // Kd是散射系数, n是表面法向量,l是光源方向(从相交点指向光源), Ks是高光系数,h是v+l的单位向量,v是视线反方向(从相交点只想视点), I是光强(光在这一点的颜色) Vec3 l = -(light.GetLightRay(record.hit_point, view_ray.DeltaTime).Direction.normalize()); float n_dot_l = Math.Max(0, Vec3.dot(record.normal, l)); Vec3 h = (-view_ray.Direction + l).normalize(); float n_dot_h = Math.Max(0, Vec3.dot(record.normal, h)); Vec3 I = Vec3.one; Vec3 dif = diffuse * n_dot_l; Vec3 spe = specular * (float)Math.Pow(n_dot_h, phong_exp); spe *= _smoothstep(0, 0.12f, n_dot_l);//为了解决背光面高光的问题,如果n_dot_l<0直接spe=0会有颜色间断层,需要做插值处理 Vec3 L = Vec3.product(I, dif + spe); //上面有两个bug/疑问 //(1)背光面也能出现高光,因为公式里n·l<0并不影响 Ks * I * max(0, n·h)^p的值; //(2)求出来的L超过(1,1,1)范围了.---暂时强行映射到[0,1] //上面两个问题估计都是要改diffuse和specular来处理 //目前先特殊处理下,以后看看大佬们怎么搞的 return(L); }
public override Vec3 GetColor(BaseLight light, Ray view_ray, HitRecord record, float depth) { Vec3 l = -(light.GetLightRay(record.hit_point, view_ray.DeltaTime).Direction.normalize()); float n_dot_l = Math.Max(0, Vec3.dot(record.normal, l)); Vec3 I = Vec3.one; Vec3 dif = diffuse * n_dot_l; Vec3 L = Vec3.product(I, dif); return(L); }
public override bool Hit(Ray ray, float t_min, float t_max, ref HitRecord record) { //运动的球先求出time时刻球心位置 Vec3 _center = GetCenter(ray.DeltaTime); //ray == o+t*d; o 是射线原点,t是参数,d是方向 //(p - c)^2 = radius^2;p是球面上一点,c是球心,radius是球半径 //交点就是把射线方程代入球面方程化为一元二次方程求参数t Vec3 p_sub_c = ray.Origin - _center; float A = Vec3.dot(ray.Direction, ray.Direction); float B = Vec3.dot(p_sub_c, ray.Direction);//(b^2)/4 float C = Vec3.dot(p_sub_c, p_sub_c) - radius * radius; float b_square_sub_four_a_c_div_four = B * B - A * C;//(b^2 - 4ac)/4 //方程组有解 if (b_square_sub_four_a_c_div_four > 0) { float temp = (-B - (float)Math.Sqrt(b_square_sub_four_a_c_div_four)) / A;// (-b-sqrt(4ac))/2a 分子分母同时除以2就可以得到这个式子,这里的 b=2B if (temp > t_min && temp < t_max) { if (record == null) { record = new HitRecord(); } record.t = temp; record.hit_point = ray.GetPoint(temp); record.normal = (record.hit_point - _center).normalize();//球心与球面上一点为法向量方向 record.material = material; return(true); } temp = (-B + (float)Math.Sqrt(b_square_sub_four_a_c_div_four)) / A; if (temp > t_min && temp < t_max) { if (record == null) { record = new HitRecord(); } record.t = temp; record.hit_point = ray.GetPoint(temp); record.normal = (record.hit_point - _center).normalize();//球心与球面上一点为法向量方向 record.material = material; return(true); } } return(false); }
public override Vec3 GetColor(BaseLight light, Ray view_ray, HitRecord record, float depth) { Vec3 l = -(light.GetLightRay(record.hit_point, view_ray.DeltaTime).Direction.normalize()); float n_dot_l = Math.Max(0, Vec3.dot(record.normal, l)); Vec3 I = Vec3.one; Vec3 color = texture == null ? diffuse : texture.GetColorValue(0, 0, record.hit_point);//这里还要改的,下面的material也是,感觉material用来定义反射之类的物理计算公式。颜色映射还是交给texture吧 Vec3 dif = color * n_dot_l; Vec3 L = Vec3.product(I, dif); return(L); }
private float PerlinInterp(Vec3[][][] c, float u, float v, float w) { float uu = u * u * (3 - 2 * u); float vv = v * v * (3 - 2 * v); float ww = w * w * (3 - 2 * w); float accum = 0; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { for (int k = 0; k < 2; k++) { Vec3 weight_v = new Vec3(u - i, v - j, w - k); accum += (i * uu + (1 - i) * (1 - uu)) * (j * vv + (1 - j) * (1 - vv)) * (k * ww + (1 - k) * (1 - ww)) * Vec3.dot(c[i][j][k], weight_v); } } } return(accum); }