From 32689ab4cc20166d27ef7170ac653bc63645438d Mon Sep 17 00:00:00 2001 From: NADAL Jean-Baptiste Date: Tue, 27 Feb 2024 23:29:44 +0100 Subject: [PATCH] [FEAT] Add Plane Chapter 09 is done --- README.md | 6 +- apps/CMakeLists.txt | 3 + apps/chapter_09.cpp | 101 ++++++++++++++++ data/chapter_09.png | Bin 0 -> 18460 bytes raytracing/CMakeLists.txt | 1 + raytracing/include/raytracing.h | 3 +- raytracing/src/core/intersection-data.cpp | 6 +- raytracing/src/core/intersection-data.h | 4 +- raytracing/src/core/intersection.cpp | 8 +- raytracing/src/core/intersection.h | 4 +- raytracing/src/shapes/plane.cpp | 63 ++++++++++ raytracing/src/shapes/plane.h | 46 +++++++ raytracing/src/shapes/shape.cpp | 17 +-- raytracing/src/shapes/shape.h | 5 - raytracing/src/shapes/sphere.cpp | 11 +- raytracing/src/shapes/sphere.h | 2 +- tests/05_rays.cpp | 34 +++--- tests/07_making_scene.cpp | 10 +- tests/08_shadows.cpp | 4 +- tests/09_planes.cpp | 139 ++++++++++++++++++++++ 20 files changed, 399 insertions(+), 68 deletions(-) create mode 100644 apps/chapter_09.cpp create mode 100644 data/chapter_09.png create mode 100644 raytracing/src/shapes/plane.cpp create mode 100644 raytracing/src/shapes/plane.h diff --git a/README.md b/README.md index 1b54a96..a8e7723 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,6 @@ The Web Site of the book: http://raytracerchallenge.com/ | :------------------------: | :------------------------: | | ![05](data/chapter_05.png) | ![06](data/chapter_06.png) | -| Chapiter 07 | Chapiter 08 | -| :------------------------: | :----------------------------: | -| ![07](data/chapter_07.png) | ![08](data/chapter_08.png) | +| Chapiter 07 | Chapiter 08 | Chapiter 09 | +|:------------------------: | :------------------------: | :----------------------------: | +|![07](data/chapter_07.png) | ![08](data/chapter_08.png) | ![09](data/chapter_09.png) | diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 7636efd..21c1b3e 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -13,3 +13,6 @@ target_link_libraries(chapter_06 PRIVATE raytracing gcov) add_executable(chapter_07 chapter_07.cpp) target_link_libraries(chapter_07 PRIVATE raytracing gcov) + +add_executable(chapter_09 chapter_09.cpp) +target_link_libraries(chapter_09 PRIVATE raytracing gcov) \ No newline at end of file diff --git a/apps/chapter_09.cpp b/apps/chapter_09.cpp new file mode 100644 index 0000000..c7a05df --- /dev/null +++ b/apps/chapter_09.cpp @@ -0,0 +1,101 @@ +/*! + * chapter_09.cpp + * + * Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * @Author: NADAL Jean-Baptiste + * @Date: 26/02/2024 + * + */ + +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com + +#include +#include + +#include + +/* ------------------------------------------------------------------------- */ + +using namespace Raytracer; +using namespace std; + +/* ------------------------------------------------------------------------- */ + +int main(void) +{ + World the_world; + Camera the_camera; + Canvas the_canvas; + Plane *the_floor; + Sphere *the_middle, *the_right, *the_left; + chrono::time_point the_start, the_end; + + printf("Chapter 09 example.\n"); + + // Floor is an extremely flattened sphere with a matte texture. + the_floor = new Plane(); + the_floor->material().set_color(Color(1, 0.9, 0.9)); + the_floor->material().set_specular(0); + the_world.add_object(the_floor); + + // The large sphere in the middle is a unit sphere, translated upward slightly and colored green. + the_middle = new Sphere(); + the_middle->set_transform(Matrix::translation(-0.5, 1, 0.5)); + the_middle->material().set_color(Color(0.1, 1, 0.5)); + the_middle->material().set_diffuse(0.7); + the_middle->material().set_specular(0.3); + the_world.add_object(the_middle); + + // The smaller green sphere on the right is scaled in half + the_right = new Sphere(); + the_right->set_transform(Matrix::translation(1.5, 0.5, -0.5) * Matrix::scaling(0.5, 0.5, 0.5)); + the_right->material().set_color(Color(0.5, 1, 0.1)); + the_right->material().set_diffuse(0.7); + the_right->material().set_specular(0.3); + the_world.add_object(the_right); + + // The smallest sphere is scaled by a third, before being translated + the_left = new Sphere(); + the_left->set_transform(Matrix::translation(-1.5, 0.33, -0.75) * Matrix::scaling(0.33, 0.33, 0.33)); + the_left->material().set_color(Color(1, 0.8, 0.1)); + the_left->material().set_diffuse(0.7); + the_left->material().set_specular(0.3); + the_world.add_object(the_left); + + // The Light source is white, shining from above and to the left + the_world.set_light(PointLight(Tuple::Point(-10, 10, -10), Color(1, 1, 1))); + + // Configure the camera. + // the_camera = Camera(100, 50, std::numbers::pi / 2); + the_camera = Camera(320, 200, std::numbers::pi / 2); + the_camera.set_transform( + Matrix::view_transform(Tuple::Point(0, 1.5, -3.5), Tuple::Point(0, 1, 0), Tuple::Vector(0, 1, 0))); + + the_start = chrono::high_resolution_clock::now(); + the_canvas = the_camera.render(the_world); + the_end = chrono::high_resolution_clock::now(); + + the_canvas.save_to_file("chapter09.ppm"); + + chrono::duration the_elapsed_time = the_end - the_start; + printf("Execution Time: %f secondes\n", the_elapsed_time.count()); + + return 0; +} diff --git a/data/chapter_09.png b/data/chapter_09.png new file mode 100644 index 0000000000000000000000000000000000000000..037223cb70fae5c5cf32046b3cbd707418d47727 GIT binary patch literal 18460 zcmeFZ_cvVM7dL*V8VpA73`r1Ch9J685+s5I;jNAqB5H&v!RSPfBu4b;B}(*YqlW0c zmyqa!=>73o>-qix-`}5g*Sh!qu-9Gt?0wGO=e+jo?r?2QRSGf|G5`Q5)YVj;0sshm z{oaXyU*8jfVzsJu7~NC4{3#i>VL~k+YL^>r0S;JiZ>so zC#X$-t!TCL9*nOL8q9v2%Z_bhQlja^b|lm%)ZgAygNw!oDe`1uD@KDS!aCC@s@_Rf zy~9FV=#>A3$jlEHhBO_TRTjEm=y|8P_Iu{`847RznQJ)8ztA7mpI6WaF!+DBY51-$ zf)c4N49ImJ>%PNCN=K?jN(Ts#XQ-vC;p}c{1I~82jrAUJ*f=bR_znIJ`VN}&416u_ zzTO@2Kk;kfm+Ajc`2Shs|KHsBLL<3+ngBw=fkFsVQBh0AO9h68Tx0E<7*ZNOK$5gv zEI@?gs8b7sH>HH&o2LNc$z21Jcr>E$CC1>1U+cHyqk>a!7Z~OIh2I0r)Ia+B;0v{M z0H^ROxh9wG=J_bLJ#m}(>%mZ|&f-BCVB2W`F27#Rmn!aFJu1YY{226cmnmt9-0BJXDgRp+$sZEeF@3Zg-nWRxFzxWQF;0*N z_#8^86m9x^p{^}vhcOQTAB!PaFdquaa6w?GIFnE@abbr>;Cy-hjYra}mvLCXYh5PN z1b+Ng=RIF81eSw7Kk}zyHj6*;-15ykwS!Ay3U*l3MhOKipXpiL3<^4?x8iC7gKNgw9kD$j1P%?lcd#_dAUS=~;d5`c7`#Ku+aY9nf7^R{bjtdM;Fkf3TQ}gJ4 z^&$?d@W0{3u>DxPEhGQx`*RBB9WT%{Rur2n{m*e z{hSQ zH1W6>G`xATt!+}=2I21{LjAjFU+y3m)GE=xs;Nj1z1E`H@K z|D5;r39!jU`q13Gj?XmDyY6 zkPr>{Y6OMYBsV4NNWSYTlL(jS5KoOj;==k$qm+NSZiwvvoeC-)c|hPelI8U{RL7No#)8;3}%V5~K#A;E!Jz(SC~1S#`#5RsISN2{=Fh^GiR zS(APi70YOT-U`^{K!Sb)moX-2G$Im_1KX6B2; zB+WF^s}1aK^0AcPF9Ke$lPN#4?RskHZX1crzKxb#E_8ntq7OLttgN?brRLk6sQ)0j zuduj}JzUAEgEcfo3zl9l@8MQmU&X4`i7Ttp@+3wLJGjKVoOSezIy`>|Tp9>#9whMd zj{FLyXU3RZe~NJnN>Oq;7OypSIt-2aZkpS_)yCgQjM>uS3^EqLAA z^nCHK%nRU3QeU&Np4U<}(|fi>`)LHsNCD}o3pifczK~}>9HQB0<9nl5*r*wL?@rI)Jm0Z*#%o>W#+`=z`J2?PWexPE2RyvnSUIX^ zvZ9qx>r~N4wCuphPE($OpwOz%<~8h=nHG#RUFhNZD=;6f1rhVcRH_dbbk%K zIwL|Ci?dg`o6>kMY-XMeZbHajF=g11EQ<7@GLQcHFATFbvVB(Gbp9yM^fXYx_V3+x zG3M?rd#jwEwhnJQfKE5Q-`^iw9Kwbbh8=P&Ye~Bnkg7rLCrbq zg-i>`9%4xCe-oHG#ekKcLo@=yLd^vL19kVxKDdmTYYnov2Uktz`at@#Dlzrj358L* z-fbRA{ME_H)u%FxsI>vVEiV9mqItMHdQ@66zH#%jH)Bp*9G23e8wFaa-L3=0axR+jJI7XTt7w{&FEAfsax?)i5t zPUFq~nBy6asgve4^qO-hk`@SCKZu84r?Hr(KrIDGXsQ${^m1$^&+K(^IdIOg@if2`W8?TO-?s1nZ|k2x9yZxz_t*(qDuC9 zr$h@xDJ1hJ0H&Yvr=aKwX*S@qE_>@U>*`zIe_EH&f`qFbDyo`8exW<$V8w!WpS|Q9 z{dIAN0Ghn#>A+yEL|eLo`=mO+YLoFrs)+&^d88@8fOKb27;5h4C-FdcEzNAQ$!<*8 zG*`=?SxH{jESX<+QhO{u(jvy2U4@(p=Tf&u(ZdJHL}&Z6sv<=`s;>{E_Z$?P>%Lr{?_u+!#&Ej2Z6@moZr@8 zc6knm>|BNNee6xZoh_^^KJrvCCy2a&o^yam!pyv z%u>%8kJl5@@VQMVVgiCfFAl2L5cx@*)HZ5)VhjZX2Jm@(mWYBTQ#}IR!)!NjS=o1O zze*O32BL1C!X8AyKD>d-Io7-LULu>8C`phMKj+?OCPX_nk)o3=q{Ai4x!46O0B>tP z5fw9&Q#?OX=Dgt3ZE~J^5ojRG8T!j*boCjI0ks;%RnDm5^nSAxSL%kp9I$%;~Kj5DH!%1`3*d z>jOYZ*euX9B*0y(>N(;RAeXc0dv@eYRdCn$?}`9mKiigHRjIPf+bjZdo*7O3VzDAx zQFS(D#VC`~?mBAL-sQ-~ksYnIM2;XZxfOk(QFhlZ^Z@!$` zh|o*T^lXkABNT7--;NkX1a%A~0LK~Zm}SzA9QE%^0a`gW=Lu>1@4k13tWn@33yhIy zrlxIZ7BkwetV9JBB~mSfo-QEUaPeITtJ%a|m|_l?<}Y{sa#$EFY3~<&#;Gap8QOAI;+g zKCS1pucfaJSfw3&)9*B^bVw#p+-Ajs7n+|%&^Bj^^bx*K!&BM)#XF|HASHNYR(6Od zF_RvaqF(b(7Yw?LDQ=%?h1#RX$-{f5&Fk%xU3j;kN?Krq zW^BFW`@L9*{X0%=;nG=HA4a*0;iKh^pO+Yk0Y(zrR{<~bH1hagdw*R0F8ho~9iaE6 z@^R_oxst2Ft4U}x)F_b=TZfOBtCw1LN$M3jtwRpjLOw7N#FniZ6vcNgU;A=iM9t&v zR#@jybMv(>9t_g-g!tAQlcI80&pVbjQsj)P~! zO>mBht`Se{a>2P2n$Oy;~VU^p661iXwGMHYrd8>+)@w)J_(rIsu zfQ7_8e!cDY7F_UH8rtFD9S#}j(K_uyK*UmU>qt`nwCCPv?0W_*Mxn$TF9yVYXnBhN zk5QrWG!V+pWq5zAr~fxx=05e!v&>Xn9EiKFBj0YoAuYmpeUw4%@TUs5oyk1<=k>5- z_rK)|75F4T+96i2!$T>hKFNan56h0;oKKY~x-ER`?%9@x7}>imZhIHi3{??pTf1tD zAG0sY_BUMhUj2%I1KE43KLCrv3Xq&}R|mCHv-adg% zA@Vvij($wvTFhesVC9*!ziiE+U%_|uJoNM;UW8v|era0F?T_6Q4h_EFEaI;xA>qr4 ztN2RQvHfbU(y3$Z+nqNuK};`-!&}IUM4qkVSCqGX@99==PR0j8@(E%E8`BJm>rAiG zKE6ux-uimAyj>0q{3PLd;XKq4`sXjZgzbo_-4S_kJBlQ%g4s*98NM(xblg%H!C@Xk z+r}T|gw=M7Sjua%NPTnF^Rj#iP~N+jU)5lh!)&gfBD*019(1p1GpOD3{_Cx9-1kQ5 zAjjt{q#s~L^3i8Wj#sCwZl1}tP|Z%ee}-wPTtp<9?%yl8+Gb-=+7Tg6Rp~*}nmCAaXjT0xS&+;*7s*`HlC{qt~onOAa=o_|NKm9O;21)3jNx2hih0nPKy~n zB|-=SNhV;(V~c047KtK8rT`s99jmDA+*R}&tlN)K{g_Xns`}TlW3L9@nGQo1IyMoe z*ob=8xh2RltLd@6H1fd@&`(pfVls`z>9Et61;ntl7h2Alw|J(&f+T8Nq?9E0uhn5` zM`=76F_2E~r&MF%F<%bdtG*qCW(@}Jx>+h6zT3lOZWeVPR!YPuY}3If;71#AJrdx z)t>daI5;02#TJ|!#Vf{ua=vDUr{r+OMhYI{HNL#x)%aT}e2iR!wQP|*g=E}2zYj_8 zMYw%to4OE_sUXX&+9xS~2^#`z&2(<+zDco1ZIL==5lI(Rywi|=PbSfuI&k2y>GZ%C zJ^>F2$G&jbH%8qe4po!M3sFYT1X}8D{_BmA1&=n|o8y}a5{Vw!*w(SPRy6(zUHY)? zXhaYIv_SpMK=I|F0;Bk5#{1q_*#lthC#wIG9VYxtxsuR!_1~Pi>V<=-60btdS0VHr zXon7Ihhu$J%)0}Tn1)+`&dgjW=*KeD)X>VG_(~bm>cItF+x~dtV zf8fw;#NWoQqatZ|yK=|y7ytZITJj`~ymSocGfdnjx=5<@Ocz1!_IMu6fl9~_frtR$ zDQHKh1)S@?*mN49e8X=I?9JY$fhrRp2caYd{>3zI36`2af|aw1FVQZ9I-vMARCnS@ z=+yufJp)n26C0qg8;XG47{S);>;szK#qbuP?IM4^n(+|NJSY}*WJlKB;qB(%RFBRG(dzX5aInQdeD&*0@^RqS;LSPH&0yi&Rmi{H<#cIF(ZI*>ee-f-r@m@_3 zOX_&@zK|73R`$2#1)Cxc!G^MDQA8{~lg>?0BD(i-fRg$eOe6DG-#cG?J?q@TniOh2 zJr(vfNuo6DYX*bhpZI=HK*BN2fATR<&dQ&+{9$Qc)H^msa4hXyS|lb9+zn9+oG-BO z{}+P`03#BDQnd3rfIE8-18G@&aPHWGjn>z#EQ*~SyhajyX*K~_TS4>5V2YCjk!W}H z^=O`I^hWi(X%k7{mRRY{mY#qnN6X|gMqKG2lgW{$Z?~%ynyn#Z(8K1aDrVA05e1bC zxJP8u4m1kP@F^(eWxa{?>I*K7Z+M9_damTg0m5iTd zUQOWN=!gQCnnVb8CtrtCyU0lgR^HObYcOAQ=*e|xB)r7IkG6(wvDUDa-Gpf1|!frb z=H6*H8(=ll3hR;Za-@iF#z~dzeW=3K^24(-fmnA#$dJHIE|ch074z3${?=Z%!b z&m%(&D7}Cur;hr>P>@8}Vx9rJ;akPJyKVgM@OUQv*oRv_9}Zqr8st|9u@;eMe_qVx zp^x?mi`$}>S-}1{OGHw4?`E8WS$R4op(ZZ#uf}ds?9g&Fn)?d9HA!)usS>(c`0Z`J z=kn3Y*R^GmOSU24f^?x(fn#*s{+5;RKeX}=E1z&F&d&iIrb*objgpovk!_FYM=m4^ ze{Eqkb${}bSp=e6*6?BXj45CJS#u)b83+)~eD{(@_og@5BR{r1*=9kv8*l!Hp8U5- zAU5DPKu75Qh0bsH9p`3y_b8 z=3enDzR~q*uaNb2yJHy~y-Y(E+2l7gTl(jic>=9utYV)AZ(`Q<4qxB6bD=hB_NVj9 zW(jFPCpcKnS#KJ83u4ScWC`h1TS4$q?Z&Y{spK=TrCaf=KP}4YRSu*hxI~ZU51f4O z>Tat58pvB+upYYf$S41FvAq_tWu$u;rR^*iD&`BH1i=eRUDtQ80s=M^#{X+%S0S3c zv{D{T5u-@l%Wrw6i77j&_3t!tXF83{)JfSq?Ib7QxivA?y-rk~j1 zK;J{UbHiN$hPN<%c`$CXC|>4wii%$^A-qBc4vP4{_A7Au|F{61;HbOMEr0NNkl|*) z!WVF}bp`1|o*FnwQw4mbsb1oi!P%YXI!mZ%r2E9gBM}P0L+@`?C3PD@d2?<@vl<+q zx@e3D(MJ{P+Re2uYX!riaq3|q&A{I3~H_Eqq=uD2!mY$ zjp4`h;L3)U1=9Y4lqdmrba87e<32Rv%1Qi7h-X&~c;U#T4oHg5PvN-B%8w%QHd8HK zpn!wP=W|a#V=B~8`xrRpH$qX*;CUFzI~@_B*kAhGUlhl(<*!7~U@jU8M=!$q&wWE- zqKB4|BPxlRHfdrNrA!|1)WMuB6YrH2?S_q1@AF47-EU_qyE4)a2f43e>Mku?ib?-F z4`&;dX5O!PWtps-fIzj4NakvVk-lkUDDd~ZJP#rFZL|Xp3 zeDlNx*{nL9_V;4OIUvX&-6afafPNBuKRI1Hlo5uIuY|AE@4xqmE`ukJnT%1(TAtml zx@Xzcv>Yvy?se2~RK=hi)__x{aJa{95NbS~O-5hoDe9Hc=VNXB12jNb5F{=qYcS`= z*Zf&5k%yPQpydCLo1FY+?82&7dX#CiD15+@R?NQ#5kz?dxdM@K1F_C6XkQBFLj(I_ zIW~Qj^PY3mlFPN_r7qquR*Aw`#;!}No-~99PrhT`k=-k;T-wojX_%(xu?ZlS z@6yJ_E!V8+T(L_=ewaJF9He@k(tE+T5b}5NC%oee=bW__m0z)UUYKuAPsm5Ua43^w zfhdSv7CJSt7aSpgo1D?+O^RAR#8zu1aqFeP8_L8k4b1bUoyc-U-y7oKHPqYkV?Qsvx}=q7IanPN!5&#%Hi%_D8Q@hwMHDh9$@ zv2rixvSZV)l9A8`RDsfqP?;d@=V2pKEvpm~wJlF6p3N;xae;qwz4CZm(4yMd2v10H zuT3r>9KJvIJ{dSIegft!Zn&tPg^!lZ_%$_9)E1yknvX6SuqF}ND%Q_8qjGqYfmk|}FN6(r;LZ;HZ8ud!8BxS2b^&L9a#UbVPQ;9Y{5 zb`(3DPr5&nG)J#SrPC#kRqk3*8>f3IOS+S9P57EW(_Vyhgs5N#Knk=1DT|~Xq9@FK zF+x2~$<11kTlX2+{2h3Ei6L9`Jq}gFa~f_o>{q1>elm@ z{+dVAekgw6*P0h|RM}8f*s_L9=B|U6K}ZXf#0CtR7w=-&UN4}8*xm)0OlYsB!u*`OX_N}R7b zKoWyoSTXaA@ZyG`K7P$jd3jnawXGA=IY4-LL@7e?VJ6`NdQ~@Eaoc%-d9jRSXjyIZ zSb=>f*mkiF-290AAPIZF7@U}uS^0jeDXR}`*vCC#TvcaHThnH!Jq zgYXd?a0C4?2`&)><_FJbYV<5#H|u_8UX)g@V5xrvwX^BGH-_t9(=V`2`BoCz$snb2 z`+;vU4RBmYCBKRnQ$1NCwXj0QbyKnv!%1yVSkJQjaMo_X9hT!y&wx*#NNCQX2r|If zK-VuiOo1FC`PK^PXX7BYugpF_be%tJbye8aHjx}%VSd)RMiJXFK^%LQ7(xoKC+1v* z&Ypbj0}pEK@Y(ntd(i-cASLE>ZEv@Bo8gVje;*phsc4=>O-@Qpe7C-1KT%4(9MjVp zcVn;g`*(f^U$^^AdQF46!Gp7lw!uvFWIEn~*}Mj!tp*=6gK43|OIa*M_08W5dz!^3 zjeh^szXKqBEJ8gaNhN@&x?Ea4t5Z4s+1EO>z%1i$d*i=dM9(g?&QdB5$1{4Ubj;3j z>LjnU&clWHM8i7}15=oRDF+ac2F3OQ^yE-d{CiSvMBkkU$NL%LHSR}SpA4i#{}}Iu z#LNhHKfleh`XV!2_^+jZ5QwF6f;33tBMyU}`h6xnn(hPBmdUElDCO}#VFv20<~;D$ zK*epJ>{ou)CEg|{lUv6tcmCz4{sOS2 zs!}(bQ$y?@`LRUwvxmtgn1Xm(dwTVDqHPK_H+k+*Bx;i{6h;F@^ab`%nMzl{$>(+3 zugP1d1oXfx{}F& z{NQH``YoTI%hfjt={TPNQtq?(f>N+TGZePNMN3yusv9a!OUM5j1*Ld)--|1qqQi5= zm7|WfK(HXPQJ`Gqkkp zkQ&aJ=enmq^Ji^Po(lLfJHR+~5q0lEei3(JKSbRAd9Oh8^|n!M*90&~zA3E;MQ|V2 zTJLxQOn|~Zuu(${VX@C{A00JkamN};aLP4*x2vE6SmV14${((U3xCSMe;KQBo~g3{ z2(5=T!nUZSJ4l|Fn1+(RVM zd4P5)QQQCx@O8KhH_A+mIzDCSncQxm;5U)Y5XvgZww^$%N8Pp8CV5nM0Dk;r1WV~m zRn@3&<)d$6@Fs(H$#1`t;yvgcIIsLW8FCraO=D0&R`Gm|CtF5)Z90!Q!7%I)siJ58 zo^i&GWW=-i+e0zEz{(pc&%!c5g9v;m-1%VAd&433$bs(X7&)EM4){m?#_2|e*Ss=S z*DHfTMs@As&0&Gd--JFVxtPcsD!h`oV|JsXLe07yT==&W=21pH+}3$1Xuv%{&8bw| zj~WP;uE$eSw}V$0HwPaA69<6tOkSe;RW*vHXOUpoG>)iP?KpQ?m zyYralc&k>8p8TM<**o<+sA^N&lbD12i5SY*T6^-OC9I#sa;aqx2xMLs#{QI;`{5!DjE3=G{z;ecT)o8;4cIb6DU=* z{VWp!xUZ+ovNYQ2FiD@mFtu(2jR& zpq`LuOJIlOuvTY}%poJzJ7v`GyP&&J<59LOma<8sQ3RiDycBe8j`mJLZP1UKAZQtYzK`>0Od7-=_zamX|jHyONR$m>o&jJDBb@&VXW} zT#{C9t8CN?Bpr&NVK7WO@2}s(e!VUQg~>$WaqKipuS1r;uq=I72O1j~?|EBRurE?w zZi(*{={z@I68T9jT1|?3U=qd#>bPKEu@=U2pDRvdG{le1~Ww zN6po&nat1j=+(sa%&p>d|3IIlERA95G$o%Os7!eNt?gyz3ALajVIrvx2wRO8WB5@* z{(_KD4Niw(cT1XE{k^SQ9*JV(AwjwJb0nMiI)(xD0z0Yit?MY7HBFPItf zM&@rZBOJW_v&lBYN$CW%C3W7WB~|jXeKe#ZU+FPA3=-S35% z-z-eOAuXqSyD;E49zQNqhIixBXr<)KB}UJR$@#~5#x7Rb=I?ZXr59|JaP^buUIVNS zT{C}FHWRvl$c-=p&=(%f82WoPq30;5O(SlZdEm0ttC>m`S$Ly=UVu#W$Q83bVQ&^U!fpX9+KdV@TAX=KO!$fTqBaNbZF zBjnSXJrqcTG~~u{eZf7`cy}5G$xkZ@+u^IitG=W!N8p#%WW0 zLJllZxbrL51wZk*PYo@MPsQ1P3L4EQ;|qv{==!z&fMLJC6;e2wnX~GeBJo%5tj_u< zkRF^adH2qw-zm69xM*a3Ta*DiaEP_?bChOVh7A|R!l*eXq6Ha%_kn?x zu}`g72@t5_JfAXAvKXy8|BGmyutwW&s?|I?+M4tB_uhCO-gc8z=`;7q2<{JZ*IP;B zS(s3SQ!<)|Eobtkx^7@x@KclRk~Mn!gdab0)^hmxzanmI`h|XYTo!dvyRrOlukX5W z`0@6Uv=WU0-(Y}D!hZmveD^6yJmA=codAEHuQC_5M^`EQIcHL%H?Z~r*v^V*7j9ks zC0P)b-y7f2N;|VLFgCq=(&UJUd>w>Sgf1eUWMB+0=y7?Y^RX9H_kFuBWmJphk0}!+ z(3?>llxvFmHzw9rT(Oi?KNezZLS<_;ONkEiO7+bI+L>oeA8&4JpVB=G+$&d%Br(tp zGySHA`vv;sx2)*?j`mQ&oaFa61%6d>sKdJs%dq^3_ll+GfCnA;*Pg`I$5gXjkyJAX zzGe4Gb55_3d25H@PGyM#Y)=W+u`Wy?Rcgh3T2HqX2*DpJM3N-)@|Pa>RmA{UhUxB! zSdsecBgPUUY<%-(%14V)~R;$79L+;q7$B>kD+3yjzy8H2r+ ze%L2uteASsA>k+7AfY|M6i0n7u!-kB4?ZNlF37hW@)mc4urB@dL8OOLB!htwq^Sv} zKH^XOm1S-Pe_j`U{$#lArE-YIn+f@ZqiTnWQL~<-c01wsu;R7Nm_On$-&IhKImVG8 zEE7C@if4k;>iD%EJ4rd~*PlHL)%hUK*+ct!BHd%_&vz1-=X}R8#6Hc{B#l*Mzeq;D zma{6Y=)d$%vbf$s&~p{ZNJK>3NAuS>G3npxF}NeK4<(Q4T2DS_Z6xD*z)w3|pxj)rDT`zeWxUs`{;B=5n>9=d`Pxy?_VhRvO!XwZXqF50A zh5;~hf}6%MR~gRx|Beq9ulls|s(7z4cO|hE+FEzD57^5$21I>Pq!}Zj0}Xyxs!)%j z1;X-O>=NHsre}hY06ZDZ#N_aBsc=M74^`QR5Lw_Qq(Aq4W|;-kV=!|I(a{i1xDdx; zobgH4{b<~ib9ImkQ1hGU&jMspjbrKAOIPln&3V}I)#s93r)UK>-@C`PiD!>M17txG zqqt;U$UVNS0D3`ZoXn^Vtf*B<76bLtMP5!JLZnv5((dB}h`!39@nD7C@Q3mr$=hg-%ytt5vUev$LP^H|dKV-(|@WZ;}{{kZeNE z+wQuPGIWaRtLz59oWm{XL4Y41XncKp-=ovRe=c|QTappyZvT8=lBlttM~dLxKu{A> z_+7=1Jbmj8fk z$((Ie139C0=5;6U7@j`V^Z7KIroQG~O(y2$H~rK6_Kr>}4n7&@bO%5wa7((5X-@r5%RrBjCF z{Mmi1g)-B#{Y(=1!g&hBJv6UNmi+IWtd6sITAoO?;x!Iq92u4`g78zLgy)*fAnA&t ztZHMd(Au8XBI+32Jx*%CKp35P`8=37Qrkp;^8%C+==2M%-=J=bJn2oCtN&M791TgQ zwIAkXE@KqrJqY*hZZ~( zkw&w0|Ecp1e;$JPsE+`WGA$92It=rYN@55LBs!#t?~p|FP)kyNV2!KM%K%vQ6g*SC zy@@H!sj=I+PXQ-%LsR@q4}Alq|3IoFin6QnMtR?~!ZRFK!H6Mp`#-?ACaMT#`wkte zl!th`zWtp>BZb6x9Q*AK70wG zKUM0+k#^`G0r|=}W2#b+f|(ZT38fiSjpV1P=L(LUs1>OU;Ot#S81u3_q(`3WndZd3 zZWviw@Xq~9@#>=S$QWj%Nz|2kD)=Di2jWnbl}F0@+m1-cMeS{uyh9p#gOJA6db4VP z|GCdV<>b9%^KM|<>yi11AdVoawLj$!Am5t5z7d=7&h$}Zpxf8RRG+VNv8t&P)&&ZK z8mJ{i91tdgpSlcn#}=aa-Ghgb+AGi`x|;06FC-KwHW6U1{)eMotB`%7h?en#JdWO^ z!AAdqI+u|AfH)hoy$KFIc}{X3Tx2>V;QEiG#CKQ|>?Z9@9>n(N{04Ca)(%xA^_8a~ zid$#(&@-Zh>5w~RsvIxOeDiZ>2_lLj$-D}Fo+)IZf)4qN2GalqVtv0FhfLR_`2LrK zhTl`1aSe%HJ% zT7C1-o|#$!rv`tFwd;X-sI>F6L+RVacz#Qjgu&{9j=am&^cfFvV9F=J%{X1#2X^;$ z9Z|h54KB|s>_b>s;W)pIlO)4d06VrM&HWb#ntEiM(?+Y>Oo?Q?4;MF%6{x9J`yrHt zO&PC_OqY3mCAoL%theVX*p{eEk8Yx0chG*|o#JCI*!Llkaj2`M4@oGChosZ`H9go$OYO4o%bsVQa@6b1$Wq;vXGdElMt%#g2&3w z8H_u2))X4)s_YByDwW=3_|*DdabSdU^>)yD2oZPpW=CV;(O(2n3v9M@Txny+w8!AX z!>se~fjOB}u=VRHUFA}GG8A1}VEH`0R`5Ha07-Z@6|r`!X!0FYu?Y3}4$*dJkNy`s zd?)9?88i1vIP!ita0bQNOQYq%}@cvT|v@sc}?(94Ysx*%XDQ zo^Nqob3Ux|63Kk-I7%E3waXzq_~N5I-)cx}Xxo)!rG&@S#4r)Vv0*sAO9>7Old)cl z0BK501*IyfSBA*VPz4cu@1rRi*>0zq^4uzr1VVYb*u62RazW>w&X+Rwd-nDMY3HlA z3Pi;US~zUNgvr|~n%kI&x2&Da{X!7Fh_|l=zP?gRX`=3#ZG)J1hdh>wHD1WVse#HI zW+}*bc4S!D_numM(Gq(*ZyYRGzWo8C0p?G~`f7F`=tiWyLNfc`VDEmH5FK& z-5~sRc2|Txf_++dQqtW)8O%Gd>_0WQUt&M--`gTjbyy3R;}<$sbIT~6JpH`5AUwDA z<<#NB`E)*`K(9EXD1!LB)pm|?+7})p%Py->ap15GZ2*3#m)kkg@j%F&w5~l~|a!wO=E`73;)QDcg-WgekEdJm>up?wVeO2$T ztS!}u)|;jE#+dqrg2D>2WO97!nE_h-0h-VBSG2cqUQ%{MEK{!3_b?KxzwvWQ#*WiX z^K+Jh5H)k!+xE@`*04&=j#%|9kLZSf8!tFAUE{sdrMwg66!JGs{ix1PyeP5=4{Gop zjWGN*IVF=UCcpHJiED9De~6s2FIV1s`g! z&EjSgZ24VbV=uOno5CNFDEAqd7!CmCF8i+WG<;ax_Nbwj+qGStu z+HE?LPppq7XSMpu_%l>BgQa>Cmh@T1y-Zie{I~bh2_M~PDXUwd>d*h`L{AoQc~{xx z{LR8ma01I zwuzc?Wi|oGoCUeaSM{;Ak$xXSO%hjfxH44_Jm}hZPT3hmZ3ylA7sg4YP@P4RFEw1{DJ(N%z(;s?kLy)&f z%2V&&G`KszZM5BGeHnSy@w_jkET_->wV)Sl23aTqc!;IYbhX@0YH3pSwzw*4m$Q%{ zSY8sy(8e|`@#Sygw+FZR#;kb(E1%t)rC@H<-xm&ZDH-1eY#8WobN@cw!w`Ki@=IMT(Ca zaKMs`QP*7>K*J3xq?j?{1oam#JQpY6{T#4&|I`ic^vFya&Q#+4KLK3@qWa&H(3X*Y z-MTSB#s)|QLDrn+0%2JP!vn%GS_`Z-)D;NH{jaAs!04Cf1YP2^#w+? zc7n7DCL-AARFA0*z_$i!%#Oa5_x5pK_}(|l1;L^fv@IX=yK!C*y&sJ0i4z&jFbx2^ zEcn2^Y={|wN2sY|q}L-e3u=r{|51S;>oi_R&44vNcTwcVj3zKM`jz9(2%|FWk@!Tv z%MzTu%0oEQ8vwEf*VAHWeV0cVY_N6i&AG3WXE<@Q6r*@OVM%k98!n~iC+WNN5Odar zwcZmB)|_?Gy0?a)DX{i(7Z8oG!gU8gmH=>l=dwT|gserIu;?16cjCP{wmq*58Q+`Z zT^Y32)mr5LcLdMq2KIhwM??5} zF+s-n<`~0SGMpkU!K{78VdXBb9M!n7*O=ei`$6d;G{N@^?5mKohPB4X`aZ|!1c`!D z&)%Ns_XR+Z{j!e0lkd|4%eilqD$m$3!3cmx<+xrT*pUt9#*nJ7jY`FTt~0>IcVlmw z2IH`d?(Z&m(vcOObNS^>FYq`I*hT)NWz&TPc3q?y3%r+8p1DASbAA-seL|$d{CvXJ zi8XhL>#SEhA>+GqG>0f2MGk?s@0>0GT+b6e0f;QZ+s6r?@ZH|UvR)wA@pSKWSWfa< zNtkc5yxdcP0cN>}W)#r6thbi^;#=E!05}8{Cn^*R73^0TB@67N=433)a=K@Bu`BCE zNq`AtLjgkO_pc`_3<6*jkk(OeU)Pg;9aP~0g6j-|UD=?%Kk1+*0N&Y-%mgB@=8>p@ zB4o*l9QuE&6q7RWk=KCCMX?7El}7(tFYT-J@NOHw4u3#_j(C~1e7FV1y% zc;}M2e%1pBqifFt=3@nb>=*EWK=RVi6PbJ;5n}GWqdw7d4c)={U~Gc*RBKuw$g376 z&*KEHoi19$SOQ^$2(adKFc=O4WC2;1Si%4;XT7w=^VJ>6_vvTkhAybN%lp<*dxqBo z1X**^b^UbJAjk&Hn@OeC=iZxph^`k94s9JVG@>>cpS^RZKMbbJB4phg7of z>?9vMCfL&{?lQjhSVQbJ-xzE@2%7I4@nPD95w^;S@gBLFMd*9S4gixDQda<+!c)9= z5bSsYD+(T7)+{iaayD3i&^=Z7YihCq(6f118^)ssCjqZ>fAV*d``1I2Sq~75%6Gj% za2(c>9z&<~#9&b#xKQU1{vzWUW4Wdnhx1u&DsY!Y8@;zh*hvdu!dal2qog-B>({y~ z@fl;eV7r1~V8JIz_h?v8jEx@!!OUlj<+^Hlm$3vuHhA{2;GJhAZ5GPp5&_5}k(rCF zA*aMKjOAh-QWikcnmSt8;5w}H>l-lQw3DY&Hn4GaDRRAY|?vpWKHEfNT&e3)Jl1UcAE01>r)*Br?HC zU1RKV2XMU$n={{?p)E8>Lgq7uveuaEo_@Ckzz)d}xm>B-S0qp*P$V!G68QhXqUP-< S!;Uln0000normal_at(the_data.point())); the_data.set_over_point(the_data.point() + the_data.normalv() * kEpsilon); the_data.set_inside(); diff --git a/raytracing/src/core/intersection.h b/raytracing/src/core/intersection.h index a732f77..c2e394e 100644 --- a/raytracing/src/core/intersection.h +++ b/raytracing/src/core/intersection.h @@ -41,7 +41,7 @@ namespace Raytracer { public: Intersection(void); - Intersection(double a_distance_t, const Shape &a_shape); + Intersection(double a_distance_t, Shape *a_shape); Intersection(Intersection &an_intersection); Intersection(const Intersection &an_intersection); @@ -65,7 +65,7 @@ namespace Raytracer private: bool m_is_nothing; double m_distance_t; - Shape m_shape; + Shape *m_shape; }; }; // namespace Raytracer diff --git a/raytracing/src/shapes/plane.cpp b/raytracing/src/shapes/plane.cpp new file mode 100644 index 0000000..b20dc57 --- /dev/null +++ b/raytracing/src/shapes/plane.cpp @@ -0,0 +1,63 @@ +/*! + * sphere.cpp + * + * Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * @Author: NADAL Jean-Baptiste + * @Date: 05/02/2024 + * + */ + +// This is an independent project of an individual developer. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com + +/* ------------------------------------------------------------------------- */ + +#include + +#include "core/common.h" +#include "core/intersections.h" + +#include "plane.h" + +using namespace Raytracer; + +/* ------------------------------------------------------------------------- */ + +Intersections Plane::local_intersect(const Ray &a_ray) +{ + Intersections the_intersections; + + if (std::abs(a_ray.direction().y()) < kEpsilon) + { + return the_intersections; + } + + double the_t = -a_ray.origin().y() / a_ray.direction().y(); + + the_intersections.add(Intersection(the_t, this)); + + return the_intersections; +} + +/* ------------------------------------------------------------------------- */ + +Tuple Plane::local_normal_at(const Tuple &a_local_point) const +{ + return Tuple::Vector(0, 1, 0); +} diff --git a/raytracing/src/shapes/plane.h b/raytracing/src/shapes/plane.h new file mode 100644 index 0000000..122d642 --- /dev/null +++ b/raytracing/src/shapes/plane.h @@ -0,0 +1,46 @@ +/*! + * plane.h + * + * Copyright (c) 2024, NADAL Jean-Baptiste. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * + * @Author: NADAL Jean-Baptiste + * @Date: 27/02/2024 + * + */ + +#ifndef _RAYTRACER_PLANE_H +#define _RAYTRACER_PLANE_H + +/* ------------------------------------------------------------------------- */ + +#include "shapes/shape.h" + +/* ------------------------------------------------------------------------- */ + +namespace Raytracer +{ + class Plane : public Shape + { + public: + Plane(void) = default; + Intersections local_intersect(const Ray &a_ray) override; + Tuple local_normal_at(const Tuple &a_local_point) const override; + }; +}; // namespace Raytracer + +#endif // _RAYTRACER_PLANE_H diff --git a/raytracing/src/shapes/shape.cpp b/raytracing/src/shapes/shape.cpp index 42e1d4b..d942592 100644 --- a/raytracing/src/shapes/shape.cpp +++ b/raytracing/src/shapes/shape.cpp @@ -38,23 +38,21 @@ using namespace Raytracer; #define kNothing 0 -uint32_t Shape::s_current_index = 0; - /* ------------------------------------------------------------------------- */ -Shape::Shape(void) : m_id(kNothing), m_transform(Matrix::identity()) +Shape::Shape(void) : m_transform(Matrix::identity()) { } /* ------------------------------------------------------------------------- */ -Shape::Shape(Shape &a_copy) : m_id(a_copy.m_id), m_transform(a_copy.m_transform), m_material(a_copy.m_material) +Shape::Shape(Shape &a_copy) : m_transform(a_copy.m_transform), m_material(a_copy.m_material) { } /* ------------------------------------------------------------------------- */ -Shape::Shape(const Shape &a_copy) : m_id(a_copy.m_id), m_transform(a_copy.m_transform), m_material(a_copy.m_material) +Shape::Shape(const Shape &a_copy) : m_transform(a_copy.m_transform), m_material(a_copy.m_material) { } @@ -67,7 +65,6 @@ const Shape &Shape::operator=(const Shape &a_shape) return *this; } - m_id = a_shape.m_id; m_transform = a_shape.m_transform; m_material = a_shape.m_material; @@ -78,7 +75,6 @@ const Shape &Shape::operator=(const Shape &a_shape) bool Shape::operator==(const Shape &a_shape) const { - // (m_id == a_shape.m_id) && ( return (m_transform == a_shape.m_transform) && (m_material == a_shape.m_material); } @@ -159,10 +155,3 @@ Intersections Shape::local_intersect(const Ray &a_ray) return the_ret; } - -/* ------------------------------------------------------------------------- */ - -void Shape::inc_id(void) -{ - m_id = s_current_index++; -} diff --git a/raytracing/src/shapes/shape.h b/raytracing/src/shapes/shape.h index 3916e59..3ec5de0 100644 --- a/raytracing/src/shapes/shape.h +++ b/raytracing/src/shapes/shape.h @@ -66,14 +66,9 @@ namespace Raytracer Intersections intersect(const Ray &a_ray); virtual Intersections local_intersect(const Ray &a_ray); - protected: - void inc_id(void); - private: - uint32_t m_id; Matrix m_transform; Material m_material; - static uint32_t s_current_index; }; }; // namespace Raytracer diff --git a/raytracing/src/shapes/sphere.cpp b/raytracing/src/shapes/sphere.cpp index 83848c8..b653fee 100644 --- a/raytracing/src/shapes/sphere.cpp +++ b/raytracing/src/shapes/sphere.cpp @@ -39,13 +39,6 @@ using namespace Raytracer; /* ------------------------------------------------------------------------- */ -Sphere::Sphere(void) -{ - inc_id(); -} - -/* ------------------------------------------------------------------------- */ - Intersections Sphere::local_intersect(const Ray &a_ray) { Intersections the_intersections; @@ -61,8 +54,8 @@ Intersections Sphere::local_intersect(const Ray &a_ray) if (discriminant >= 0) { double the_sqrt = std::sqrt(discriminant); - the_intersections.add(Intersection((-the_b - the_sqrt) / (2 * the_a), *this)); - the_intersections.add(Intersection((-the_b + the_sqrt) / (2 * the_a), *this)); + the_intersections.add(Intersection((-the_b - the_sqrt) / (2 * the_a), this)); + the_intersections.add(Intersection((-the_b + the_sqrt) / (2 * the_a), this)); } return the_intersections; diff --git a/raytracing/src/shapes/sphere.h b/raytracing/src/shapes/sphere.h index 768b2b5..8f3bc6e 100644 --- a/raytracing/src/shapes/sphere.h +++ b/raytracing/src/shapes/sphere.h @@ -37,7 +37,7 @@ namespace Raytracer class Sphere : public Shape { public: - Sphere(void); + Sphere(void) = default; Intersections local_intersect(const Ray &a_ray) override; Tuple local_normal_at(const Tuple &a_local_point) const override; }; diff --git a/tests/05_rays.cpp b/tests/05_rays.cpp index c2be4fd..a798fc8 100644 --- a/tests/05_rays.cpp +++ b/tests/05_rays.cpp @@ -234,7 +234,7 @@ SCENARIO("An intersection encapsulates t and object", "[features/intersections.f Sphere s; WHEN("intersection(3.5,s)") { - Intersection i(3.5, s); + Intersection i(3.5, &s); THEN("i.t = 3.5") { @@ -257,7 +257,7 @@ SCENARIO("An intersection could be affected", "[features/intersections.feature]" Sphere s; AND_GIVEN("i1 <- intersection(3.5,s) and i2 <- intersection()") { - Intersection i1(3.5, s); + Intersection i1(3.5, &s); Intersection i2; WHEN("i2 <- i1") @@ -286,8 +286,8 @@ SCENARIO("Intersection could be compared", "[features/intersections.feature]") Sphere s; AND_GIVEN("i1 <- intersection(3,s) and i2 <- intersection(4,s)") { - Intersection i1(3.0, s); - Intersection i2(4.0, s); + Intersection i1(3.0, &s); + Intersection i2(4.0, &s); THEN("i2 > i1") { @@ -326,10 +326,10 @@ SCENARIO("Aggregating intersections", "[features/intersections.feature]") Sphere s; AND_GIVEN("i1 <- intersection(1,s)") { - Intersection i1(1, s); + Intersection i1(1, &s); AND_GIVEN("i2 <- intersection(2,s)") { - Intersection i2(2, s); + Intersection i2(2, &s); WHEN("xs <- intersections(i1,i2)") { Intersections xs = Intersections({i1, i2}); @@ -361,7 +361,7 @@ SCENARIO("Operations with intersections", "[features/intersections.feature]") AND_GIVEN("s <- sphere()") { Sphere s; - Intersection i1(1, s); + Intersection i1(1, &s); AND_GIVEN("xs2 <- intersections({i1})") { Intersections xs2({i1}); @@ -423,10 +423,10 @@ SCENARIO("The hit, when all intersections have positive t", "[features/intersect Sphere s; AND_GIVEN("i1 <- intersection(1,s)") { - Intersection i1(1, s); + Intersection i1(1, &s); AND_GIVEN("i2 <- intersection(2,s)") { - Intersection i2(2, s); + Intersection i2(2, &s); AND_GIVEN("xs <- intersections(i1,i2)") { Intersections xs = Intersections({i2, i1}); @@ -453,10 +453,10 @@ SCENARIO("The hit, when some intersections have negative t", "[features/intersec Sphere s; AND_GIVEN("i1 <- intersection(-1,s)") { - Intersection i1(-1, s); + Intersection i1(-1, &s); AND_GIVEN("i2 <- intersection(2,s)") { - Intersection i2(1, s); + Intersection i2(1, &s); AND_GIVEN("xs <- intersections(i1,i2)") { Intersections xs = Intersections({i2, i1}); @@ -483,10 +483,10 @@ SCENARIO("The hit, when all intersections have negative t", "[features/intersect Sphere s; AND_GIVEN("i1 <- intersection(-2,s)") { - Intersection i1(-2, s); + Intersection i1(-2, &s); AND_GIVEN("i2 <- intersection(-1,s)") { - Intersection i2(-1, s); + Intersection i2(-1, &s); AND_GIVEN("xs <- intersections(i1,i2)") { Intersections xs = Intersections({i1, i2}); @@ -514,16 +514,16 @@ SCENARIO("The hit is always the lowest nonnegative intersection", "[features/int Sphere s; AND_GIVEN("i1 <- intersection(5,s)") { - Intersection i1(5, s); + Intersection i1(5, &s); AND_GIVEN("i2 <- intersection(7,s)") { - Intersection i2(7, s); + Intersection i2(7, &s); AND_GIVEN("i3 <- intersection(-3,s)") { - Intersection i3(-3, s); + Intersection i3(-3, &s); AND_GIVEN("i4 <- intersection(2,s)") { - Intersection i4(2, s); + Intersection i4(2, &s); AND_GIVEN("xs <- intersections(i1, i2, i3, i4)") { Intersections xs = Intersections({i1, i2, i3, i4}); diff --git a/tests/07_making_scene.cpp b/tests/07_making_scene.cpp index 255a5e1..a2c9ff9 100644 --- a/tests/07_making_scene.cpp +++ b/tests/07_making_scene.cpp @@ -143,7 +143,7 @@ SCENARIO("Precompute the state of an intersection", "[features/intersections.fea Sphere shape; AND_GIVEN("i <- intersection(4, shape)") { - Intersection i(4, shape); + Intersection i(4, &shape); WHEN("comps <- prepare_computations(i,r)") { IntersectionData comps = i.prepare_computations(r); @@ -185,7 +185,7 @@ SCENARIO("The hit, when an intersection occurs on the outside", "[features/inter Sphere shape; AND_GIVEN("i <- intersection(4, shape)") { - Intersection i(4, shape); + Intersection i(4, &shape); WHEN("comps <- prepare_computations(i,r)") { IntersectionData comps = i.prepare_computations(r); @@ -211,7 +211,7 @@ SCENARIO("The hit, when an intersection occurs on the inside", "[features/inters Sphere shape; AND_GIVEN("i <- intersection(1, shape)") { - Intersection i(1, shape); + Intersection i(1, &shape); WHEN("comps <- prepare_computations(i,r)") { IntersectionData comps = i.prepare_computations(r); @@ -252,7 +252,7 @@ SCENARIO("Shading an intersection", "[features/world.feature]") Shape *shape = w.objects(0); AND_GIVEN("i <- intersection(4, shape)") { - Intersection i(4, *shape); + Intersection i(4, shape); WHEN("comps <- prepare_computations(i,r)") { IntersectionData comps = i.prepare_computations(r); @@ -289,7 +289,7 @@ SCENARIO("Shading an intersection from the inside", "[features/world.feature]") Shape *shape = w.objects(1); AND_GIVEN("i <- intersection(0.5, shape)") { - Intersection i(0.5, *shape); + Intersection i(0.5, shape); WHEN("comps <- prepare_computations(i,r)") { IntersectionData comps = i.prepare_computations(r); diff --git a/tests/08_shadows.cpp b/tests/08_shadows.cpp index 03c2c1c..2ca90bc 100644 --- a/tests/08_shadows.cpp +++ b/tests/08_shadows.cpp @@ -164,7 +164,7 @@ SCENARIO("shade_hit() is given an intersection in the shadow", "[features/world. Ray r(Tuple::Point(0, 0, 5), Tuple::Vector(0, 0, 1)); AND_GIVEN("i <- intersection(4, s2)") { - Intersection i(4, *s2); + Intersection i(4, s2); WHEN("comps <- prepare_computatons(i,r)") { IntersectionData comps = i.prepare_computations(r); @@ -200,7 +200,7 @@ SCENARIO("The hit should offset the point", "[features/intersections.feature]") shape.set_transform(Matrix::translation(0, 0, 1)); AND_GIVEN("i <- intersection(5, shape)") { - Intersection i(5, shape); + Intersection i(5, &shape); WHEN("comps <- prepare_computatons(i,r)") { IntersectionData comps = i.prepare_computations(r); diff --git a/tests/09_planes.cpp b/tests/09_planes.cpp index b7422dc..60203a0 100644 --- a/tests/09_planes.cpp +++ b/tests/09_planes.cpp @@ -244,3 +244,142 @@ SCENARIO("Computing the normal on a transformed shape", "[features/shapes.featur } } } + +/* ------------------------------------------------------------------------- */ + +SCENARIO("The normal of a plane is constant everywhere", "[features/planes.feature]") +{ + GIVEN("p <- plane()") + { + Plane p; + WHEN("n1 <- local_normal_at(p, point(0, 0, 0)))") + { + Tuple n1 = p.local_normal_at(Tuple::Point(0, 0, 0)); + AND_WHEN("n2 <- local_normal_at(p, point(10, 0, 0)))") + { + Tuple n2 = p.local_normal_at(Tuple::Point(10, 0, 0)); + AND_WHEN("n3 <- local_normal_at(p, point(-5, 0, 150)))") + { + Tuple n3 = p.local_normal_at(Tuple::Point(-5, 0, 150)); + + THEN("n1 = vector(0, 1, 0)") + { + REQUIRE(n1 == Tuple::Vector(0, 1, 0)); + } + AND_THEN("n2 = vector(0, 1, 0)") + { + REQUIRE(n1 == Tuple::Vector(0, 1, 0)); + } + AND_THEN("n3 = vector(0, 1, 0)") + { + REQUIRE(n1 == Tuple::Vector(0, 1, 0)); + } + } + } + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("Intersect with a ray parallel to the plane", "[features/planes.feature]") +{ + GIVEN("p <- plane()") + { + Plane p; + AND_GIVEN("r <- ray(point(0, 10, 0), vector(0, 0, 1))") + { + Ray r(Tuple::Point(0, 10, 0), Tuple::Vector(0, 0, 1)); + WHEN("xs <-local_intersect(p, r)") + { + Intersections xs = p.local_intersect(r); + THEN("xs is empty") + { + REQUIRE(xs.count() == 0); + } + } + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("Intersect with a coplanar ray", "[features/planes.feature]") +{ + GIVEN("p <- plane()") + { + Plane p; + AND_GIVEN("r <- ray(point(0, 0, 0), vector(0, 0, 1))") + { + Ray r(Tuple::Point(0, 0, 0), Tuple::Vector(0, 0, 1)); + WHEN("xs <-local_intersect(p, r)") + { + Intersections xs = p.local_intersect(r); + THEN("xs is empty") + { + REQUIRE(xs.count() == 0); + } + } + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("A ray Intersecting a plane from above", "[features/planes.feature]") +{ + GIVEN("p <- plane()") + { + Plane p; + AND_GIVEN("r <- ray(point(0, 1, 0), vector(0, -1, 0))") + { + Ray r(Tuple::Point(0, 1, 0), Tuple::Vector(0, -1, 0)); + WHEN("xs <-local_intersect(p, r)") + { + Intersections xs = p.local_intersect(r); + THEN("xs.count = 1") + { + REQUIRE(xs.count() == 1); + } + AND_THEN("xs[0].t = 1") + { + REQUIRE(xs[0].distance_t() == 1); + } + AND_THEN("xs[0].object = p") + { + REQUIRE(xs[0].object() == p); + } + } + } + } +} + +/* ------------------------------------------------------------------------- */ + +SCENARIO("A ray Intersecting a plane from below", "[features/planes.feature]") +{ + GIVEN("p <- plane()") + { + Plane p; + AND_GIVEN("r <- ray(point(0, -1, 0), vector(0, 1, 0))") + { + Ray r(Tuple::Point(0, -1, 0), Tuple::Vector(0, 1, 0)); + WHEN("xs <-local_intersect(p, r)") + { + Intersections xs = p.local_intersect(r); + THEN("xs.count = 1") + { + REQUIRE(xs.count() == 1); + } + AND_THEN("xs[0].t = 1") + { + REQUIRE(xs[0].distance_t() == 1); + } + AND_THEN("xs[0].object = p") + { + REQUIRE(xs[0].object() == p); + } + } + } + } +}