From c069f83de003f80bf0988b38493b595cb465ccb2 Mon Sep 17 00:00:00 2001 From: Jakub Stasiak Date: Wed, 10 Jul 2019 12:56:23 +0200 Subject: [PATCH] Add some reflections and native color mixing --- output.png | Bin 23057 -> 25215 bytes src/lib.rs | 43 +++++++++++++++++++++++++++++++++++-------- src/main.rs | 2 +- tests/lib.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 83 insertions(+), 11 deletions(-) diff --git a/output.png b/output.png index 99d9e35dd0feb9a8b709789668520237860bf157..1a8aacc1bd8c26d43744d0da54e800357414f983 100644 GIT binary patch literal 25215 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 GiTy8Ukinn; literal 23057 zcmeFY_g7PE7cCqMqKIGvq=^-z_b&3Hhb|x`g%Sw8H|ZcnQB;a3kkCPeP|^sY2k8P5 z+94Qv5fm^$=ry!&pF6(4;*JYHWMsqMPuc5PYp%KGdjHH=_YxZ)8wdotq_6jn83=Ud z76^12cK$SQh3h((2=H;%Rm(^V1S(IycxcZ8e81(WXJ!Nfg$si~F|R=&CU7a{F9;MQ z0|G4~Kp?dY5QxVwhiv)~_`^8|L*0KsC;$C^ZYWL#fh-^B|D$CQI>wlEPyekKP(*+0 zBvI!IhLmEavVn>78v3G{rumx16B!jLd{_jci;v*R0FHvV(sT1l7&UqJ}HCM>fVJ_TbAL< zyV1alKMxC8cpQEQuFnJiN_mV-f=ne028LmiEiFepOq8jv^oA|>l@mcwjQo>kvQd8_ zD-|6mijPBLz&sd|4fq<-Ne;qS!IxS&MhvSMf$t@5_HDt~zK> zD_pW6|3H-$^lRiY5fhmkcxKQo$iBlW>wWKX#w%=`j&!CxPrrY<>#hgFYy=pJ)P8Dbo!ui4Xywvr$bu(bA6850 zs2C4)R*&_sRI^|)bkvp*yyF;##zj4TTSK*5h`MqLR4a5IMlJ9O#(L7nt`n$ZG}2dj zl`I0P$d4argi}kUTiVb6%@(AB{mtT-9(YX z-)eAR3k5Z+s&&U~KMqGNOV+xQH%>#0I;d&f_PzcW=4#F>4n2@C{xIi^^B%sxoSz>g z2g93KL8(vZ{Q*t0AkYMU^CE0o&*UkYTyi4>JmKwkvO(kE!W|EH9EP+!3)w$~b&)~! z!nzC7ka^U}(_?=C%T0^QJwOAtOUSWoW)cjc!{#1P#V2JtgJ8eI7N#t$-sm0Lj}nKN zJ;z^xn(W8HYoF#}`9<6{5I0#t&2=ipG20Pz|8zq9pzO#77*ZcE;+;Pxl=JgWjsicb zl?`P;_pnsH;i-C9x11H*E#-nX`AJc@R8}Zd$Qe*}0hlzY;sPvMj|zTPkI77HF&?|Q z`Y_b>lwpx}30Z1}y2{1Pc`=t(jzX&qQ6;v}I6K~b4v>n!>t&);;p&ba)PLVYmYXQX zsTEohgN`3qS-<(FyF8}qsl!mm!`n+#J;m%wLSa*Hg98ZU=V`2gkURK`2UqbVX5Wu#XIjC(vAaGXlFn%WmeCx!ptZufdKF{Q;*kK+P|69Gb&#YskL!BaC_zU8aJ|l;ne6ohy4))o)YKkX!%SU9g+GoSH$)C#eku zQ<|D&J}teigWd#zIA;Ew9x|u9Q+e5iJ%n;A8=f!jP)@Gs`wU$1%-pl zq#d}HUSQ_EU;H_>`J!OE_mB( zs@*|41-L3pLC@c3aRaCG;`9xjBtXpr>iC%L+%31z>kFYeam)?y(J~`-=g!aX-1bJ~ zMI*sD+6np68OZMw^>L@1h{#H@W4r%ulU4r`vyI#up|cajzJg`pcwto84lv#cw>?%= z(u8lZQ4duU)hwpO#uL@Sc04#6-4goWXllrq?PuX;p9mgmu?J71tDZEEd9y=oD3~so zV!>pM{s`$*H;Ocy$aQ$Jecj1=NBk^E0Be2$X2%}Fj~fNc7@DTW)vU^#fgIi1bs%6& zpm-HW@QPvW16n!L6w*EeaqmdEMvOnHjeMO{iL&i$@HhpMnbbdvK@HJtHhF6|mQ^B&VVH6ASQU>LO++4Dqe7MNR%_8kK>E-N%+{dAtQekfja-Au;(l-A@5g8V(7OcI-M? z{qwr@^DAfFnC*c7y|{a%@*8sw)O@y6fS4B)5YMe1+b!b`UJ=PiGMo1P5H|;_cAy!nKHczRhK|97e1&WwjIa4t^Mje_dQG_Uyk35 z1&<1`@BFZ4k2c~7J`c0)pvt(QIdQ@q+`7}_Y!H58qcGwW=tJAUIb5+ZnWBR;(a1pL zlga)q?tB4@6uIOo%Op{cPow)Vu8reR$eUHJYj=hp(eXy8A*LR%570<15;B)rY zZuP4w)DU%AwoM)Mt5Ll#X8VUP$B;?;%|tWld5qvWM3S&1Lz&&sxW_}W?c&G=a_51A zGrYAU`i3HxL?!@GtX_L}jOp3wl@(^!+tNXxl8~HJz`JQ@Z65XRY}Tfyw3|XA`UZ#r zES`ZqwQ&Om`eds;ZCq9&dgj%kl>NGv5_)d$W<^XDDoW&NVM6>i2-NtS9maVW$TeIN zZ`AxIwT8Q`+2Y%fTeP3$C#+BDtNX?8kSG$VP%*2#no2#33;Z<<0gqY3E=4B|g87Jf z|2{Yin()-ULA2F__BHPegpI@wSX7@?3}PSh(Ut(aO6<#aJ0`$JV|E=1{_TdjlNZw! zCH_hBFj&AHdY~9r320qvz-eyKuVb~=nC;IBjt7Ms$l+_1qL|PR={d7nE8S)^N;k|P z3Mo{ffT|?rvU!s!6sS9aglcQrk;NXB#>ar4nqvRtAm2lHjIS(R8LU48S}Ak92piVl zr;LODU78IGb2Ft_ug{4mz-q?sOnBdbKqwwPnS33%TGNu5{zvYXNfi_M6@2qbzU)KJ zB=wnV^t!EZLeLcuXt_hS?Hf`5kyQgPb2s=)giA8#7k8EW=d zshtKr3${4rc_02EseZ#MR8g{ZKmn4E_HoRLizL5x?_qmPb7R3~5J<aA5z4sy+vBv2z@(0Krd-XlrdWIbKD@(^rE4RPfdqtd0rbDw5-}L`_+PBbi)8_W zmE}V69f-eHpK8*+=ej^y5z@AUqs^>TJ7b7YJ%3+M2rT;$A4ik0{%#e-t0wNC@hK`J zV(u*HmcPZRC6a?#T$W8$wBp~J=Om;)7h#=r174i~oYn7Y-T-en_glW`%E~q&_9$>kT*|5T+ zQ_F$3qyU#p&98okWa!n(Y2(1d*BcAp0e2?@cWVfo!@a5SGenC{&d-6ZhSJyo7b~ZA z1-nGIg*D zFBQ=-$T#>$aQs_soa=vcXz;st3Y-5$>;q(D>3yvO-U(F1Rf(iXBNvU5{?y zAC1))I-&B$A%Q51mYNw#hGg6KkY%(bfV|-4-3zefj^LXUcv+DEE~L+G4RgmD;#&Ww zfP(@$=7xh4ilJ&m&uN<{R%({qvye2DY^{8Xq+xaHUyo)0eqqguY0NzSd;(;LgM#|a zTtcTu0?Y)h9F#2ZAAkg&!YiCd`6)M+oM5Qco`GHq_P{vUPIlK9 z%syTpe#)0Yx{f@a(7H^F@BeRKoW)_|_h88!p{u$MSBM}`fcjX>oU^brsgQf-u@Q?Q z*MP_ayD(YPzQ-?gTQo~%(!Lz2`X_mKT=Dd1-q?TyyC?4HvQnUPXK8fik*3os}rtDIm(1n5n!Ie^Rgup8kd{LpY~%#yhp^TH92UG}tQsTtDP< z!p*h|gNfgy?ERtN=ltqa?qMYzH0}eTaz4=ORCk`VW^m$Akk`WvH6KM9sZI>02!D7f z_1OtlFc!Sbsf1SdFfcI;znfr|iP=bFysZ_GVx>utUxQ*IeubV!!An*@NiLH5{yIJw zLd^zz)0GSVJ?i}-_=4y08wsl}edyE;Tt`!VM_7)cHcrKH)E<^V4aMQ!1u5=W0Qf%} z1vo3XwZ**)`{@^E4TE{wWh|nDB0Q(yp~_MsRU^^FV^zyUv{2?nH;D_Sfs?I9s&_=;=^5b*vng-NqO|iR~i8d}4;t&bd$q=> z!TKU8D>77(GwAJ4B*XNFeE)$neJ^kGtuwudwP{1luDMzkfA656bBObQb4QtjSUYsTPx_-_QGOcw^ej zD1lhyCL(_uqIS+uUyKq3b{Ce6s8E7C*KqH0iy*5|eXkf-fjl_%uGbYM$1ff=Kfncz zsw(s{WUqP>fD7-chU<>z$KxCJTpD`PCXLI5$PeH}k9?i$d8@T?odBfc*1bxsh7%0h zQZJbmj4u7sx!cWg)H%>Gofl$}I-_Igzb+$zd~CKJ>?BnNA4KMsy|f2VWTt?AGoKOE zJb)&+K;%m(*JQyrtDIwL_`y`mRQ8e3^J=$-saP5a2N`(_jwQCs0FLA72OuY@*Gs#P z7v9gja2$A9k*k2I1)t*LInIw?u-Ms{tuOi3{P&HwJ7zERl?0l)zcC2ruDB7$0?Ozz zWdZ!LqVVIeZM=hsEPO=r^`uT9meWZ+036-vQmdrF-1cs%j(He%OB= z?!SrR4eNk#+hwEUSWp{p+M}j-x*k0>SNNS<_iI*TVaUtU;UsyRa*z9(ADv^%&;S1$ z!j$lin-h;n*#}Q%LOzy!`zxk_UPXV*GfYOaPO60}+OQ@t{^lw7NJ~0T>itKSrc-OE zzSNVfgQkw7=KwxP+5(rpQw*|zbYHZ8E|qU9t_MZlC;W6nrEGex&(PBAg9AFV<86Y#dA&;;IzPd4^y{n!tVf(GH^i5$Ds2R z)_?Jf@}x{tKUJ5W3H)RBmJk)-c2BRo0hXWQ^OVKYjLa6-%%kf$%3nUvS%h`ypl;d2 z3KTJu;h&yArvCjHy?S_b7g{lx@9~kaG6bFM97CE{k?0;XKne=J9h>O91hed*I1JsT zmu{Jc8!oNAJF3{y9=_be22G#5@@p{2ZziqGD%g9&jF|*rx_cTad3ybYP-;`}kryJW zlbbk%)|m;GfR^3~D!q=EbEkSd{c1MSv}yIaU6WxhlCWuGzP{x4+T*bJL2YivFq$^9 zzkMR;)2rO(@>JG}@saS#K6I+4P@h-)Am_yc;OY9Sg+dEa2D0s%dUiqTrVsxPeeVVq znH5|83Oy5E>AwhL(5=WTD-A|gnugK22bnE7AH)!m29RZjjEhlLON$}mxq*!(OSckR z!b0er_(7@fiCPvxC*o7;><_o1(x+kvP6f*wTFu)&)pCNfpBs@kMJ}}j<`_P!6$?Js zP|nx}GCFCSYUqtL(wNDQx09W})#-2R@@*6M4VX`cuf6!Gja66}52SH=?Vd&%EeBs3 z3$)uEw4DKm3?E^(ESUKLn%Wt?fDav}@(9Dd4f%hnn7TJzbdnYCh4JMT*!QHISbmwA zt1?d@Hu99tL}y8bwigc+nmu)_F-^yOdtu|)Hg!zM?p{<|zA#jXMVr@;Ng|xBUu7lI zI&tFkqJ!7KKB1=cG<%OM+SZe)!_*3?Kd!L^sa&LgAg0Qp*`tR%$cpP;ag8P~M%n6f z7Or+JF3?L(qYC-Wzf&3!Bhtj~#re-X)n;1h|6*lIe?F*;*JzBbIbYE!BMNHo*Y|6m zRZXf3S?x#|t}4@8@2F{QY515IH1}$@I8(4ck0En|-HVe7-tpFU^tC$}b<@1(tvV~W z@8xCvC>cFHGP)L3hdQpymfI@l4Gf|ugCvAss0Jwfc>h<)5nq2mSs`mKyxbBB&~&f$ z1Ptg=5O%9W)WLc6jq{C)SHI9ss#10=yoQ6~FuATC?hcPQ>gv!P3GVXvQS^-`*;Gk| zzM#2@(&4jPVq8;a%xgG)`Q0?I6VYhFQWxG!@{IUH+sBa57BhOJ<$YLEuUrV`glN2buoiulgpSCsj$^quL zUHkO!BnjF=vQt-f?i2s1`Z@$cg++&LUGrnxU zvr>1YOt1IxZRu@ zx3fB~x`{^;>}r06i$x-rMM87gl|;D--~6HLd9la?&Z1>#%q_=J<9>|7O;03{nIX`! zOFSHP^2yO@jX_iz(o&r9jU9QUmBfPcI?PKiStd)=JAl6 z@*N3>Q30i_^6OKkOyXRA#S<3s(C2?_G-`KeBNdPHUtJteVF}P(VW`tB-9H*a?(1n% zyaI?STOJF?i01d`mQHQsb8DqcN?ysEb2U26}?EM4Vsb3Z1PRLYE$P! z-Yl7thYESc_a56fNgw7@n|h9%W~Bt|o0;0-YB+>_jVE9BF(M@C6pG4WETU@wV+V8bRFwui>^F@vv$Ws$a4QUJGkG~EP}W=GCpA+ldx zyQeB)y?&cS#?62e_d3xdPfIE}&6X59gFl#lTZPr_vaU#SF7@{e;wNrG$Q7qeRbFOwM9YeQu)&BsaAk*xX`_!{ z+>egGMtf91k4UPJv1-BKv=zCa(o>Uv2l?}vNc%{`rD^(sad_T~4=hi{q@Nz2*ZKUt zZ9M36%zalhkyrd83|lxl*gyF($;>v3NJ}UAsUJUx95=eptgReJ%&l;@ABj5+srbe^ zch+@o&X29X4&L0#yDOht4KQM5Xjkf)!3Q>(iO5EEDjS3kuYn5~JHi>=1P2QF!+2iZiLtu2sjoLXK(N_s6d3+Dvu{rMeTAMMj*>nnWQN;*T;) z3(9r`{s8R3)$8S?{vPj*J>|AQXOqYt=H`U-glPEfqrRVnn`uM6v;TPQ{D>_$L%dGV za+jFSP@E(*$tfex;a1PXiWw?rP=%ZTx8!kyNbN0*R3Bl3WaV?u!-)@$JhBrp9I)*+ z;;Y2_CqwbSClYo?(onj;KlLby?3u3%sCMr-v_x`gDh+x=BLMKoQQw!_c#+OI`R6fb zEAxLxKC$f@tPQ@*_LRp*w?g*CKVO24G9BJtbt(?pxWc%PZ+fPrL2O#x;qCbfZt^h} zvvU^zyg2Xnz{if6$i*)F)K{kd&G8NO6V|tH9@*>i6QfW7>T8p-hcp5>uX_LK6EGis zOny)T=`4Ya^Alxe_|Gw`OpLxWqDb?~0OE-gjDGJIF`fBqr+m_6aJz|lv0*sp> z7i#)~%WLiI#|0{5E1f9+MM!w9<7h|)z(ZLuzfoagW1E%RJn{VEzMJhJoQE`K5bRIE z4(N}Ej7R&OaDO@6?&kQBm@v6rC#G(iK0?zp>_03}DGs8AQpN>!YP&5XnNu&7!~Fsg z5%pnbZ8toSHhXZBr^de8e<#1CQao@WL7N{4rBw>bIOd})I`nw1J8=#2Y z^Sk-OLqufCRERcis~5@8%=QtiK}#Ty$VOA@?Hl0o4?!bR_U60ma^T-57u@lg0M!Yxt?`(oirkX@cPm0v z)H*Ens2r&O9{XXv{sq5ydP*80%C0Xr-K48)gYT(gCRv<}D0SVdN}r70ea3th6BG_i zOrNPAK7z+C`7}qId1}guNTO#oGB$wqQ(G#QEK>fDOa6aU&~M9pKpr{t0FUGDcRGm1BwbF`uteiJD6a zCasnu%gl`S;S-VJGl2rp&0_|u ziL^2NJFwSvsSXDSDxRB*=c1HAS}&jL?UHjP*JE|=LS;p` zvSTe@VnU~{1N)sp;dHe-^+ICPAZse5bo)0(_#R9P(O4XF#hzP;Pk13vc2(p z?p(?4qb@jB>Z(d;-+R^L7KMeRSKO%J+nkrw zDOoF`5?3Z!6jwI4M+2jST8-wou6*eL|7Fi_@-AkG*OD<$X=!OzA<#?iC3kj ziYTH>lmjRl{~FiIDUUye71gLV+9;t4c5nyz)<$U`$8N0#H2u|`wWJDc?bu5aQq~*s zQ*0v}9j5NJT;?Q#d#JJeQz+J_KA+(W*m%%JQ{~Bg)t1wWh!AV=RR9=_`;6#8ZrgI! z>{?#&yymk39{Ur)B@t9pb`PFZeZJ<{+LjiC>nSwk<`D*;`4)#TivHJ@q%uJ{4svvW zL?bBt^xtqoSm#3W%%fQMy5@ubVFeq*QD&*7^uU2@c!H4@Q?;hd_55a` z!EQbB_(yqQ$B{4ft_U2SIETUIsHuUlH;7qIlAG1B22v869@6!zqmdm32_BY7l1p5V zG7k1TU*;M#GpojP*IIF1OEWuBfo+*S+k*h<+f>8EfXM=`xB);C5{Qfvc0%Jy-EpFl ztOEw<*MHFB5iaFvTo%OHPs{DczsUSkeK9=KA${l5#ev~}MrJYOzeR2t8X>l@TF)9O zm=UABW)d4@&aoTfDy+`8iL;g!F926hC2@m)$2iwiFfeJ}Lp+nJ^k2!92?Hlpp(IBh zsD8nkHITO1u?X~(o|VvV;z)o^)%R4NRz6k&)2x{iE@8Z$vNpE&7ApBRr=)crWMZ9o z+zvZ!EKfZXwd#6d8}?qz?TSljHx|(@!jB&d+%^plsu7=B5528Xc0)48(V!;K$kClio|4>L6_rzWeGmR-k&Kj{{kYh+<{2BVGyF42eNdts5!7l-Qu z-57GC9=ih`+21&q8-qD+h_iAX;QJ4n309Mk6lJ`&YS#7Qeu$CE;iHQ8pBp{2vgG#b2;1!Ro%qx{_z2(Biigz8L@Y^V6p{dosI^IK$ z{$fqG5H{1n*Bm3BjQw`kZfI#+UuNIFJ5j-MiRX0i-1gA)8%q-&bRwFngfKk{RrogO zwLPsjZE&KxOYxJ|kfl>RPlqGF+?p5(dS;xlI-GVqyk!{BBx=V|^D|*4pTszze&hPK zGBY<(cAA4;38cX3UFtuvmy3NXqwb+v1JUL9W4SI^!XE+a?*>hODwlZ{P)U%4a-b~x zocSw(hU>7*uxb>85MQk+@L`m?T8jdWvj{%qK<$0XdTu6JR>}s5+WM?QiJgd2g7yPf z8p_fYTs|*#n23yg$wq#;Bl{ydps=1ScLV$9RKkzqxHlrUbq zot%Ha_1OFEp#O8}g?fT%E#LU!cv3jzXt!}8)VJ&SP%s|W^45eK|1A;yXJbbzT*zQ_ zBM-<|_ArzyE9w@+p|<&7BJ({`5kr@}%5py39Jogmrjb)SK~ z2FM~drP9JepWpo7dXmF#Sfuok(r&zezfC6Cw^9VwBWvl$+q+ZlQp={$my{S4S)vbT zoQdkOe_-6v1>|;``p|hJt3(LCG41}sX=LyN2XqkbX}M{M44j2aVt?1n#;uhT3y4+P zx$T|5Qf7Y+(b=bf(B$hAF{x%CO%ALYUs(l|7G4Yw)t#BUO)usecw%K?8%;bCapJfX zHPq96k1g4fz+_wU;_#9#_2TKF<{INA`#_cHzv(|!j@e!w!8Lj@QNo+6Ri)vzKKw)afk2fKswcXpl5qabEVi5avj6k2n1^ z00zxXv*Pm0txkk{H#|93>2;Xe^y8G;c-%hlM zstf>!1e{V%WiH*ZX-M!;THBb0@HIwOA6qwul6bMQ%GUDi;!%eMZ7>UF2E_qV{z6gI zimU#mwRx@BhsLkB5D!!Gg6m!2`w`8oZFmxAgMLNLaAFHpl2t+#i*I-u9$WpPYHhVa z|HI>Avr4jzzNe(d$2@~3S)a8goBP;thuPuTTUCiJrL!07A9znRY=X(TZ<^SobKVT} z-xkOpyaX$&-(8l&Iig7+TF!*Unxby15tpVKsSuoBuJEvvquI>;?yua^nc{!QGNszJ zxd6kD4w&`%46R*!Ya5Ap{)JRl|9i$p_4lawLPulL@vq2>u*eb;UF_d`EN_=rNM$#9 zCaornAJl#FDJ&Z;0A`g)EBV7JdPzB23q`3uC@>X17#mXwu@`!>{vszAm{3YoiWCs) zWxXU*Y-c!DImX2kYdE*32jl0&FHIlNJNxd0>4`~Vuj8E_i3fg;sVe2L9{q@rhFA5r zg!D|=u6@nk#;6b*V2xHBo`66GD~#aM6=YqiI!qQtPQ3{ZOw2)s02()L{q$$^M>FNV z1>lVe*mnwKlXVgy(I}YF8`ytQyx_vOJwdfbgOlRfj>=Z^{mX!|iDt7O*KPOM>$^9IpF z$Ijb;1@BM-DEXxAA`ySVqsr*OIRFW8xdqS)_q7x1JXBExohIqfR~z7u<;-VDJRP$q z^YkREK@-yDf*3s-<0+@o9`*u~NzJ~7)*P}6v%1lLC}BWe(MB=eH9UI&zh%F&z{VPI z?$nYF6YT?nteulUh5hl087x$+dIuIFIz4))gPm_b(VH*OpLblib<~3Mn`7M0_~10X zN5|md4Zr^_aW+Z$0!^n4%3f!M)3(kgw2g}o`y?UDz6GfsJvWuG>q^6gchBrc{-Lg= zw99)7i=)a&QubCYi)V(ATmK7x+^iPk@O}L`m|XOfeDT0@-MHf7&*&$Uez(x(&(Hmb zzMR z*CC4#FES+sm>3nN+|D06x9;#Y?j-HdJ0YF0*bQxodKIh}0Z^*Jy;?5Zl3`|9+hPwa z!5{3)N?o|Rq20Lj%q^0oSMeC5UUp^g}*1f)BUm&UoM>) zLIXCYx*JpFFNeyp1N&#X>@mBYHj02#xAH^X)dMAlQmnXgRXL#PvPvN!IZcTw@61^lm!WoU5B#WxEvr8Sv?kxP>xi=L}l&!)BdPNXZ5&v>~of)#GBA3>QFOa?M z&jhHp@{w+r@m}PyfDdt5YF^xUCn`Xfa33?pi{AlRr@@LTIwY+89kK)W$i0g0p(x>? zkr&aMNpr2}H>`d?DiVs;v~G7p&%DuXG79JH_c^6oe0G@=LwO-DGS>rOlKdW3+b%J^ z8^QDQv+c8qReIdBs|ReI2qOk3_lfzc>w5P1(DeLw{!|ARpuQB0h)`dm88*_9k%~Ex zK=6P-jzv9bX`X5VWyK+!o0Qt*8`w~BvfYaX$do`Ns;nA)0`1C%*|E z7;d{|eIXVzZwudf7l)R272WXUMoZw$nmt-KqKrD?4b9s%!|Kh7I}e#*D?F#)21cDS z)bF57g(y9Ba`g!9@^WZFHsQSurppqNS|fEFL=T@C2z@)EB_J^)ean}LVx1M^V>ESo z&F0Z{zU@K<_lWg>l>sKiKiY2*gbNKqHR-sz7Ks`dlg;Sn$^=B%9QN4wAOj3A#xcM) z_WGfQ6Ye=`s7`|qbm>AEc?h?2HJay3KB2;-m43Ot-S3NQO{7*iMF-1BGv7Jd&|#_o zp!AG-HxO@&sl(aJ{Kmg+gz*TP6VB_Q-m~vwQ3CEv=rKiVrjQLdJbZ#vww8@n=~P+- zJ!xyW4w`p>(OmwVPS6QqXO9DiMR1%uYAIFs{b5(2p=3xqEaia`;}19iu@9=e+PK;3 z{_pa5-X)Cs|7Pk|>ek&=)Dx89c^c?Xq1m{9Mm@h4QqcC-O}J_zk^7~kdKST6|7d&vrJ%CI$+E&UN{P%)X>xfhRYd{40z=8f*^0DfixHQ~3 zpNw}Fb(HLJea=@+k~WB38{;rf524s*C9Ht!QF*z(&CC()q-_~T+JCC6ZOw@8neLH% zW>BGX1h0QH=DiJnG~%CNi}+-Ll-aEu|K^k}Y*UC|uc)|<m^ z!WTl0)xaOlGe*J?TIR16VrrN!$1NSDNukY@} z@1Qzqt*s_*Pm7BInOhFkFOX9Qr0aO9?-M0Qbhovp6`-n=aM8$!kj(1mr<>Ps5rOW7 z&GP4`hlX&^M6*8*K2A^Bob%oAn6;3#O1fEfoVw)$w12z}nF5@*r@O{7J$WAQ?H)^( zXvZyEbvTggp;u?;5jg}UAT>S;WO$RArp$-CW6zU;gOv3pv}B$# z1JN?2D6ui_1A@^FdDP;NbD3lYS9yH;GT=UgZ$Oxy%((}i+nw-M1sCr)G%mr35*Hx2 zcnqcQPS#)p>k-*;kx${mr##KC5dW0}0Hf;e#=Wvu6MuB_+cV~6+Zvr!L zdvjmOSWJU&<)KQI&i#G*O2-shJi(w{zk46zHw$(Uw0FfpI@9-Y zRj`tzUp+pt)t4r(!Ys@DB=LpYGKerwb8%0F>(aiXm+Xi^;|rfLblIi{cDcf*A+x?z ztMHZ8TeA(ny#%|LE|1vG6eiwp!kb+q7D0$4qomz?XMbN46KN#T7ah&&9e&HtFZnFA z%;tP;mtFQ3vr_xi8b_pHrE`CLJvu$~pe(6YFpoF6#fn3EBJH@oBd0=e>Rq~XI-t-E zs=pQ$S#<5rkr5LDl;xL|SgYv`bO(qtf+}-?75ZKrMn_4F6Yz!um>ZboEqS5B8tU|X z)V#m=dDs(8{ro~6$9lZYJtU|TT1X%Idph&wbO`|EHKj=-h*^8@;CoktW+UAQiGAh^y9 z{e5XMcm+B-Aono@mra$4AetYssHO>CRS~a%U|5wuNKh3dhdmy8`Q-y zH)ed472D?#mx*3L^j2W4Fl7Kj6e?%WMe`*wRk1z~uOxAud3}&eLPz&kxkGlRe)guQ0&l8U$%|mS&016X*%Iess1VK z$hDr1x?+IG{WakS*sbpZo1*Zl24ueH|9?^)Uc3EhOfz# z;V);L?gBsY_(`}e8*D1wICJ&Q=yJccW~L?G$h(aV;%~h3E5q){WyP`Pq)%GFV!QGR z@iBv)V>-Ct^v!#|B|uXWEgeTS=dOsqE607@f25gZF&3kMo?{L`ffuPHXCL?%tn|gL zssEQcU9n9=r2hH2YMyS9gY*K9pp+&lPcKQI_Ai(dPoo{mO3fn#Eq@mJog-B9x73$H zp_KQ!5OZcMfP%ehv6o!k4N^zXyI7NxgoxkhDVo{-P{6Sw%Th#=W56@4^xUmGVb|dI zd6!7pU*}rW0Cjl2|ALF`ocuGOJ?%}t;poPxZm44YC2m)zQ1OO`)BDjo{+aB)(gYhV znnyknedY+vHGQ3Amp!9ui4v=3@%)+*dG83%5WrC9qu1vi?68gR^Yx8zQa7CzCy+wP ze-hIvaV=6g)Al3$*#i{wCYpBZlqMnnHO=E!tGRkd* zv{mzolc)S|+HLKRbn}Iy)SQEX!iQOaOx}jrfzGZDlmA-P>a694;PgdCyGe%NV&Qtb zlT>MWwxFb4n5X|v>0dC08t^UASvvL7TdCu_$o{9?72GoikHj6|2K|N8^R_MXo6^)a zDTFgNSZqWOA7|%XQDxhfKPqr(V|VUC4e-OM_CKaDk7$N;qzJ{($WXy5K=sUM@^PE9}s(z~--b-X-qJ51&8VtT*{`)KOXtEL>%N(s3& z4G;0(r`UGXe@!Ql6o)%-4i8D1&W~aK(yb1uvYs48(8TK{0Fk{2+<+>A0PduJ%3P$Hj z6~tq)fwIWPyJy8olK-$swhDh!!-LT2#0U-Aef2n%kJC@pmKY0dNJ)+(pT?Y?}h?ZzUN;}jxwKrMY>kLL(kA+5kF68 z{0mcit1-(v2{lB$6=!OInb5c88@S4MEc9t|mbtW{=BUfxJM1vSX!ON6-Jj`Yq%Y7y zY(4^I@w873gm^SQi*d7QDz1=|9-5PLi4?O z({PoewnG3L&EV#9l~3!-t&mNM9q?Z{N-EZ5#7WALRlf!_6sSQ?uwsv{ zYS=Oi(5>L3T5Mo!YE-)CLM=0DC4K%n9O&Y)XVFF<7XCSOP|-8OAV%#Pte*jN*9i@R z0cx}D_NxVoG7+o(H+qk&nCZevmh5c?ht}yX@n^0q6LkF3pSdsy7hvtB;}!a;n!*KR zb_OTA6aD-yKub6aV+1E%SX|^DYM&Knc#;4)a^q9wKlnO(K16*#L2ym~4>VxibmnZ)!op74n~XFtZ=iCLc$4;a+iRp4m1j3i)t! z8c+y#<^xIvp;RYFdDM{_|FQ#?_^Jx%@SEU0G-7HqYwGf4d*1J^;=}GYq!8*I+jty@ z+(fZ1E)uHR@4o_lXu7++TS|(NFTV+PeHc&c^_6UTnI z?qTsB$cg+qfvPI!F2S|Sd(i2=ISPci){8&By-V;(jrp>3uyleH(AqD`mR@jCVQznQ zuzL&!LZ(*H(W6-3ddH{%?uQ{~an?JfOCKUflU_9$e6SCoUv7Q3qvI3Ep z9{;G8KZ0S012h>6Ux0?>)+~tcOqs5&9wm{x{8b5bU$A8gUcTqFiOR{j*Yq!PvejXE zeb|Bsa9QP_-=v(}J~CzM0NTbCjxztrOWp7I-y{Hxo3n1M>#1)33+tuX23tv6*sZ4d zs3zGSb3trffh)Hv{;oB!s;D!#$uJZLMof85xq2Mds}X0@Wnd^~Sw ztv4xfHebtQ7LS{LVmB*q{<*ih9x94IiLR(W?_p735_I_DDsl19l3B6U4+u=J(LZIT z%D7$U9wdoTprf`AEv?s(TfWrr71wjSET@+Gww-^M)n9rwth^O0OW^e!teBqg4Ce1C z8Zum{r6@@Y0qV@ox_ny2b(6dstYyC(N^gnLD$mD`?^?wplUqE;!z7z#@m!9XM$q-M zRy#cd!k;^A%O1h65IYVvfzgwxn}umWSJ{75dTebFpcW7;oDO0=oGrP2;})W~*u<(o zHET%w`PvjxQzt;dv9xl3cSm3=_=bei*#mvNt$zM|6i0tHRQVpZxj%+WFFOsN1*yv1N^0h|;PX*+;e!CAtwp zV#e5)q3p(*ovhu~vW&=*+fuWbF}4v#gHR|LrpQiijWx1_@LWAF{{Q3u;(r{^>*x5r znpfvs*Y~`x>pZXPJU^e$2c`DiaJd5kfIy7|DA&uQlyAN7kW6(|z(`-dGbAuUwmOmp zq5wv;=)Y*qoQ~277{_2I+N?{VWB=VI7yiNo$NJttMr7vQh^#QShL#YELD z^PFtg(1)%X=)3tf8|DF6rI_n-PMNbXh2ii^2j)g}onYl97tc3Ky=y0`reMC!&8I%C zOqq}>bp{Tc<{U3MPpB~E7Y34Dyf;S#0=hToaPq~G1zaO?D`GQXj#%A&eJ!NP{M(?Q zh1Qe_+A@!FYI7s>Sv~y|Zp_)(kV&&MI_fUr| zI9}t-`msDNAlygzLL=J6JyS+o1AsxWd;di-K zP4=D<9k(!@!Y=0Qgt-L{CCH6TJ>gZZNES9j&y+#^jMyzKrEzSe>Qci(j*#{WC14G* z%FTKboois%l3^o8b=&ivXQVM*7OzbsLIcUz*bK>!OZo81*f->%~1Em%C7} zML(4=X!*>Quw#p*{m-lNl5tYuHU;dwFvs7YHt`eS(#|h-4OhyPT~w3FeQPc)d+l6- zo!s>}tcHlrQ>j*twMn_s{=NJvb6Y!RRg5nLJ@5x``WANSgx^v(YHKzt6mC^>I!H@4 zDR1-KyiVM#!sXVT!POFK+90RUl%6|)fMRB2rPC0;vEPS$2^x@9cFxFSnT(b{oik#5 zvM^{j#piT)x`|@*y#9veyWNt_)JX-^PF_3EN49&EU>l7jMEw&l-FgM(Tk(L?-T^YM z0KD~v?t&a^zGxHBV(fDG%{=YvZ6)!HW97@TlM3v*rk#dQ6;)$4$&~55A*pN9R~}dw zRGwbYcY~Zn4+Dn@wgfaMT6)`-!-=z=E_y~}_B@+h#nQtD<-y*24X&R_KZEKYNgg>7 z!%uiATIP`HU*L9auK(9K6`4oAA);2@wA%pHad#b(c;y;VrQqaFDJM%HP?$6(?$o}L zRfMep>6^l5?RV-Z&;SCv&kK0`QS@W=N(n$+oEeV)(2Hii1$<=}<+fja*jU+%WC6sVB#zeqZ7 zs)~r>Np{S@v;+N*S5ISv4=?TiYPez>&e1h%(paX$Rm2Y5JbwKFsBD2gR!}HEJmBJs zqXNY+ujJ0G!-jy9RVNEpr-ffj*z9^KM3+QTS!<+!TTDu`cncwFmPvh3f8P{$++G}9 zB~3?(fNE#h->W}Z5aFH6r&ZzAovEe&$Ij8jDdm)$`1(*O=3URPz@OOHP)%pS ze@|$J0D^~-9-JL}_SmaPWx42n+2Ysti9GRE-%o@w7wZ6$Z;OXk0+w}fzlbknDsiy4 zJKp_7+1^lzLWjJ_isk#$KyIL!D&-vDWENQ<#fQ|`~|l7h)dU-H`KK zf5d>;77Ca5R!G50?vIX5{=3@S!a>;MmXCLZYl|lD6lq9VSL%#?e!_h^PUyd_LF#s( z*=8}wKDR(;cSLBMe{DEajB!x^H;(kU^7Ik<>eg%=+@?0wE~Y%E=~$%qr@x4%8yyV? z?WLe_16j_B<0y*HdKY#4S%pOH6U1RtsryEdOLL-)pq!s@6{U);fx}P;iNZYKMXHHl ze|9)xCiY$|yD#3q{}Z;;%szbqe6viL(lrHl!k}d-aT&G)sH|V#$lJATq#_G0Xfv!E z0XC}-j(cRB^MN9W3w#dOZls=#?mA4Mc_QB*0C64~C$k_}(%}|wNUD2)=N}U9}a7 zQY=zrKhVwlhw)8J-mXfvO3q)?kC%R)-AqJ8emYn?TQLPd9z17?FjY}`@Cr9$`@mEr z&f^Ei+z{N@!qW`*>PfFMa?q!Cxtz`pOg_ICN7xW&Z$g1~tL9rY%aM65JkL<-rWE!Ieac%J; z=5A`9kWUe?J+FyM{BI5qbu;@^O`MS4??2&WdY-63#N4mBg2Gz8sddm>v1rfcHaI94 zbw9mud(B|cu!*x17w^E8aF&f?W)Ah{{|%;yEsi{3LEiwuqr%?kvqL^~EDddeyEjVZ zph{qjJ>M;z@XF#r%=O6UeenMkEGcaZYOjM52-96Jt!2I{Bm9~`%%a&^vZgvs>7yEIQrCE*HLklr~&`UdFh zmMv#G^Z4Lid_&z2XS=ot z{aqfICYbtgtBHZ@XuxWKpvj>aVfNQQOwH3;FJ7+4M(E2I@CtY4ba=pR+IS+8#1}q0 z-%SqQWV~?OWPo#WA9Cglh@HCm?+B|~Kb%E4t-@JM%o1^$butQBC&{ylF3LsWE_hg< z$3awCSMqa>130viTD-p~GA}nR4DJU)n`RMrL3#WOBai^phjwnrolB6EzKA6rR;2z& z%O6E>5;BI^$1xb{;q?3Oxfl{mogbYIj+Upb@nI_DU|ur!J4edX zmsa`2R^8Ptwi=(FcUUkjun5zkY+pJUMXd(fp;y? zWGuJmCTn>t4(rT;8maS}Zp!oH7 zhI!Oh-?%qN+?WAKXVFvnsmSuW^zPR0^=A(4|K!cX`VDmIbA}MGY&EGW&Rv6Eb9_EW zMYp56N)l+AAQIf4;S37a^A|((W2*M-E1{@L%V%B${iX#VD3gX3KS>Q;68LiS_+%mz zHxcv)P4l@vS5Z<%{bOQ3VYQs2LUn5RcKdW*ZmT%fM-XQfEBkN7^cCG$=nRFt|JfXqWVjt=Fv2 zJxP9Y%f+)-+|)gY(I{b^!SC-Rt>b^2*h>e;v;p)souVNR{^mJ}c03$6O;fw7bTfc2 z(ypgB=H81W8CQ-F`Q0CH`@)?^J9#(k=ec(FM#sGW^`bQ3Dg6-~Mdv{Z4?VoHd?K?} zi;tN7!#acoe`-nKT#dfi18zAsj0V8eUrNXTB+oKy|4P8SNo8w_tmk@ISC{8k(f8*) z&n%SY*v~wLEU9y*+Offx86I;=V%~7=;c4~pAoNNFe*2ETjxnJ7b+L?J1KUS4Law@q z2Vr}>_WnIMejXiOz!x}W447>8?akEin(gzG=hEAZ7ua{uDTJd0ff}pM@ApP53dcOOxH^OeojN!jSxohZ-o%MNuGkN4gUC3fx5F^-BSK-)Lg#lVf?x_P~c5*3T5XMKJXhH)QCPD?6E!-1d+%4H6lHz zmPNAKTEVor_BW-EQ{Hvu<9Wgv99+d;i^+2%4g|%P{6oRqgjZF2!L^GqCsjU4U{MM< z0ppjc=?$HViKCa!pN(cH5mI#ge~tb%7GNEGjOC9S$hU@iZXu(VD2v4ten5y}v)(it zai{&NPa1jvMADCVfUPej#<*E&L5u)#x|#ygiGY;v$b~>6K<%dZN1NiT9!w&Gy)wdluxXRij{gjiJ7CUN8s>IV-N|wgZ8{W=a4sQn)9kq?A0j`$h z18eQQj0{WfSlPktTd>&d#-P{nkW~TJlW`BHnq_JublJ>iNI7O(Ek8})+d0yB_$ONd zpRX1B*OUQ6S6J zi@G$ns`c6Mr`1^p=nbknH#Fe$>7=07j*!)hV6=EAP@aEaWU*lT<(74)aNuAiK26cV zeaNZnl=ncuYK}ouBwSIe`lZG^yp*_?z}ILb3?cMh%3^_8P8khUq|n&_KQx7SqjLz_g$FQvHsS%tz+iwNlh32MQ=UNsk9fr{qKiqHWKN zol9?#&Ajg)8ULF&$_6t4o2X@9ohjyMY>m2E+nUZ$@?MLZH;tOF#Mdi~n7{eB%^v%7 zpULt2RSDVNGOf*WiI$NYDZhi-Kashrg9InI9?e*j29HK_nK+aojTJ5CWMrPqR%c)W zV814ovdA2I-U@e2?xZmY4XUiL<6y{?O=Lug>T%!x+7&&2TFb9=5dnYTRUhrht52!E zTy2=i_Xoo)Fp&Bnl-Z=s5&zR)9C&^E>6>xx0M1wMB_6*va_tY=3JBs&4o(H}m}0p; zv&>3*B9iLt6NzXtj*Rzwmx{O$X9un}Xv30Fwdy|l2*I`GPGve=-f2|O`q|7d!k3zQ za~#qn4n|S&Soqj{CAt$3!MT9MnRWG^r|9)RaFG6o!22-*6)8q+gK0L^uJw!0;?7rO z1s!PtMbnJXOyUCO5a`I`TD;D6|WX|rFkO~Z#D-*1?H1SXQf`p956mtgm+s6cn{ z1GxfK)>MFMC@4d%ps=fI(5osMa!}}1C^URqT>t+u@b!1|ychoeH{imT@BW^Yk-phq JL_O#D{{o8G;M@QJ diff --git a/src/lib.rs b/src/lib.rs index 1d1914f..ba6731a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -185,6 +185,13 @@ impl Ray { dir: self.dir, } } + + pub fn reflected(&self, position: Vector, normal: &UnitVector) -> Ray { + Ray { + pos: position, + dir: self.dir.reflected(normal), + } + } } impl AlmostEqual for Ray { @@ -336,7 +343,13 @@ pub fn posunit_to_unit(value: f32) -> f32 { pub struct Radians(pub f32); -pub fn render(spheres: &[Sphere], camera: &Camera, width: usize, height: usize) -> Image { +pub fn render( + spheres: &[Sphere], + camera: &Camera, + width: usize, + height: usize, + bounces: usize, +) -> Image { let mut image = Image::new(width, height); for i in 0..width { for j in 0..height { @@ -345,19 +358,33 @@ pub fn render(spheres: &[Sphere], camera: &Camera, width: usize, height: usize) i as f32 / (width - 1) as f32, j as f32 / (height - 1) as f32, ); - let color = match closest_intersection(&spheres, &ray) { - None => Color::new_black(), - Some(intersection) => { - let brightness = intersection.normal.0.dot(&-ray.dir.0); - intersection.sphere.color * brightness - } - }; + let color = trace_ray(&spheres, &ray, bounces); image.set_color(i, j, color); } } image } +pub fn trace_ray(spheres: &[Sphere], ray: &Ray, bounces: usize) -> Color { + match closest_intersection(&spheres, &ray) { + None => Color::new_black(), + Some(intersection) => { + let brightness = intersection.normal.0.dot(&-ray.dir.0); + + let mut color = intersection.sphere.color; + if bounces > 0 { + color = color + + trace_ray( + &spheres, + &ray.reflected(intersection.position, &intersection.normal), + bounces - 1, + ); + } + color * brightness + } + } +} + pub fn closest_intersection<'a>(spheres: &'a [Sphere], ray: &Ray) -> Option> { let mut closest_hit = None; let mut closest_hit_distance = f32::MAX; diff --git a/src/main.rs b/src/main.rs index 70837a9..0b6477f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,6 @@ fn main() { aspect_ratio: 4.0 / 3.0, fovx: Radians(90.0f32.to_radians()), }; - let image = render(&spheres, &camera, 800, 600); + let image = render(&spheres, &camera, 800, 600, 3); image_to_file(&image, &mut file); } diff --git a/tests/lib.rs b/tests/lib.rs index 8469d60..0a2ca7e 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,6 +1,6 @@ use raytracer::{ - closest_intersection, image_to_file, AlmostEqual, Camera, Color, Image, Intersection, Radians, - Ray, Sphere, UnitVector, Vector, + closest_intersection, image_to_file, trace_ray, AlmostEqual, Camera, Color, Image, + Intersection, Radians, Ray, Sphere, UnitVector, Vector, }; use std::str; @@ -450,3 +450,48 @@ fn test_color_addition() { ); assert_almost_eq!(Color::new_red() + Color::new_red(), Color::new_red()); } + +#[test] +fn test_trace_ray() { + let spheres = [ + Sphere { + center: Vector { + x: 2.0, + y: 1.0, + z: 1.0, + }, + radius: 1.0, + color: Color::new_red(), + }, + Sphere { + center: Vector { + x: 4.0, + y: 4.0, + z: 1.0, + }, + radius: 1.0, + color: Color::new_green(), + }, + ]; + let ray = Ray { + pos: Vector { + x: 1.0, + y: 3.0, + z: 1.0, + }, + dir: Vector { + x: 1.0, + y: -1.0, + z: 0.0, + } + .normalized(), + }; + assert_almost_eq!( + trace_ray(&spheres, &ray, 0), + 45.0f32.to_radians().cos() * Color::new_red(), + ); + assert_almost_eq!( + trace_ray(&spheres, &ray, 1), + 45.0f32.to_radians().cos() * (Color::new_red() + Color::new_green()), + ); +}