• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EST 03:07
CET 09:07
KST 17:07
  • 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
Team Liquid Map Contest - Preparation Notice6Weekly Cups (Feb 23-Mar 1): herO doubles, 2v2 bonanza1Weekly Cups (Feb 16-22): MaxPax doubles0Weekly Cups (Feb 9-15): herO doubles up2ACS replaced by "ASL Season Open" - Starts 21/0258
StarCraft 2
General
https://www.facebook.com/BackRestore.USA/ How do you think the 5.0.15 balance patch (Oct 2025) for StarCraft II has affected the game? Vitality disbanding their sc2-team Team Liquid Map Contest - Preparation Notice ByuL: The Forgotten Master of ZvT
Tourneys
RSL Season 4 announced for March-April Sparkling Tuna Cup - Weekly Open Tournament $5,000 WardiTV Winter Championship 2026 Sea Duckling Open (Global, Bronze-Diamond) PIG STY FESTIVAL 7.0! (19 Feb - 1 Mar)
Strategy
Custom Maps
Publishing has been re-enabled! [Feb 24th 2026] Map Editor closed ?
External Content
The PondCast: SC2 News & Results Mutation # 515 Together Forever Mutation # 514 Ulnar New Year Mutation # 513 Attrition Warfare
Brood War
General
Gypsy to Korea BSL 22 Map Contest — Submissions OPEN to March 10 Flash's ASL S21 & Future Plans Announcement BGH Auto Balance -> http://bghmmr.eu/ BW General Discussion
Tourneys
ASL Season 21 Qualifiers March 7-8 [Megathread] Daily Proleagues [BSL22] Open Qualifier #1 - Sunday 21:00 CET Small VOD Thread 2.0
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
Path of Exile PC Games Sales Thread Nintendo Switch Thread Stormgate/Frost Giant Megathread Battle Aces/David Kim RTS 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 Russo-Ukrainian War Thread Things Aren’t Peaceful in Palestine YouTube Thread UK Politics Mega-thread
Fan Clubs
The IdrA Fan Club
Media & Entertainment
[Manga] One Piece [Req][Books] Good Fantasy/SciFi books Anime Discussion Thread
Sports
2024 - 2026 Football Thread Formula 1 Discussion 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: 2088 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
28098 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 1h 53m
[ Submit Event ]
Live Streams
Refresh
StarCraft 2
mcanning 160
SortOf 98
Livibee 41
StarCraft: Brood War
Sea 36820
Britney 26737
Bisu 9291
ToSsGirL 242
PianO 214
Dewaltoss 167
Terrorterran 14
Dota 2
XaKoH 463
NeuroSwarm134
League of Legends
JimRising 642
Counter-Strike
Stewie2K1394
m0e_tv521
Super Smash Bros
Mew2King118
Other Games
C9.Mang0340
Fuzer 186
Organizations
StarCraft: Brood War
Afreeca ASL 3500
Dota 2
PGL Dota 2 - Main Stream2620
PGL Dota 2 - Secondary Stream387
StarCraft: Brood War
UltimateBattle 258
StarCraft 2
Blizzard YouTube
StarCraft: Brood War
BSLTrovo
sctven
[ Show 13 non-featured ]
StarCraft 2
• practicex 30
• AfreecaTV YouTube
• intothetv
• Kozan
• IndyKCrew
• LaughNgamezSOOP
• Migwel
• sooper7s
StarCraft: Brood War
• BSLYoutube
• STPLYoutube
• ZZZeroYoutube
League of Legends
• Lourlo1836
• Stunt547
Upcoming Events
CranKy Ducklings
1h 53m
RSL Revival
1h 53m
Reynor vs Zoun
herO vs sOs
WardiTV Winter Champion…
3h 53m
Classic vs Rogue
Solar vs Gerald
Bunny vs Nicoract
ByuN vs Zoun
herO vs Clem
MaxPax vs Cure
AI Arena Tournament
11h 53m
Patches Events
14h 53m
Replay Cast
15h 53m
Sparkling Tuna Cup
1d 1h
RSL Revival
1d 1h
Classic vs TriGGeR
Cure vs Cham
WardiTV Winter Champion…
1d 3h
OSC
1d 4h
[ Show More ]
BSL
1d 11h
Replay Cast
1d 15h
Replay Cast
2 days
Monday Night Weeklies
2 days
OSC
2 days
Replay Cast
4 days
The PondCast
5 days
Replay Cast
5 days
Replay Cast
6 days
Liquipedia Results

Completed

Proleague 2026-03-05
PiG Sty Festival 7.0
Underdog Cup #3

Ongoing

KCM Race Survival 2026 Season 1
Jeongseon Sooper Cup
Spring Cup 2026
ASL Season 21: Qualifier #1
RSL Revival: Season 4
WardiTV Winter 2026
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

ASL Season 21: Qualifier #2
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.