{"author_link":"\/users\/bootak","author_name":"BOOtak","author_uid":"bootak","comments":[],"epoch":1602192203,"event":"LD47","format":"md","ldjam_node_id":230316,"likes":14,"metadata":{"p_key":"150929","p_author":"BOOtak","p_authorkey":"1109456","p_urlkey":"367434","p_title":"Speed up 3d in TIC-80, or reimplementing decades-old tricks from scratch","p_cat":"LDJam ","p_event":"LD47","p_time":"1602192203","p_likes":"14","p_comments":"0","p_status":"WAYBACK","us_key":"1109456","us_name":"BOOtak","us_username":"bootak","event_start":"1601596800","event_key":"76","event_name":"Ludum Dare 47"},"node":{"_collation":{"body_sanitizer":"TextUtils::SanitizeHTML via existing importer","event":"LD47","removed_author":false},"_superparent":212256,"_trust":7,"author":109456,"body":"My game is made in TIC-80 fantasy console, and uses 3d \"wireframe\" graphics to draw everything. It looks fine and all, but TIC-80's Lua interpreter can't do much math and line drawing per second, especially in Web build. So I took several steps to optimize rendering, which I wanna demonstrate below. These are old tricks, but it's still kinda fun to watch how they work. Hope it'll be fun to follow my steps.\n\nTo demonstrate, I've added two debug prints to the game: line count and FPS count.\n\nSo, at the beginning, it looked like this:\n\n![init_3.gif](\/\/\/raw\/09b\/a1\/z\/39bad.gif)\n\n**Initial state: max = 470 lines per frame**\n\nHere it shows ~60 FPS, but things were much worse in Web builds. Moreover, rails are disappearing! \n\nEach rail is just a very long 3d line, and I can't render a line if one point is behind a camera. So they disappear as soon as camera is over. At first, I decided to split each long 3d line into several short ones.\n\n**Complex rails: max = 700 lines per frame**\n\nHere things started to get slow. Web version would be dead at this point. Also, lines still were disappearing right in front of a camera. Not cool.\n\nSo I wondered. If part of the line is behind a camera. Can I just draw another part, which is in front?. Well duh! Assume we have two points, p1 and p2, with coordinates (x1,y1,z1) and (x2,y2,z2), and p1 is behind a camera (so z1 < 0). Then we can calculate how much of a line we should draw, which is `z2 \/ abs(z1-z2)`. Muliply line length by that, calculate new position of p1, and boom!\n\n**Back to ~470 LPF**\n\nNext up: drawing distance. That was easy: object too far? Don't draw it! I selected drawing distance = 100. Everything with `avg(z1,z2) > 100` is ignored.\n\n**Drawing distance: 400 LPF**\n\nIt still maxes out at around 400 lines, but on average is well lower than before.\n\nNext up: Viewport! So, from side to side, the frame in a game is around 100 degrees. What if angle between given point and a camera is larger than that? Well, it won't be visible then! So why render it? If angles from camera to both points of the line were larger than 120 degrees, I didn't draw it. Calculating angle difference was a bit hard, even StackOverflow got me useful answer from the third time, but at the end everything worked fine.\n\n**Angle distance: max = 200 LPF**\n\nHuh, we just halved our lines with this one! But can we do better? Yes we can! Models simplification! When object is at a distance, we can draw it with less lines! For example, each rail is actually not one, but two lines: top and bottom ones. We can skip one of these if rail is far enough. To do this, I mark lines which can be hidden with a flag, and then check how far they are. This allow me to save couple more math operations and line drawings:\n\n![draw_angle.gif](\/\/\/raw\/09b\/a1\/z\/39bb6.gif)\n\n**Model simplification: max = 150 lines**\n\n**Bonus: change line color depending on it's distance from the camera!**\n\nYeah, we can paint lines more pale to show that they are at a distance, it's pretty easy but looks cool.\n\nSo, that was fun to code, and fun to learn new stuff. Hope you enjoyed this article, and now you better understand what is going on under the hood.\n\nYou can check out my game and see everything for yourself [here](https:\/\/ldjam.com\/events\/ludum-dare\/47\/infinite-rails)\n\nPS: It still works kinda slow on Firefox. Should I implement fixed-point maths and pre-calculated sin\/cos tables next time?","comments":1,"comments-timestamp":"2020-10-08T22:42:31Z","created":"2020-10-08T20:02:08Z","files":[],"files-timestamp":0,"id":230316,"love":14,"love-timestamp":"2020-10-09T07:06:33Z","meta":[],"modified":"2020-10-09T07:06:33Z","name":"Speed up 3d in TIC-80, or reimplementing decades-old tricks from scratch","node-timestamp":"2020-10-08T21:35:52Z","parent":222067,"parents":[1,5,9,212256,222067],"path":"\/events\/ludum-dare\/47\/infinite-rails\/speed-up-3d-in-tic-80-or-reimplementing-decades-old-tricks-from-scratch","published":"2020-10-08T21:23:23Z","scope":"public","slug":"speed-up-3d-in-tic-80-or-reimplementing-decades-old-tricks-from-scratch","subsubtype":"","subtype":"","type":"post","version":701422},"node_metadata":{"n_key":"230316","n_urlkey":"367434","n_parent":"222067","n_path":"\/events\/ludum-dare\/47\/infinite-rails\/speed-up-3d-in-tic-80-or-reimplementing-decades-old-tricks-from-scratch","n_slug":"speed-up-3d-in-tic-80-or-reimple","n_type":"post","n_subtype":"","n_subsubtype":"","n_author":"109456","n_created":"1602187328","n_modified":"1602227193","n_version":"701422","n_status":"WAYBACK"},"source_url":"https:\/\/ldjam.com\/events\/ludum-dare\/47\/infinite-rails\/speed-up-3d-in-tic-80-or-reimplementing-decades-old-tricks-from-scratch","text":"My game is made in TIC-80 fantasy console, and uses 3d \"wireframe\" graphics to draw everything. It looks fine and all, but TIC-80's Lua interpreter can't do much math and line drawing per second, especially in Web build. So I took several steps to optimize rendering, which I wanna demonstrate below. These are old tricks, but it's still kinda fun to watch how they work. Hope it'll be fun to follow my steps.\n\nTo demonstrate, I've added two debug prints to the game: line count and FPS count.\n\nSo, at the beginning, it looked like this:\n\n![init_3.gif](\/\/\/raw\/09b\/a1\/z\/39bad.gif)\n\n**Initial state: max = 470 lines per frame**\n\nHere it shows ~60 FPS, but things were much worse in Web builds. Moreover, rails are disappearing! \n\nEach rail is just a very long 3d line, and I can't render a line if one point is behind a camera. So they disappear as soon as camera is over. At first, I decided to split each long 3d line into several short ones.\n\n**Complex rails: max = 700 lines per frame**\n\nHere things started to get slow. Web version would be dead at this point. Also, lines still were disappearing right in front of a camera. Not cool.\n\nSo I wondered. If part of the line is behind a camera. Can I just draw another part, which is in front?. Well duh! Assume we have two points, p1 and p2, with coordinates (x1,y1,z1) and (x2,y2,z2), and p1 is behind a camera (so z1 < 0). Then we can calculate how much of a line we should draw, which is `z2 \/ abs(z1-z2)`. Muliply line length by that, calculate new position of p1, and boom!\n\n**Back to ~470 LPF**\n\nNext up: drawing distance. That was easy: object too far? Don't draw it! I selected drawing distance = 100. Everything with `avg(z1,z2) > 100` is ignored.\n\n**Drawing distance: 400 LPF**\n\nIt still maxes out at around 400 lines, but on average is well lower than before.\n\nNext up: Viewport! So, from side to side, the frame in a game is around 100 degrees. What if angle between given point and a camera is larger than that? Well, it won't be visible then! So why render it? If angles from camera to both points of the line were larger than 120 degrees, I didn't draw it. Calculating angle difference was a bit hard, even StackOverflow got me useful answer from the third time, but at the end everything worked fine.\n\n**Angle distance: max = 200 LPF**\n\nHuh, we just halved our lines with this one! But can we do better? Yes we can! Models simplification! When object is at a distance, we can draw it with less lines! For example, each rail is actually not one, but two lines: top and bottom ones. We can skip one of these if rail is far enough. To do this, I mark lines which can be hidden with a flag, and then check how far they are. This allow me to save couple more math operations and line drawings:\n\n![draw_angle.gif](\/\/\/raw\/09b\/a1\/z\/39bb6.gif)\n\n**Model simplification: max = 150 lines**\n\n**Bonus: change line color depending on it's distance from the camera!**\n\nYeah, we can paint lines more pale to show that they are at a distance, it's pretty easy but looks cool.\n\nSo, that was fun to code, and fun to learn new stuff. Hope you enjoyed this article, and now you better understand what is going on under the hood.\n\nYou can check out my game and see everything for yourself [here](https:\/\/ldjam.com\/events\/ludum-dare\/47\/infinite-rails)\n\nPS: It still works kinda slow on Firefox. Should I implement fixed-point maths and pre-calculated sin\/cos tables next time?","title":"Speed up 3d in TIC-80, or reimplementing decades-old tricks from scratch","wayback_source":[]}