Thank you all for watching, hope you enjoyed this one! Don't forget that the first 1,000 people to use this link will get a 1 month free trial of Skillshare: skl.sh/thecherno09211
The two ingredients of disaster: (1) putting a \ between root path and file name/path evn if rootpath is empty (2) leaving the rootpath empty when the current directory can be referenced via "." -- note that "./subdir/file.ext" would have worked flawlessly Tbf, "." is far less well known than the parent directory "..", so this is ultimately a failure to interface due to lack of documentation. There should be a comment somewhere that "." rather than "" should be used to specify the current dir.
The code was not broken, no debugging would have been needed if it was put in the path specified in the code. The author is a one man band, who obviously has not worked in an organization like "The Cherno" were you have to learn about sharing your code. Being a Dev is much more than writing and debugging code.
@@TheReferrer72 It's still broken. If you were to develop a game and sell it but then all the specified paths in the code is from the dev's computer, the game will not run on other computers, the game is broken.
It's nice to see how many of the bad habits you're pointing out. Things like that are so important yet so often overlooked. Particularly the thing with using int64_t instead of long long is a thing I didn't learn until I went to university and lost style marks on an assignment because of it. Loving this series!
I thought the point of "short" and "long" was that they are a known size, as opposed to int which, back in the old days, could be 16 bits. Very curious that a long might not be 32 bits, but a "long long" should always be 64, unless they start making 128 cpus or something? idk, seems like a weird thing to trip over. I like the "i32, u32, f32" etc... convention anyway.
@@jamesmnguyen Generally ‘int’ will be faster that ‘int8_t’ since it is usually the size of registers on the CPU. When you use int8_t, there’s a good chance your compiler is just bitwise ANDing an int with 0xFF whenever it’s used.
@@baileyharrison1030 I think you missed the point of my comment. I was annoyed at the ambiguity of the size of my data types. Not the performance. Which is mostly orthogonal to my problem.
Definitely a fan of a series on the raytracing in one weekend focused on speed improvements. The debugging your application for performance improvements is a rare resource!
Thank you so much for teaching me programming. Today i landed my very first big job as a software engineer. You made my life. I can't thank enough. Love you. 🥰
When parallelizing the work load should be divided as equally as possible. However, the easiest way to do that is to make the work pieces as small as possible because the work itself may not be spread evenly. In Uni there was a session to parallelize Mandelbrot set image generation using pthreads. I managed to get %200 speed using two threads (in 2012), and splitting the work more did not yield improvement, which was disappointing because I had 4 cores. My instructor took one quick look, and told me to try splitting on each row of the image (instead of splitting the work of a 800 pixel tall image into 200-400 tall chunks, it would be 1 or 2 pixels tall chunks). When a thread had finished a row of pixels, it would process the next one. This gave another boost giving me 398% performance using 4 cores. In retrospect, if one looks at the Mandelbrot set, it becomes apparent that splitting on the vertical it in the middle works fine for two, but anything else and you get uneven loads since the outer areas are much faster to compute. I have not messed much with raytracing, but imagine that certain parts of an image might require more attention, eg. glass refraction and reflection.
Yeah, the idea is that you want your threads to finish as soon as possible. In the case of this code, using vertical strips, results in each worker taking longer than they need to for specific areas. One way to counter that is by splitting them up in chunks of equally sized squares. This will free up threads as quick as possible and can tremendously speed up the processing time, since some chunks are likely to take longer (e.g. rendering lighting on a model) than other chunks (e.g. rendering a skybox).
I think splitting center out is also a good idea. Most of the detail in a scene will be in the centre and if you have some GUI that can display partial renders as they are updated then that detail is displayed more quickly so if there is something wrong on a long render you can cancel faster
If utilisation and execution time are the criteria, why not divide the work into very small pieces and have the workers grab tasks from a pool? Think blender rendering, it goes in squares. Stuff that completes faster completes faster, and the worker goes to get work sooner.
I've learned more C++ by watching 2-3 code review videos of yours, than I ever learned in high school and CS undergrad combined. thanks a lot Cherno, for these videos. and please keep making them from time to time, really appreciate it
5:37 Using relative paths vs absolute paths was like one of the first things I was taught when learning about file io. If anything, it was for making sure we wouldn't get a zero on any assignments that involved file io streams.
As a TA, when I was teaching the labs, I would demo how to use relative paths to my students. The problem is that only a fraction of the students would bother showing up for the labs unless they were made mandatory (and then for the rest of the term you would have to listen to complaints about mandatory labs yet strangely the lab's grade average was higher with mandatory labs).
29:52 I would love to see something like that! I've been exploring raytracing for a while and that blog and your videos have been a huge help. It would be great to see them together!
34:46 This is so true! Was about to write pretty much what Cherno said in the video. This can seriously cause/hide bug especially for others. Or for the writer that wrote it after a few weeks/months.
@The Cherno Great review. I agree with everything besides your point at 53:26. When I read the code I do not want to see extra 3-5 lines of code that may or may not influence the algorithm directly. The whole point of the function is to encapsulate some problem and return solution to that problem. The real problem with the "illuminate" function is the name, it updates direction, intensity and distance() of the ligh, it should be called update or genarally something more descriptive.
I never thought to make a shortcut with the intended working directory. That's a really neat trick. I kinda feel dumb since I knew the option was there but never understood when I'd need to use that feature.
Not sure if you see these comments from years ago but I NEED a Vulkan tutorial from you. You have a gift for teaching and it would be so so helpful. Good luck with Hazel :)
It sounds like your argument on a single file is that each file consists of a class and separating classes and trying to pull them together can be tough. I agree with you, needless separation makes things difficult. On the other hand, I also think a 20K line file is impossible to sort through and insanely hard to unit test since you typically have one file of unit tests per file. That'd probably be a 100K file of unit tests. The way I'd do this in JavaScript is to separate each method into a function that you can run independently so long as they belong in separate places. Makes it super easy to unit test and each one would be self-contained. But I also wouldn't be creating separate classes, interfaces, and data types for each one. I don't know what you were dealing with in the DX11 renderer, but when I looked at game engines in C++ years ago, it was insanely hard to follow as an amateur. On the other hand, I remember making some caching class in the past and remember how difficult it was to read in 6 different files with classes. I think the key here is classes. If you have smaller, reusable components, it's a lot easier to follow so long as each one is self-contained.
I fully agree with the statement about using custom file formats. I'm a researcher and almost every research application uses a custom file format for their Config file. It's an absolute nightmare. I tend to use json or yaml for Config files in all my applications.
As someone who writes lots of one-liners, I’ve come across a neat shortcut for debugging exactly what I need (in Visual Studio). You can place your cursor on what you want to debug and then press F9, this will make sure it only breaks at that specific statement. I mostly use this within LINQ lambdas in C# and haven’t tested on inline if statements, but I believe it should work. Also, I completely agree they should be avoided in favor of readability. The more experience I get in programming, the more I try to make code that is very readable, but as simple as possible. In the past I would write 5 files with lots of complications to cover every edge case, but nowadays I stray towards simpler solutions that get the job done and that my team can actually understand the code quickly. One small thing that bugs me :) why do you write member variables with m_ prefix? Isn’t the _ enough to let you know that a variable is a member variable?
I really like that series, I'm binge watching over christmas vacation :) As an amateur programmer (overstatement of the year...) I find it quite interesting not only to have your opinion, but more importantly the reason why. I particularity appreciated the compiler directive part, it made a lot of things clearer, as well as the breakpoint/if statement. Nice to see my use of "obvious" variable types isn't frown upon, I just apprec iate seeing right away how large it is. :)
For assets, I put them in the release folder, and set working dir of debug and release to be the release folder. If you want to run debug outside the IDE, you can create a symlink, and git ignore it, but generally if I am not in IDE, I don't need the debug exe.
@@MempoEdits I'm doing single image. I'm trying to make an engine that can render both polygon ray traced, and distance function ray marched geometry. Currently, doing really solid progress. I plan on implementing it into blender as a plugin. Don't know how I'll handle the ray marching scene in blender yet... What type of path tracer are you working on?
Another thing about relative paths is that files like the input files could also store paths relative to the input file rather than cwd, both of course works, but with multiple nested objects like this one might consider either of the pattern. The logic goes like if I read a file, I assume the paths in the file are relative to this file I'm reading, not the entire project
I think the issue with file paths/working directory setup not being taught properly is mostly due to the assumption that programming students already know about this by the lecturers. Self-taught people seemingly only come up against it when deploying/distributing projects and so a lot of the early stuff that they use to learn develops and embeds bad habits. As an IT Pro, I've been dealing with this subject my entire career (as simple as it sounds) but since I have started studying development this year, it has become all to clear that a lot of the more basic IT concepts such as this just seemingly aren't taught with the rigor that they should considering their relevance in the overall ecosystem.
41:13 this part has some bad issues depending on the platform. It writes size_t to the BM file but size_t is 32-bits on 32-bit systems and 64-bit on 64-bit systems so the code wont work for 32-bit systems, although it seems to coincidentally work here because of little endian and overwriting the previous bytes. Also it does unaligned memory writes, which might be fine for x86 (there is a performance penality) but for some other cpu architectures it can cause a program crash. The solution is to use int32_t/uint32_t instead of size_t and use memcpy(header + 0x2, ...) instead of *(size_t*)(header + 0x2) = ... The code wont work for big endian either, but I guess thats fine because big endian is not common.
Funny you pointed the file size, I have the same issue, I like my files in the 500-1000 line range, and I get grumpy when the code convention forces me to put one class per file.
Remember around 2000 or something I decided to have some fun and use macros in C++ to basically be able to write Visual Basic code that became C++ code. It was funny for a short while and I got some old VB code to run... But I also felt it was super stupid while doing it :)
Little hint, at least on my system on Linux and 3900X manually written intrinsics is quite a lot slower, as what the compiler does. g++ and clang will optimize SIMD instructions in, when the compiler knows it can with the right flags like -mavx2 -march=x86_64 -m64 - O3 and so on.
In the end its all about the efficiency of the acceleration structure that holds all the polygon data. Vulkan really does a great job in providing a very capable acceleration structure that is somewhat easy to use and invredibly fast. My prof at uni couldnt believe how much fastet the vulkan BVH structure is than anything his students and colleges could do in the past. Of course Raytracing Hatdware Acceleration also has a massive impact of 30-50% and is (at least with a 2080, 3080 or 6900xt) very usable in a realtime scope. Anyway a render to texture aproach with the cpu is the best way to learn raytracing and can be accelerated with the gpu quite easy.
It also means you have to write all the code to set Vulkan up. I thought getting OpenGL going sucked until I checked out what a minimal Vulkan program looked like.
@@Bobbias Yes you are right but there is already a lot of information and tutorials on how to setup vulkan and on the other hand you do not need to program an acceleration structure :)
@@BossBeneBabybuilding data structures is fun tho. BVHs and other spatial data structures in particular are pretty interesting. IMO the best way to learn c++ is to build cool data structures and play with them. one of my most instructive experiences with the language was when i tried to put a nontrivial struct into a data structure i had implemented, and i was forced to learn about move semantics and the rule of five to prevent my data structure from leaking memory or segfaulting
int - i have seen it really just covering the specified range - aka +- 32767 (yes, NOT -32768 but -32767) - some signal processing equipment. And on smaller platforms it is quit common for int to be 16bit. (But nothing hinders a platform from int being 16 byte large either) As for int64_t - similar story - that is NOT a fundamental type, the standard says (for all "int*N*_t") it only exists if and only if the system does have a 64bit 2's complement type with no padding. And it can cause problems with conversion and overloads as int64_t might be a long on one system, and long long on another. I really wished that they are not defined as basically type-defs cause i really like to have data-types where i know exactly how large they are and how that will behave with my code. For the atomic: calling load()/store() without further parameters has no advantages and behaves the same as if using the variable directly. They do come in handy (and can significantly reduce the performance-impact) when you are using different memory-orders.
A question about your Hazel engine, how do you have it so the play button works? As in, in what way do you save the state of the game to return to after done testing? I have my engine at a state of rendering a pre-defined mesh with a simple gravity system, but I wann add a play button so I can test and revert to, my guess is that you have a duplicated version of your map, and you use the main version, then load back in the duplicated version when done. Now if that's so, it might be a little harder then expected as I use unique_ptrs and idk how exactly I can work around that lol.
I'd love to see you follow the Raytracing in one weekend and explain it a bit! ABout a year ago i started programming a raytracing engine in Ruby for a school assignment (ony language i knew by that time) and i eventually got it to render normal maps, soft lights etc but only infinite planes and perfect spheres, since anything above that would have exploded render times since wasnt thinking about optimization a lot and ruby definitely isnt the way for such heavy processing :D If you were to upload that series id try to reimplement my rendere in c++, because i think i really need to learn more about low-level optimization and stuff like that. Also i always wanted to do more with c++, ive only programmed an audio plugin with JUCE, but i didnt know where to start for a custom project. I'd also love to see a follow up video of how to build a Visual Inerface to create Scene and render them!
Since you told, that you have never seen sizeof(int) != 32 bits, I wanna give you an example: the arexx rp6 robot uses an 8bit processor and its int size is 16 bit, seen on page 64 of the manual. Well it's just C, but there are few cases, where int is not 32 bits. But no one would run a raytracer on these kind of systems. Keep on making such interesting content 🙂
Instead of selecting a default file if the argument is missing it should just error out with missing file. Set the sample file in in program arguments instead.
People learning programming on Linux are more or less required to learn about paths and the working directory, as those are basics of the command line (which is far more ubiquitous in the Linux world) So, that you see so many beginners who don't understand those concepts might be, that you're audience are mainly windows users. (not trying to bash windows, but this is one of the reasons I believe Linux to be a more intuitive programming environment, when doing low level stuff (like file manipulation)
You talked about indentation styles. I think that K&R is more readable than Allman, because It does not distance the code from the function signature and binds them visually together. In general, it keeps code compact but not compressed. C was defined in K&R and Bjarne Stroustrup does also use K&R. I don't see why the Microsoft standard is the C++ standard.
I prefer Allman but the truth is: It just doesn´t matter where you put the braces as long as you put braces in there. Both versions are perfectly readable and that is the important part. If a programmer complains about where braces are I know that he or she mostlikely isn´t a very good programmer because he/she gets distracted by irrelevant things.
Coming from Java, I have to disagree on having everything in a single file. To be fair that in itself isn’t wrong, but I feel clubbing things together in a single file will make you want to also combining multiple entities in a single class, or multiple functionalities in a single function. There needs to be certain separation of concerns. But maybe that’s just my inner OOP talking xD
32:27 I had just those kind of problems when I was writing an algorithm for parsing JSON files in the C++98 standard that OpenWATCOM 1.9 uses and it was really painful to figure out how to process truncated values, invisible symbols and I haven't yet figured out how to convert pointer addresses to strings and how to process anomalies like if there is another curly braces range in the current range of strings between current curly braces and if I implement more fixes it will fuck the previous algorithms up
That rootpath should be set to the base directory of the scene file, since the paths within are relative to the scene. These types of path concatenation errors are so obscenely common that I am genuinely puzzled as to why standard libraries don't have better path manipulation functions. It's a big red flag any time you see someone appending strings with "\\".
I had this dream three weeks ago where you made this video and i was screaming at the top of my lungs "THANK YOU THANK YOU" in public at a bus stop. but the weird part is that ive never ridden a bus before
Thank you all for watching, hope you enjoyed this one! Don't forget that the first 1,000 people to use this link will get a 1 month free trial of Skillshare: skl.sh/thecherno09211
programming raytracing while having no basic understanding of working dir... I'm lost for words
Please do more university assignments! they are so informative
The two ingredients of disaster:
(1) putting a \ between root path and file name/path evn if rootpath is empty
(2) leaving the rootpath empty when the current directory can be referenced via "."
-- note that "./subdir/file.ext" would have worked flawlessly
Tbf, "." is far less well known than the parent directory "..", so this is ultimately a failure to interface due to lack of documentation. There should be a comment somewhere that "." rather than "" should be used to specify the current dir.
Remember Anakin, only a sith deals in absolute paths
You should have to delete() them - not join() them! :-)
Cherno debug review!
Plot twist: They send you broken code to test your debugging skills 😂
xD exactly!
The code was not broken, no debugging would have been needed if it was put in the path specified in the code.
The author is a one man band, who obviously has not worked in an organization like "The Cherno" were you have to learn about sharing your code.
Being a Dev is much more than writing and debugging code.
@@TheReferrer72 If i hit f5 and it doesnt run, its broken.
@@TheFlynCow exactly, thank you.
@@TheReferrer72 It's still broken. If you were to develop a game and sell it but then all the specified paths in the code is from the dev's computer, the game will not run on other computers, the game is broken.
It's nice to see how many of the bad habits you're pointing out. Things like that are so important yet so often overlooked. Particularly the thing with using int64_t instead of long long is a thing I didn't learn until I went to university and lost style marks on an assignment because of it. Loving this series!
You must have had a great professor. I wasn't even taught that these fixed types exist, and only learned this by watching Cherno videos.
I started using the fixed size types when I started to get annoyed about how big my data types were.
I thought the point of "short" and "long" was that they are a known size, as opposed to int which, back in the old days, could be 16 bits. Very curious that a long might not be 32 bits, but a "long long" should always be 64, unless they start making 128 cpus or something? idk, seems like a weird thing to trip over. I like the "i32, u32, f32" etc... convention anyway.
@@jamesmnguyen Generally ‘int’ will be faster that ‘int8_t’ since it is usually the size of registers on the CPU. When you use int8_t, there’s a good chance your compiler is just bitwise ANDing an int with 0xFF whenever it’s used.
@@baileyharrison1030 I think you missed the point of my comment. I was annoyed at the ambiguity of the size of my data types. Not the performance. Which is mostly orthogonal to my problem.
Definitely a fan of a series on the raytracing in one weekend focused on speed improvements. The debugging your application for performance improvements is a rare resource!
love to see us in the foreground lol
Thank you so much for teaching me programming. Today i landed my very first big job as a software engineer. You made my life. I can't thank enough. Love you. 🥰
30:00 Yeah definitely, the book is really well written + your explanation would be really helpful.
Not so good! He does not explain the true basics of raytracing! I strongly suggest you pbrbook for learning in a better way raytracing
@@edu_rinaldi Thanks for the recommendation. I’ll check it out.
"we're back on Windows yes!"
"what's this your computer will restart"
I died laughing
When parallelizing the work load should be divided as equally as possible. However, the easiest way to do that is to make the work pieces as small as possible because the work itself may not be spread evenly. In Uni there was a session to parallelize Mandelbrot set image generation using pthreads. I managed to get %200 speed using two threads (in 2012), and splitting the work more did not yield improvement, which was disappointing because I had 4 cores. My instructor took one quick look, and told me to try splitting on each row of the image (instead of splitting the work of a 800 pixel tall image into 200-400 tall chunks, it would be 1 or 2 pixels tall chunks). When a thread had finished a row of pixels, it would process the next one. This gave another boost giving me 398% performance using 4 cores. In retrospect, if one looks at the Mandelbrot set, it becomes apparent that splitting on the vertical it in the middle works fine for two, but anything else and you get uneven loads since the outer areas are much faster to compute. I have not messed much with raytracing, but imagine that certain parts of an image might require more attention, eg. glass refraction and reflection.
Yeah, the idea is that you want your threads to finish as soon as possible. In the case of this code, using vertical strips, results in each worker taking longer than they need to for specific areas. One way to counter that is by splitting them up in chunks of equally sized squares. This will free up threads as quick as possible and can tremendously speed up the processing time, since some chunks are likely to take longer (e.g. rendering lighting on a model) than other chunks (e.g. rendering a skybox).
I think splitting center out is also a good idea. Most of the detail in a scene will be in the centre and if you have some GUI that can display partial renders as they are updated then that detail is displayed more quickly so if there is something wrong on a long render you can cancel faster
If utilisation and execution time are the criteria, why not divide the work into very small pieces and have the workers grab tasks from a pool? Think blender rendering, it goes in squares. Stuff that completes faster completes faster, and the worker goes to get work sooner.
@@Asdayasman That's the idea. The benefit is also that if any worker fails, it's a lot less damage and makes it quicker to correct.
Did your threads wait for all other threads to finish before working on new pixels or what?
I've learned more C++ by watching 2-3 code review videos of yours, than I ever learned in high school and CS undergrad combined. thanks a lot Cherno, for these videos. and please keep making them from time to time, really appreciate it
I made a ray tracer as part of my dissertation at uni and seeing other people's just emphasises how much mine was lacking 😂
well you can always improve it. as a beg i see code as situational and it is a bias as it can get , humans improve code
Yes, please do a video on ray tracing in one weekend, I would be more than interested 😁
5:37 Using relative paths vs absolute paths was like one of the first things I was taught when learning about file io. If anything, it was for making sure we wouldn't get a zero on any assignments that involved file io streams.
Thank you so much for your review! Learned so much from it, already started to fix the code ;)
did you write that specific code?
@@judedavis92 yeah, it was shown in the intro
@@makarivashko1463 Bravo! I also took the 3d rendering class but didn't write it from scratch.
As a TA, when I was teaching the labs, I would demo how to use relative paths to my students. The problem is that only a fraction of the students would bother showing up for the labs unless they were made mandatory (and then for the rest of the term you would have to listen to complaints about mandatory labs yet strangely the lab's grade average was higher with mandatory labs).
props to the programer for sharing, and props to you Cherno. have learned so much from you.
29:52 I would love to see something like that! I've been exploring raytracing for a while and that blog and your videos have been a huge help. It would be great to see them together!
34:46 This is so true!
Was about to write pretty much what Cherno said in the video.
This can seriously cause/hide bug especially for others.
Or for the writer that wrote it after a few weeks/months.
In older 16-bit machines and older compilers I saw sizeof int being 2 bytes. Fun times.
I used to hate c style ints when I came from assembly where you work with sizes explicitly (byte, word, dword, etc..) stdint changed my c life.
+1 for the raytracing in one weekend tutorials!
I would be tottaly up to a raytracer in one weekend series
6:28 yeah, I once had the case of somebody circumventing our "no absolute paths" linter by using ".." until he was at his root...
@The Cherno Great review. I agree with everything besides your point at 53:26. When I read the code I do not want to see extra 3-5 lines of code that may or may not influence the algorithm directly. The whole point of the function is to encapsulate some problem and return solution to that problem. The real problem with the "illuminate" function is the name, it updates direction, intensity and distance() of the ligh, it should be called update or genarally something more descriptive.
I would love too see the raytracing in one weekend
A mini series on raytracing by the cherno? Count me in!
36:00 also another pitfall for that:
if(...)
if(...) x = 10;
else
x = 15;
I think some code analyzers even annotate such misleading intendations.
Oof!
That is very easy to misunderstood if you would see it only for a second :-)
@@igorthelight I think it can be misleading no matter how long you look at it if you don't know the language's grammar
Dang, that took me 5-10 seconds before I noticed what was misleading about that code snipet. I had to basically run that code to check.
In my company we have to use braces, even for 1 line ifs, It sounds pedantic but I think it does actually reduce bugs.
@@MsJavaWolf I recently made that part of my coding style. It annoys my urge to compact my code. But I know it's better in the long run.
I think the developer had a "Oh, didn't think that :p" moment when Cherno just made a shortcut and changed the Start in in the executable folder.
I would love to see you do a 3D rendering series with raytracing and stuff
yeah, the people want 3D, we've always wanted 3D
The thing I like about absolute path is that, whenever they come about, they show you a glimpse into the soul of whoever wrote them
That start-in was a useful nugget of info.
I never thought to make a shortcut with the intended working directory. That's a really neat trick. I kinda feel dumb since I knew the option was there but never understood when I'd need to use that feature.
Yes Cherno, please do a ray tracing series from the scratch. Thanks
Not sure if you see these comments from years ago but I NEED a Vulkan tutorial from you. You have a gift for teaching and it would be so so helpful. Good luck with Hazel :)
It sounds like your argument on a single file is that each file consists of a class and separating classes and trying to pull them together can be tough. I agree with you, needless separation makes things difficult. On the other hand, I also think a 20K line file is impossible to sort through and insanely hard to unit test since you typically have one file of unit tests per file. That'd probably be a 100K file of unit tests.
The way I'd do this in JavaScript is to separate each method into a function that you can run independently so long as they belong in separate places. Makes it super easy to unit test and each one would be self-contained. But I also wouldn't be creating separate classes, interfaces, and data types for each one.
I don't know what you were dealing with in the DX11 renderer, but when I looked at game engines in C++ years ago, it was insanely hard to follow as an amateur.
On the other hand, I remember making some caching class in the past and remember how difficult it was to read in 6 different files with classes. I think the key here is classes. If you have smaller, reusable components, it's a lot easier to follow so long as each one is self-contained.
Seeing your take on Ray Tracing in One Weekend would be very interesting to see!
30:00 I read the book too and I will really love to see you go through it and explain stuffs
Not multithreading in debug mode makes a lot of sense to me. Breakpoints are annoying because you will be jumping between threads.
YES please a video series about ray tracing!!
Thanks for that shortcut trick for changing working directory!
I fully agree with the statement about using custom file formats. I'm a researcher and almost every research application uses a custom file format for their Config file. It's an absolute nightmare. I tend to use json or yaml for Config files in all my applications.
As someone who writes lots of one-liners, I’ve come across a neat shortcut for debugging exactly what I need (in Visual Studio). You can place your cursor on what you want to debug and then press F9, this will make sure it only breaks at that specific statement. I mostly use this within LINQ lambdas in C# and haven’t tested on inline if statements, but I believe it should work.
Also, I completely agree they should be avoided in favor of readability. The more experience I get in programming, the more I try to make code that is very readable, but as simple as possible. In the past I would write 5 files with lots of complications to cover every edge case, but nowadays I stray towards simpler solutions that get the job done and that my team can actually understand the code quickly.
One small thing that bugs me :) why do you write member variables with m_ prefix? Isn’t the _ enough to let you know that a variable is a member variable?
I really like that series, I'm binge watching over christmas vacation :)
As an amateur programmer (overstatement of the year...) I find it quite interesting not only to have your opinion, but more importantly the reason why.
I particularity appreciated the compiler directive part, it made a lot of things clearer, as well as the breakpoint/if statement.
Nice to see my use of "obvious" variable types isn't frown upon, I just apprec iate seeing right away how large it is. :)
One of the best Code Review!
Yes on the ray tracing in one weekend!
For assets, I put them in the release folder, and set working dir of debug and release to be the release folder. If you want to run debug outside the IDE, you can create a symlink, and git ignore it, but generally if I am not in IDE, I don't need the debug exe.
You're gonna hit 400K soon! Congo in advance
Interested in the raytracing in a weekend thing!
There's also another trick using files, the first argument of the main method array is the path of the executable.
And he could have set the path in the debug options in VS. Nonetheless, great vid!
Learning from someone else's code is good, but it has to be good code. A learner is not always able to judge it :)
Indeed. Asking a beginner to interpret some esoteric uncommented ramblings is probably a waste of time, and may reinforce bad habits.
This is so creepy... I'm working on my path tracing engine right now and thought about your code review show, and the notification pops up.
😱
What’s crazier is that I finished raytracing in one weekend yesterday
My university assignment is a raytracer and I just finished it an hour before this video released...
are you doing real-time or single image? I'm working a path tracer while watching this video :D
@@MempoEdits I'm doing single image. I'm trying to make an engine that can render both polygon ray traced, and distance function ray marched geometry. Currently, doing really solid progress. I plan on implementing it into blender as a plugin. Don't know how I'll handle the ray marching scene in blender yet...
What type of path tracer are you working on?
Another thing about relative paths is that files like the input files could also store paths relative to the input file rather than cwd, both of course works, but with multiple nested objects like this one might consider either of the pattern.
The logic goes like if I read a file, I assume the paths in the file are relative to this file I'm reading, not the entire project
Would love to see the ray tracing in one weekend video
im just on the c++ series but i come and like the video to support the channel
id be extremely interested in your RayTracing series
I think the issue with file paths/working directory setup not being taught properly is mostly due to the assumption that programming students already know about this by the lecturers. Self-taught people seemingly only come up against it when deploying/distributing projects and so a lot of the early stuff that they use to learn develops and embeds bad habits.
As an IT Pro, I've been dealing with this subject my entire career (as simple as it sounds) but since I have started studying development this year, it has become all to clear that a lot of the more basic IT concepts such as this just seemingly aren't taught with the rigor that they should considering their relevance in the overall ecosystem.
YES, do the raytracing in 1 weekend video!
41:13 this part has some bad issues depending on the platform. It writes size_t to the BM file but size_t is 32-bits on 32-bit systems and 64-bit on 64-bit systems so the code wont work for 32-bit systems, although it seems to coincidentally work here because of little endian and overwriting the previous bytes. Also it does unaligned memory writes, which might be fine for x86 (there is a performance penality) but for some other cpu architectures it can cause a program crash. The solution is to use int32_t/uint32_t instead of size_t and use memcpy(header + 0x2, ...) instead of *(size_t*)(header + 0x2) = ...
The code wont work for big endian either, but I guess thats fine because big endian is not common.
Cool story, bro.
Funny you pointed the file size, I have the same issue, I like my files in the 500-1000 line range, and I get grumpy when the code convention forces me to put one class per file.
Remember around 2000 or something I decided to have some fun and use macros in C++ to basically be able to write Visual Basic code that became C++ code. It was funny for a short while and I got some old VB code to run... But I also felt it was super stupid while doing it :)
std::cout
Cherno: "were doing a ray tracing code review!"
Also cherno: spends the first 5 minutes ranting about working directories
31:50 "like json or yaml, I would use yaml for this"
TOML: "B-but.. its basically ME ALMOST!"
I love that there is #ifdef _WIN32 at 41:53
as if it was meant to be cross platform but
filenames are using backslashes and D:\\...
This is amazing! Got so much out of this review
Little hint, at least on my system on Linux and 3900X manually written intrinsics is quite a lot slower, as what the compiler does.
g++ and clang will optimize SIMD instructions in, when the compiler knows it can with the right flags like -mavx2 -march=x86_64 -m64 - O3 and so on.
In the end its all about the efficiency of the acceleration structure that holds all the polygon data. Vulkan really does a great job in providing a very capable acceleration structure that is somewhat easy to use and invredibly fast. My prof at uni couldnt believe how much fastet the vulkan BVH structure is than anything his students and colleges could do in the past. Of course Raytracing Hatdware Acceleration also has a massive impact of 30-50% and is (at least with a 2080, 3080 or 6900xt) very usable in a realtime scope. Anyway a render to texture aproach with the cpu is the best way to learn raytracing and can be accelerated with the gpu quite easy.
It also means you have to write all the code to set Vulkan up. I thought getting OpenGL going sucked until I checked out what a minimal Vulkan program looked like.
@@Bobbias Yes you are right but there is already a lot of information and tutorials on how to setup vulkan and on the other hand you do not need to program an acceleration structure :)
@@BossBeneBabybuilding data structures is fun tho. BVHs and other spatial data structures in particular are pretty interesting. IMO the best way to learn c++ is to build cool data structures and play with them. one of my most instructive experiences with the language was when i tried to put a nontrivial struct into a data structure i had implemented, and i was forced to learn about move semantics and the rule of five to prevent my data structure from leaking memory or segfaulting
Video was worth it just for the absolute paths talk alone lol
Thanks Cherno!!!
int - i have seen it really just covering the specified range - aka +- 32767 (yes, NOT -32768 but -32767) - some signal processing equipment.
And on smaller platforms it is quit common for int to be 16bit. (But nothing hinders a platform from int being 16 byte large either)
As for int64_t - similar story - that is NOT a fundamental type, the standard says (for all "int*N*_t") it only exists if and only if the system does have a 64bit 2's complement type with no padding.
And it can cause problems with conversion and overloads as int64_t might be a long on one system, and long long on another.
I really wished that they are not defined as basically type-defs cause i really like to have data-types where i know exactly how large they are and how that will behave with my code.
For the atomic:
calling load()/store() without further parameters has no advantages and behaves the same as if using the variable directly. They do come in handy (and can significantly reduce the performance-impact) when you are using different memory-orders.
Absolute path should never be constants , is what i feel, but they can be a changeable variable.
Simply amazing stuff.
Which programming languages are you willing to do code reviews for? I'm guessing C/C++, but would you review projects built in other languages?
Yep he Will review codes in all languages
@@AlexFord-gp7by ayyyyyy nice I might send in one of my projects after I polish it up a bit more
A question about your Hazel engine, how do you have it so the play button works? As in, in what way do you save the state of the game to return to after done testing? I have my engine at a state of rendering a pre-defined mesh with a simple gravity system, but I wann add a play button so I can test and revert to, my guess is that you have a duplicated version of your map, and you use the main version, then load back in the duplicated version when done. Now if that's so, it might be a little harder then expected as I use unique_ptrs and idk how exactly I can work around that lol.
I'd love to see you follow the Raytracing in one weekend and explain it a bit! ABout a year ago i started programming a raytracing engine in Ruby for a school assignment (ony language i knew by that time) and i eventually got it to render normal maps, soft lights etc but only infinite planes and perfect spheres, since anything above that would have exploded render times since wasnt thinking about optimization a lot and ruby definitely isnt the way for such heavy processing :D If you were to upload that series id try to reimplement my rendere in c++, because i think i really need to learn more about low-level optimization and stuff like that. Also i always wanted to do more with c++, ive only programmed an audio plugin with JUCE, but i didnt know where to start for a custom project. I'd also love to see a follow up video of how to build a Visual Inerface to create Scene and render them!
Since you told, that you have never seen sizeof(int) != 32 bits, I wanna give you an example: the arexx rp6 robot uses an 8bit processor and its int size is 16 bit, seen on page 64 of the manual. Well it's just C, but there are few cases, where int is not 32 bits. But no one would run a raytracer on these kind of systems.
Keep on making such interesting content 🙂
Yeah, I figured that embedded systems would probably be the ones with non-32-bit ints. Thanks for the example!
On my uni, when the delivered project doesn't run, you automatically fail the entire semester! :')
Same.
Which is a good thing.
The thumbnail makes me lose my shit. So funny
Instead of selecting a default file if the argument is missing it should just error out with missing file. Set the sample file in in program arguments instead.
People learning programming on Linux are more or less required to learn about paths and the working directory, as those are basics of the command line (which is far more ubiquitous in the Linux world)
So, that you see so many beginners who don't understand those concepts might be, that you're audience are mainly windows users. (not trying to bash windows, but this is one of the reasons I believe Linux to be a more intuitive programming environment, when doing low level stuff (like file manipulation)
What text color theme do you use? Can I download it somewhere or would I have to input it in manually? I really like the look.
It’s part of Visual Assist, I think, but slightly modified.
22:28 I'm fairly certain that's not reflection, but rather refraction.
This guy is still working. Im still procrastinating.
If you don't want to have to change the code to get it running have people send in projects in a VM image
You talked about indentation styles. I think that K&R is more readable than Allman, because It does not distance the code from the function signature and binds them visually together. In general, it keeps code compact but not compressed. C was defined in K&R and Bjarne Stroustrup does also use K&R. I don't see why the Microsoft standard is the C++ standard.
I completely agree.
I prefer Allman but the truth is: It just doesn´t matter where you put the braces as long as you put braces in there. Both versions are perfectly readable and that is the important part. If a programmer complains about where braces are I know that he or she mostlikely isn´t a very good programmer because he/she gets distracted by irrelevant things.
@@Serendipity4477 Yes I do work with both, the most important thing is to be consistent. And clean code is more than just indentation.
Coming from Java, I have to disagree on having everything in a single file. To be fair that in itself isn’t wrong, but I feel clubbing things together in a single file will make you want to also combining multiple entities in a single class, or multiple functionalities in a single function. There needs to be certain separation of concerns. But maybe that’s just my inner OOP talking xD
Cool! Hope you can rewrite the ray tracing renderer from scratch one day with c++
32:27 I had just those kind of problems when I was writing an algorithm for parsing JSON files in the C++98 standard that OpenWATCOM 1.9 uses and it was really painful to figure out how to process truncated values, invisible symbols and I haven't yet figured out how to convert pointer addresses to strings and how to process anomalies like if there is another curly braces range in the current range of strings between current curly braces and if I implement more fixes it will fuck the previous algorithms up
40:08 on the arduino platform (and maybe other avr microcontrollers) int is 2 bytes. I recently had an annoying bug caused by this :))
For some reason I thought that I'd never understand C++, but looking at the code it doesn't seem that bad
38:00
Seems like detached braces are only Unreal thing.
LLVM, Google style always attached.
I love this Wojack code
0:23 , HAHA, I understood that reference.
EXCITED!!!
100% into a video on the Ray Tracing in One Weekend
"We are back on Windows! Yes! Wait, your computer will be restarted?" LOL fomrced umpdat
I really like it!
That rootpath should be set to the base directory of the scene file, since the paths within are relative to the scene. These types of path concatenation errors are so obscenely common that I am genuinely puzzled as to why standard libraries don't have better path manipulation functions. It's a big red flag any time you see someone appending strings with "\\".
You are a saint!
I had this dream three weeks ago where you made this video and i was screaming at the top of my lungs "THANK YOU THANK YOU" in public at a bus stop. but the weird part is that ive never ridden a bus before
Hey Yan, could you give us/me a quick rundown of your hardware(keyboard, monitor, pc, etc) looking for some inspiration for my setup! thanks!