• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EDT 15:11
CET 20:11
KST 04:11
  • Home
  • Forum
  • Calendar
  • Streams
  • Liquipedia
  • Features
  • Store
  • EPT
  • TL+
  • StarCraft 2
  • Brood War
  • Smash
  • Heroes
  • Counter-Strike
  • Overwatch
  • Liquibet
  • Fantasy StarCraft
  • TLPD
  • StarCraft 2
  • Brood War
  • Blogs
Forum Sidebar
Events/Features
News
Featured News
ByuL: The Forgotten Master of ZvT29Behind the Blue - Team Liquid History Book19Clem wins HomeStory Cup 289HomeStory Cup 28 - Info & Preview13Rongyi Cup S3 - Preview & Info8
Community News
Weekly Cups (March 2-8): ByuN overcomes PvT block0GSL CK - New online series13BSL Season 224Vitality ends partnership with ONSYDE20Team Liquid Map Contest - Preparation Notice6
StarCraft 2
General
Blizzard - classic cup GSL CK - New online series Weekly Cups (March 2-8): ByuN overcomes PvT block Weekly Cups (Feb 23-Mar 1): herO doubles, 2v2 bonanza Vitality ends partnership with ONSYDE
Tourneys
Master Swan Open (Global Bronze-Master 2) RSL Season 4 announced for March-April Sparkling Tuna Cup - Weekly Open Tournament PIG STY FESTIVAL 7.0! (19 Feb - 1 Mar) $5,000 WardiTV Winter Championship 2026
Strategy
Custom Maps
Publishing has been re-enabled! [Feb 24th 2026] Map Editor closed ?
External Content
The PondCast: SC2 News & Results Mutation # 516 Specter of Death Mutation # 515 Together Forever Mutation # 514 Ulnar New Year
Brood War
General
ASL21 General Discussion BGH Auto Balance -> http://bghmmr.eu/ BSL 22 Map Contest — Submissions OPEN to March 10 BSL Season 22 battle.net problems
Tourneys
ASL Season 21 Qualifiers March 7-8 [Megathread] Daily Proleagues BWCL Season 64 Announcement [BSL22] Open Qualifier #1 - Sunday 21:00 CET
Strategy
Soma's 9 hatch build from ASL Game 2 Fighting Spirit mining rates Simple Questions, Simple Answers Zealot bombing is no longer popular?
Other Games
General Games
Nintendo Switch Thread PC Games Sales Thread Path of Exile No Man's Sky (PS4 and PC) Stormgate/Frost Giant Megathread
Dota 2
Official 'what is Dota anymore' discussion The Story of Wings Gaming
League of Legends
Heroes of the Storm
Simple Questions, Simple Answers Heroes of the Storm 2.0
Hearthstone
Deck construction bug Heroes of StarCraft mini-set
TL Mafia
Mafia Game Mode Feedback/Ideas Vanilla Mini Mafia TL Mafia Community Thread
Community
General
US Politics Mega-thread Things Aren’t Peaceful in Palestine Mexico's Drug War Russo-Ukrainian War Thread YouTube Thread
Fan Clubs
The IdrA Fan Club
Media & Entertainment
[Req][Books] Good Fantasy/SciFi books [Manga] One Piece
Sports
Formula 1 Discussion General nutrition recommendations 2024 - 2026 Football Thread Cricket [SPORT] TL MMA Pick'em Pool 2013
World Cup 2022
Tech Support
Laptop capable of using Photoshop Lightroom?
TL Community
The Automated Ban List
Blogs
FS++
Kraekkling
Shocked by a laser…
Spydermine0240
Gaming-Related Deaths
TrAiDoS
ONE GREAT AMERICAN MARINE…
XenOsky
Unintentional protectionism…
Uldridge
ASL S21 English Commentary…
namkraft
Customize Sidebar...

Website Feedback

Closed Threads



Active: 1306 users

A little excercise in optimization and math

Blogs > fmod
Post a Reply
fmod
Profile Blog Joined November 2013
Cayman Islands330 Posts
Last Edited: 2014-03-08 01:35:44
March 08 2014 01:35 GMT
#1
Today I was reading some code for atmospheric lighting. Glancing over the code, I noticed this: (I did rename a couple of things).

+ Show Spoiler +
// As the y tex coord goes from 0 to 1, the angle goes from 0 to 180 degrees
float fCos = 1 - (nAngle + nAngle) / (float)mHeight;
float fAngle = std::acos(fCos);
vec3 ray(std::sin(fAngle), std::cos(fAngle), 0);

for(int nHeight=0; nHeight < nSize; nHeight++)
{
// As the x tex coord goes from 0 to 1, the height goes from the bottom of the atmosphere to the top
float fHeight = delta + innerRadius + ((outerRadius - innerRadius) * nHeight) / mWidth;

// The position of the camera
vec3 eyepos(0, fHeight, 0);

// If the ray from vPos heading in the vRay direction intersects the inner
// radius (i.e. the planet), then this spot is not visible from the viewpoint
float B = 2.0f * dot(eyepos, ray);
float Bsq = B * B;
float Cpart = dot(eyepos, eyepos);
float C = Cpart - innerRadius*innerRadius;
float discr = Bsq - 4.0f * C;
bool bVisible = (fDet < 0 || (0.5f * (-B - std::sqrt(discr)) <= 0) && (0.5f * (-B + std::sqrt(discr)) <= 0));


What it does is pretty obvious, first it finds some cosine and sine to a particular angle, then applies the quadratic formula to solve the intersection of a ray with the planet.
If you know something about trigonometry, this will bother you a lot :

float fAngle = acosf(fCos);
vec3 ray(std::sin(fAngle), std::cos(fAngle), 0);

It does seem a little strange to call an inverse cosine only to take it's cosine again the next instruction, and of course we can replace it by fCos.
Secondly, we can eliminate the acos call entirely by using the pythagorean identity :

[image loading]
you can easily see how you can solve this to get sin(angle)

float fCos = 1 - (nAngle + nAngle) / (float)mHeight;
vec3 ray(std::sqrt(1 - fCos*fCos), fCos, 0);


secondly is the quadratic formula, to solve the intersection of the ray with the sphere. What most people forget to do is to remove all the 2, 4, 0.5 coefficients which will cancel each other anyway.
we get:

float B = dot(eyepos, ray);
float Bsq = B * B;
float Cpart = dot(eyepos, eyepos);
float C = Cpart - innerRadius*innerRadius;
float discr = Bsq - C;
bool bVisible = discr < 0 || -B - std::sqrt(discr) <= 0) && -B + std::sqrt(discr) <= 0;

Now you might look at the bVisible boolean expression and wonder if it also can't be simplified any further, and yes indeed it is possible. In particular, the factors between the && signs:
We start by letting D = sqrt(discr) and multiplying both expressions by -1 and we get:

D + B >= 0 && -D + B >= 0

suppose the case that the left hand side is false, e.g D + B <= 0, if we subtract 2D from both sides of this equation we get

-D + B <= -2D <= 0

,which means the right hand side will also be false.
since -D + B < D + B, when the right hand side IS true, the lhs will also be true.

this allows us to write the expression as :
 bVisible = discr < 0 || B >= std::sqrt(discr); 



Hope you enjoyed reading it and learned something

*****
I don't particularly like you.
-Kaiser-
Profile Blog Joined November 2011
Canada932 Posts
March 08 2014 07:28 GMT
#2
I think you're smarter than me.
3 Hatch Before Cool
TheEmulator
Profile Blog Joined July 2010
28099 Posts
March 08 2014 08:17 GMT
#3
On March 08 2014 16:28 -Kaiser- wrote:
I think you're smarter than me.

Makes two of us
Administrator
Biolunar
Profile Joined February 2012
Germany224 Posts
Last Edited: 2014-03-08 08:37:59
March 08 2014 08:37 GMT
#4
On March 08 2014 10:35 fmod wrote:
float fCos = 1 - (nAngle + nAngle) / (float)mHeight;


Make that a
static_cast<float>(mHeight)
and I am happy

Btw replacing any sine/cosine functions from the standard library is always a good idea. I’ve read that they are pretty buggy if the argument gets too high, but I haven’t checked myself.
What is best? To crush the Zerg, see them driven before you, and hear the lamentations of the Protoss.
Clazziquai10
Profile Blog Joined August 2011
Singapore1949 Posts
March 08 2014 13:07 GMT
#5
I'm a computer science major and I have no idea what's going on here *hangs head in shame*
Mr. Wiggles
Profile Blog Joined August 2010
Canada5894 Posts
March 08 2014 18:13 GMT
#6
I'd be interested in seeing how much of a difference this makes in terms of performance in addition to cleaning up the code. You save yourself several calculations here by making the code simpler.

Did you profile the code at all to compare its performance before and after improving it? It would be cool to see that by applying some more math to the problem, you're not only able to improve the code readability and clarity, but also the performance.
you gotta dance
Hryul
Profile Blog Joined March 2011
Austria2609 Posts
Last Edited: 2014-03-08 19:20:58
March 08 2014 19:17 GMT
#7
the thing that interested me most was how you managed to impelement TeX code here. Then I found out it was a pasted pic
Edit: not that the other stuff is uninteresting. math is a useful skill toi have.
Countdown to victory: 1 200!
Cyx.
Profile Joined November 2010
Canada806 Posts
March 08 2014 19:38 GMT
#8
Since you already have Bsq you could save yourself one more call to std::sqrt() by writing the last expression as

bVisible = discr < 0 || Bsq >= discr;

BirdKiller
Profile Joined January 2011
United States428 Posts
Last Edited: 2014-03-08 22:19:56
March 08 2014 22:16 GMT
#9
On March 09 2014 03:13 Mr. Wiggles wrote:
I'd be interested in seeing how much of a difference this makes in terms of performance in addition to cleaning up the code. You save yourself several calculations here by making the code simpler.

Did you profile the code at all to compare its performance before and after improving it? It would be cool to see that by applying some more math to the problem, you're not only able to improve the code readability and clarity, but also the performance.


We can estimate the theoretical relative performance decrease/increase by looking into the computational complexity of each of the operations and functions. For example, suppose the functions and operations like addition, sin, square root, etc., follow the complexity linked here:

http://en.wikipedia.org/wiki/Computational_complexity_of_mathematical_operations

In the original code, the first block that we looked into called 3 functions/operations: arccos, sin, cos. This has a combined time complexity of 3 * O(log(n)^2 * M(n)). In complexity arithmetic, we don't care about constants so the block has a complexity of O(log(n)^2 * M(n)). Don't worry about what M(n) is; we're just comparing, not computing.

In the modified code, the first block now calls several functions/operations with equivalent complexity: subtraction x2, addition, division, and square root. This has a combined time complexity of O(M(n)).

Not even knowing which multiplication algorithm the program/compiler is using, we can then argue that the modified code is faster by a factor of log(n)^2. This is quite small I would say. However, this is under A LOT of assumptions, chiefly that the compiler is so dumb such that it couldn't figure this optimization out on its own and that the algorithms used for trigonometric functions is equivalent to that used by the program/compiler.
fmod
Profile Blog Joined November 2013
Cayman Islands330 Posts
March 08 2014 23:06 GMT
#10
On March 09 2014 04:38 Cyx. wrote:
Since you already have Bsq you could save yourself one more call to std::sqrt() by writing the last expression as

bVisible = discr < 0 || Bsq >= discr;


That'll only work for positive B though. The square root is assumed to be positive always. If not the early out behaviour of || will assure it never gets there,

BirdKiller you are right that these are very 'micro' optimizations. I mostly posted this because it interested me and maybe others as well. One thing though is that by avoiding (inverse) trig functions the result will usually be more accurate, apart from being faster.
I don't particularly like you.
Please log in or register to reply.
Live Events Refresh
Next event in 4h 49m
[ Submit Event ]
Live Streams
Refresh
StarCraft 2
elazer 436
JuggernautJason116
MindelVK 37
StarCraft: Brood War
Britney 19694
Calm 3406
ggaemo 238
Snow 160
Dewaltoss 136
hero 100
Shine 30
yabsab 11
Dota 2
monkeys_forever241
Counter-Strike
fl0m2979
byalli286
Heroes of the Storm
Liquid`Hasu64
Other Games
gofns33120
tarik_tv12673
Grubby2985
FrodaN1788
Beastyqt604
B2W.Neo561
ceh9484
XaKoH 164
QueenE90
Hui .85
C9.Mang081
Trikslyr59
Organizations
Other Games
gamesdonequick2084
StarCraft 2
angryscii 21
Blizzard YouTube
StarCraft: Brood War
BSLTrovo
sctven
[ Show 17 non-featured ]
StarCraft 2
• StrangeGG 76
• Kozan
• LaughNgamezSOOP
• sooper7s
• AfreecaTV YouTube
• Migwel
• intothetv
• IndyKCrew
StarCraft: Brood War
• Michael_bg 10
• STPLYoutube
• ZZZeroYoutube
• BSLYoutube
Dota 2
• lizZardDota246
League of Legends
• Nemesis7410
• TFBlade1138
Other Games
• imaqtpie1022
• Shiphtur183
Upcoming Events
PiGosaur Cup
4h 49m
GSL
14h 49m
WardiTV Team League
16h 49m
The PondCast
1d 14h
WardiTV Team League
1d 16h
Replay Cast
2 days
Replay Cast
3 days
CranKy Ducklings
3 days
RSL Revival
3 days
WardiTV Team League
3 days
[ Show More ]
uThermal 2v2 Circuit
3 days
BSL
4 days
Sparkling Tuna Cup
4 days
RSL Revival
4 days
WardiTV Team League
4 days
BSL
5 days
Replay Cast
5 days
Replay Cast
5 days
Wardi Open
5 days
Monday Night Weeklies
5 days
WardiTV Team League
6 days
Liquipedia Results

Completed

ASL Season 21: Qualifier #2
WardiTV Winter 2026
Underdog Cup #3

Ongoing

KCM Race Survival 2026 Season 1
Jeongseon Sooper Cup
Spring Cup 2026
BSL Season 22
RSL Revival: Season 4
Nations Cup 2026
ESL Pro League S23 Stage 1&2
PGL Cluj-Napoca 2026
IEM Kraków 2026
BLAST Bounty Winter 2026
BLAST Bounty Winter Qual

Upcoming

CSL Elite League 2026
ASL Season 21
Acropolis #4 - TS6
Acropolis #4
IPSL Spring 2026
CSLAN 4
HSC XXIX
uThermal 2v2 2026 Main Event
Bellum Gens Elite Stara Zagora 2026
NationLESS Cup
CS Asia Championships 2026
Asian Champions League 2026
IEM Atlanta 2026
PGL Astana 2026
BLAST Rivals Spring 2026
CCT Season 3 Global Finals
IEM Rio 2026
PGL Bucharest 2026
Stake Ranked Episode 1
BLAST Open Spring 2026
ESL Pro League S23 Finals
TLPD

1. ByuN
2. TY
3. Dark
4. Solar
5. Stats
6. Nerchio
7. sOs
8. soO
9. INnoVation
10. Elazer
1. Rain
2. Flash
3. EffOrt
4. Last
5. Bisu
6. Soulkey
7. Mini
8. Sharp
Sidebar Settings...

Advertising | Privacy Policy | Terms Of Use | Contact Us

Original banner artwork: Jim Warren
The contents of this webpage are copyright © 2026 TLnet. All Rights Reserved.