3. Don't be afraid to write a function
Any time you use code more than once, consider throwing it off into a function. Even if the code is only one line long. Even if the code appears in several spots and doesn't really seem function-worthy.
Any time you use code more than once, consider throwing it off into a function. Even if the code is only one line long. Even if the code appears in several spots and doesn't really seem function-worthy.
4. Work on your code a little bit at a time
When you try to fix problems, avoid the temptation to make more than one edits at a time. Address the issue, and then add new code. It's tempting to hop around your code and work on several things at a time. Do those things one at a time! When you attempt to do several things at a time, you can screw up. But which thing did you goof up? You have to go back and check everything, including the related statements and functions, to ensure that they work.
When you try to fix problems, avoid the temptation to make more than one edits at a time. Address the issue, and then add new code. It's tempting to hop around your code and work on several things at a time. Do those things one at a time! When you attempt to do several things at a time, you can screw up. But which thing did you goof up? You have to go back and check everything, including the related statements and functions, to ensure that they work.
5. Break apart larger projects into several modules
No one likes to scroll through hundreds of lines of code. No one likes to read pages of printout. Unless you're totally immersed in your project and can keep everything stored in your noggin, break out functions into modules. Each file, or module, is compiled and linked separately to form the code. The benefits are that the files are smaller and if they compile and work, you no longer need to mess with them.
No one likes to scroll through hundreds of lines of code. No one likes to read pages of printout. Unless you're totally immersed in your project and can keep everything stored in your noggin, break out functions into modules. Each file, or module, is compiled and linked separately to form the code. The benefits are that the files are smaller and if they compile and work, you no longer need to mess with them.
6. Know what a pointer is
A pointer is a variable that stores a memory location. A memory location stored in a pointer references another variable. Therefore, the pointer must be initialized before it's used. When the pointer variable is prefixed by the
•
•
• Arrays are automatically referenced by their memory locations, so you can use an array name without the
• A great way to explore pointers is to use the debugger; specifically, the Watches window
A pointer is a variable that stores a memory location. A memory location stored in a pointer references another variable. Therefore, the pointer must be initialized before it's used. When the pointer variable is prefixed by the
* operator, it references the contents of the variable at the memory location.•
* declares a pointer variable•
& returns the address of a variable• Arrays are automatically referenced by their memory locations, so you can use an array name without the
& prefix to grab its address• A great way to explore pointers is to use the debugger; specifically, the Watches window
7. Use white space before condensing
Whitespaceful code is readable; whereas consice code is cool. Programmers love to bunch up statements, cramming as many of them as they can into a single line; e.g.:
Admit it: such constructions looks cool; it makes it seem like you really know how to code. But it can also be a source of woe. My advice: Split out the code before you condense it. Make liberal use of white space, especially when you first write the code.
Whitespaceful code is readable; whereas consice code is cool. Programmers love to bunch up statements, cramming as many of them as they can into a single line; e.g.:
while(putchar(*(sample++)))Admit it: such constructions looks cool; it makes it seem like you really know how to code. But it can also be a source of woe. My advice: Split out the code before you condense it. Make liberal use of white space, especially when you first write the code.
8. Know when if-else becomes switch-case
Avoid stacking up multiple if statements as it usually means that the programming logic is flawed. Any time you have many
Avoid stacking up multiple if statements as it usually means that the programming logic is flawed. Any time you have many
else-if statements, you probably need to employ the switch-case structure instead.9. When you get stuck, read your code out loud
To help you track down that bug, start reading your code aloud. Pretend that a programmer friend is sitting right next to you. Explain what your code is doing and how it works. As you talk through your code, you'll find the problem. If you don't, have your imaginary friend ask you questions during your explanation.
Don't worry about going mental. You're a programmer; you're already mental. As a bonus, talking through your code also helps you identify which portions need to have comments and what the comments should be.
To help you track down that bug, start reading your code aloud. Pretend that a programmer friend is sitting right next to you. Explain what your code is doing and how it works. As you talk through your code, you'll find the problem. If you don't, have your imaginary friend ask you questions during your explanation.
Don't worry about going mental. You're a programmer; you're already mental. As a bonus, talking through your code also helps you identify which portions need to have comments and what the comments should be.
10. Don't just comment on what the code is doing — comment on why
Duh. Of course
Again, pretend that you're explaining your code to another programmer or the future-you. Future-you will thank present-you for the effort.
a++; // increment aDuh. Of course
a is incremented. Here's a better version of that comment:a++; // skip the next item to align outputAgain, pretend that you're explaining your code to another programmer or the future-you. Future-you will thank present-you for the effort.
“There are some projects that you keep coming back to as you get more experienced. You make something that you feel proud of, and then three years later you look at it in distaste and feel you could do so much better, so you go for a remake.”
— DrPetter, Raytracers
— DrPetter, Raytracers
The problem with doing something no one has ever done before is that you have nothing to compare your work with and measure your progress against.
Where you can, you will bend the logic of the machine to your will; where you can't, your logic will be reshaped by it.
“...[O]ne of the earliest [applications] of dither came in World War II. Airplane bombers used mechanical computers to perform navigation and bomb trajectory calculations. Curiously, these computers (boxes filled with hundreds of gears and cogs) performed more accurately when flying on board the aircraft, and less well on ground. Engineers realized that the vibration from the aircraft reduced the error from sticky moving parts. Instead of moving in short jerks, they moved more continuously. Small vibrating motors were built into the computers, and their vibration was called dither from the Middle English verb "didderen", meaning "to tremble." Today, when you tap a mechanical meter to increase its accuracy, you are applying dither, and modern dictionaries define dither as a highly nervous, confused, or agitated state. In minute quantities, dither successfully makes a digitization system a little more analog in the good sense of the word.”
— Ken Pohlmann, Principles of Digital Audio
— Ken Pohlmann, Principles of Digital Audio
This media is not supported in your browser
VIEW IN TELEGRAM
Frustum culling
Frustum culling
In a game, we want to smooth animations:
Smooth animation = a high, fixed FPS (frames per second)
The GPU, like any other processor, can only do a fixed amount of work in a fixed amount of time.
A fixed FPS = a fixed time to create a frame = a fixed work budget per frame = limited things the GPU has to draws for a frame
The GPU mainly does two jobs:
• Vertex shading: related to the 3D geometric description of objects in the scene
• Pixel shading: drawing the individual pixels on the frame
We also want high quality images:
Higher image quality = more pixel shading = less vertex shading
To decrease the amount of vertex shading the CPU, which decides what should be drawn and sends them to the GPU, should skip the things outside the view cone.
Because the display is a rectangle, that view cone is a four-sided pyramid that has its point cut off; this is called a "frustum" in geometry.
Frustum cull = have the CPU skip telling the GPU to draw things outside of the viewing frustum
To a very rough approximation, an outdoors scene with a 90-degree view cone sees 1/4 of the full 360 degrees, so if we compare what would happen if we draw the full scene to drawing
only within the view cone, we skip approximately 3/4 of the vertex shading work.
Because of the way the system works, no pixel shading would have been done for culled objects, only vertex shading. So culling saves vertex shader work but not pixel shader work.
Note that frustum culling is not loading or unloading anything from the main memory. The objects still have to be loaded (in RAM) for physics, AI, etc. to be applied to them; they are
just not rendered (not sent to the GPU).
Almost every game and animated clips uses frustum culling, because it is simple, cheap and effective. It is probably the single most ubiquitous optimization found in graphics.
Generally, graphics optimization is important because it frees up GPU time to render more things, with more details. There are many ways of saving work on the GPU, such as:
• Frustum culling: not trying to draw things that can't be seen because of the view cone
• Occlusion culling: not trying to draw things that can't be seen because they're behind other things
• Level of detail: skipping small geometric details when things are far enough away those details can't be made out anyway
• Simpler mathematical approximations to the equations governing how things reflect light
— Summary of Why Frustum Culling Matters, and Why It's Not Important by nothings on Github
In a game, we want to smooth animations:
Smooth animation = a high, fixed FPS (frames per second)
The GPU, like any other processor, can only do a fixed amount of work in a fixed amount of time.
A fixed FPS = a fixed time to create a frame = a fixed work budget per frame = limited things the GPU has to draws for a frame
The GPU mainly does two jobs:
• Vertex shading: related to the 3D geometric description of objects in the scene
• Pixel shading: drawing the individual pixels on the frame
We also want high quality images:
Higher image quality = more pixel shading = less vertex shading
To decrease the amount of vertex shading the CPU, which decides what should be drawn and sends them to the GPU, should skip the things outside the view cone.
Because the display is a rectangle, that view cone is a four-sided pyramid that has its point cut off; this is called a "frustum" in geometry.
Frustum cull = have the CPU skip telling the GPU to draw things outside of the viewing frustum
To a very rough approximation, an outdoors scene with a 90-degree view cone sees 1/4 of the full 360 degrees, so if we compare what would happen if we draw the full scene to drawing
only within the view cone, we skip approximately 3/4 of the vertex shading work.
Because of the way the system works, no pixel shading would have been done for culled objects, only vertex shading. So culling saves vertex shader work but not pixel shader work.
Note that frustum culling is not loading or unloading anything from the main memory. The objects still have to be loaded (in RAM) for physics, AI, etc. to be applied to them; they are
just not rendered (not sent to the GPU).
Almost every game and animated clips uses frustum culling, because it is simple, cheap and effective. It is probably the single most ubiquitous optimization found in graphics.
Generally, graphics optimization is important because it frees up GPU time to render more things, with more details. There are many ways of saving work on the GPU, such as:
• Frustum culling: not trying to draw things that can't be seen because of the view cone
• Occlusion culling: not trying to draw things that can't be seen because they're behind other things
• Level of detail: skipping small geometric details when things are far enough away those details can't be made out anyway
• Simpler mathematical approximations to the equations governing how things reflect light
— Summary of Why Frustum Culling Matters, and Why It's Not Important by nothings on Github
Memory
Any IC that stores data for immediate use, often meaning addressable semiconductor memory, i.e. ICs consisting of silicon-based MOSFETs. Semiconductor memory is organized into memory cells.
Memory cell
An IC that stores a bit, and keeps its value until it is set or reset. The memory cell is the building block of any computer memory.
Storage devices can be categorized in three ways:
1. Random versus sequential, based on access
2. Volatile versus non-volatile, based on volatility
3. Primary versus secondary, based on usage
Any IC that stores data for immediate use, often meaning addressable semiconductor memory, i.e. ICs consisting of silicon-based MOSFETs. Semiconductor memory is organized into memory cells.
Memory cell
An IC that stores a bit, and keeps its value until it is set or reset. The memory cell is the building block of any computer memory.
Storage devices can be categorized in three ways:
1. Random versus sequential, based on access
2. Volatile versus non-volatile, based on volatility
3. Primary versus secondary, based on usage
Random access versus sequential access
The processor can access a part of the memory either directly (randomly), allowing data to be read or written in approximately the same amount of time irrespective of its physical location;
or sequentially, where the time required to read or write varies significantly, due to mechanical limitations, depending on the physical location of the data on the medium.
RAM:
• DRAM
• SRAM
SAM:
• Magnetic memory devices, e.g. hard disk drives
• Optical discs
While SAM is read in sequence, arbitrary locations can still be accessed by "seeking" to the requested location. This operation, however, is often relatively inefficient.
The processor can access a part of the memory either directly (randomly), allowing data to be read or written in approximately the same amount of time irrespective of its physical location;
or sequentially, where the time required to read or write varies significantly, due to mechanical limitations, depending on the physical location of the data on the medium.
RAM:
• DRAM
• SRAM
SAM:
• Magnetic memory devices, e.g. hard disk drives
• Optical discs
While SAM is read in sequence, arbitrary locations can still be accessed by "seeking" to the requested location. This operation, however, is often relatively inefficient.
Volatile versus non-volatile
Volatility means the memory requires power to maintain its data.
Volatile:
• DRAM
• SRAM
Non-volatile:
• Any kind of ROM
• Flash memory
• Magnetic memory devices, e.g. hard disk drives
• Optical discs
Volatility means the memory requires power to maintain its data.
Volatile:
• DRAM
• SRAM
Non-volatile:
• Any kind of ROM
• Flash memory
• Magnetic memory devices, e.g. hard disk drives
• Optical discs
Primary versus secondary
Due to their higher density at lower cost compared to RAM, as well as resistance to wear and non-volatility, SAM are more suitable for secondary data storage.
Primary:
• DRAM for main memory
• SRAM for processor cache
Secondary:
• Magnetic SAM (e.g. hard disk drives and solid-state drives)
• Optical discs
Due to their higher density at lower cost compared to RAM, as well as resistance to wear and non-volatility, SAM are more suitable for secondary data storage.
Primary:
• DRAM for main memory
• SRAM for processor cache
Secondary:
• Magnetic SAM (e.g. hard disk drives and solid-state drives)
• Optical discs