• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EDT 02:06
CET 07:06
KST 15:06
  • 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
[ASL22] Finals Preview: Sweet Victory!9[ASL22] Ro4 Preview: Mirror Mirror6[ASL22] Ro8 Preview: Within Reach5[ASL22] Ro8 Preview: In A Tizzy11[ASL22] Ro16 Preview: Holy Diver5
Community News
Evil Geniuses - shutting down14ISSL (IntoTheTV x SOOP SC2 League): Premier5Weekly Cups (October 12-18): 5.0.17 era begins1[$1250] International ShieldBattery League75Weekly Cups (October 5-11): Farewell to 5.0.167
StarCraft 2
General
How do you feel about the mass reverts in the 5.0.17 PTR? REPORT: StarCraft 2: Remastered In Development Team Liquid Map Contest #22: Results and Winners No more SC2 streamers on team liquid? Evil Geniuses - shutting down
Tourneys
ScienceCraft (October 24-25) - Live Event Sparkling Tuna Cup - Weekly Open Tournament RSL goes to London! 2026 Offline Finals Nov 21-22 ISSL (IntoTheTV x SOOP SC2 League): Premier WORTEX Challenger Series — Open SC2 LAN in Budapes
Strategy
[H] ZvP Mid-Late Game: Stalkers Collossi HT
Custom Maps
[G] How to playtest arcade maps [A] Nemrods 1/4 players [M] (2) Sweltering Sands
External Content
Mutation # 549 Endless Sparkles The PondCast: SC2 News & Results Mutation # 548 Shining Bright Mutation # 547 Temple Of Terror
Brood War
General
Recent recommended BW games Oceanic Brood War - Join and chat! Bot on ladder BW General Discussion Sagi.gg Launcher Released
Tourneys
[Megathread] Daily Proleagues [$1250] International ShieldBattery League [ASL22] Grand Finals [BSL23] RO24 Group C
Strategy
Cliff Jump Revisited (1 in a 1000 strategy) 50,000-Word Terran Builds Memo 2026-10-22 Simple Questions, Simple Answers
Other Games
General Games
Stormgate/Frost Giant Megathread Nintendo Switch Thread Mobile Legends: Bang Bang Armies of Exigo - YesYes? General RTS Discussion Thread
Dota 2
Dota 2 Champions League Season 3 Begins April 25!
League of Legends
[TL LoL EUW IHs] Teemo shall perish
Heroes of the Storm
Heroes of the Storm 2.0
Hearthstone
Deck construction bug
TL Mafia
TL Mafia Community Thread
Community
General
Canadian Politics Mega-thread Things Aren’t Peaceful in Palestine US Politics Mega-thread European Politico-economics QA Mega-thread Russo-Ukrainian War Thread
Fan Clubs
Reynor Fan Club The Flash Fan Club Serral Fan Club
Media & Entertainment
Anime Discussion Thread Movie Discussion! [Manga] One Piece
Sports
Football (Soccer) Thread TeamLiquid Health and Fitness Initiative For 2023 MLB/Baseball 2023
World Cup 2022
Tech Support
Computer Build, Upgrade & Buying Resource Thread
TL Community
Recent Gifted Posts
Blogs
Innovate or Game Over?
TrAiDoS
ShieldBattery on Mac
Kraekkling
[ASL22] Ro4 Day1 Ticket Giv…
bITt.mAN
Can Bots Beat Pros?? Starcr…
namkraft
Customize Sidebar...

Website Feedback

Closed Threads



Active: 7947 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
28104 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 54m
[ Submit Event ]
Live Streams
Refresh
StarCraft 2
WinterStarcraft540
StarCraft: Brood War
Rain 2517
GuemChi 1616
Leta 296
ProTech162
ZergMaN 34
Noble 17
Icarus 11
League of Legends
Doublelift4274
JimRising 693
Super Smash Bros
hungrybox608
Heroes of the Storm
Trikslyr34
Other Games
summit1g9171
PiGStarcraft207
RuFF_SC274
Sick60
Organizations
Other Games
gamesdonequick517
[ Show 13 non-featured ]
StarCraft 2
• practicex 36
• AfreecaTV YouTube
• intothetv
• Kozan
• IndyKCrew
• Migwel
StarCraft: Brood War
• BSLYoutube
• STPLYoutube
• ZZZeroYoutube
Dota 2
• lizZardDota2166
League of Legends
• Stunt473
Other Games
• Scarra755
• Shiphtur567
Upcoming Events
IntoTheTV X SOOP
4h 54m
ByuN vs Lambo
MaxPax vs Bunny
PiGosaur Cup
17h 54m
The PondCast
1d 3h
Kung Fu Cup
1d 4h
IntoTheTV X SOOP
2 days
SHIN vs GuMiho
Clem vs Classic
OSC
2 days
WardiTV Invitational
3 days
GSL
3 days
Epic.LAN
3 days
Replay Cast
3 days
[ Show More ]
Sparkling Tuna Cup
4 days
Epic.LAN
4 days
Yamato Cup
5 days
Map Test Tournament
5 days
WardiTV Weekly
6 days
Replay Cast
6 days
Rogue vs Classic
Liquipedia Results

Completed

Acropolis #5 - GSC
Blizzard Classic Cup 2026
HCC Season 3

Ongoing

Acropolis #5
KCM Race Survival 2026 Season 4
International ShieldBattery League
BSL Season 23
PGL Masters Bucharest 2026
Stake Ranked Episode 5
1win Private Club #2
Thunderpick World Champ. '26
ESL Pro League Season 24
Stake Ranked Episode 4
1win Private Club #1
Logitech G Play Connect 2026
SL StarSeries Fall 2026
FISSURE Playground #3
BLAST Open Fall 2026
Esports World Cup 2026

Upcoming

IPSL Winter 2026-27
SC4ALL II: Brood War
BSL 23: Non-Korean Championship
HSC XXX
Stellar Fest 2: Lunar Cup
SC4ALL II: StarCraft II
Kung Fu Cup 2026 Grand Finals
RSL Offline Finals
eXTREMESLAND 2026
PGL Major Singapore 2026
Stake Ranked Episode 6
BLAST Rivals Fall 2026
IEM Beijing 2026
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.