• Log InLog In
  • Register
Liquid`
Team Liquid Liquipedia
EDT 20:40
CEST 02:40
KST 09:40
  • 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] Ro16 Preview: Holy Diver4[ASL22] Ro16 Preview: Rough Waters10[ASL22] Ro24 Preview: Siren's Call8[ASL22] Ro24 Preview: Summer's End9Serral wins HomeStory Cup 2915
Community News
StarCraft open world shooter announced at BlizzCon97Weekly Cups (Aug 30-Sep 7): herO thrives amid growing schism10Official StarCraft website teases new content ahead of BlizzCon?175Stellar Fest TWO the Moon (Dec 16-20)9Weekly Cups (August 24-30): Patches' balance mod takes over3
StarCraft 2
General
StarCraft open world shooter announced at BlizzCon How do you feel about the StarCraft shooter announcement at BlizzCon 2026? Balance hotfix patch 5.0.16b (July 16) Blizzard Classic Cup @ BlizzCon 2026 - $100k prize pool Team Liquid Map Contest #22: Results and Winners
Tourneys
RSL Revival: Season 6 - Qualifiers and Main Event RSL goes to London! 2026 Offline Finals Nov 21-22 SC2 AI Tournament 2026 Fall Sparkling Tuna Cup - Weekly Open Tournament KSL Week #92
Strategy
[G] Having the right mentality to improve
Custom Maps
Nexus Wars 2021 GUIDE [M] (2) Industrial Park
External Content
Mutation # 543 Enhanced Defenses The PondCast: SC2 News & Results Mutation # 542 The Ascended Mutation # 541 Binary Choice
Brood War
General
New 3v3 BGH Ladder (and more) on ShieldBattery! Official StarCraft website teases new content ahead of BlizzCon? [D] Brainstorming a balance patch for Brood war Making an Online Broodwar Manager Game [ASL22] Ro16 Preview: Holy Diver
Tourneys
[ASL22] Ro16 Group C [Megathread] Daily Proleagues [ASL22] Ro16 Group B [ASL22] Ro16 Group A
Strategy
Replay Review Process - What do you do? Simple Questions, Simple Answers Odyssey Mineral Stack Saturation Game Theory for Starcraft
Other Games
General Games
Nintendo Switch Thread EVE Corporation Stormgate/Frost Giant Megathread Diablo IV [Maplestory Hardcore] Let's Play~!!
Dota 2
Official 'what is Dota anymore' discussion
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
US Politics Mega-thread Artificial Intelligence Thread Russo-Ukrainian War Thread UK Politics Mega-thread Things Aren’t Peaceful in Palestine
Fan Clubs
MarineLorD Fan Club The Creator Fan Club The ShoWTimE Fan Club
Media & Entertainment
[Manga] One Piece Movie Discussion! Diablo Animated Series on Netflix
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
The Automated Ban List Northern Ireland Global Starcraft
Blogs
Virtual Romance, Real-Life C…
TrAiDoS
Regacy Esports:Our Goa…
regacyesports
Dreaming of BW patches (mod…
c3rberUs
LOCKPICKING NOOB
LUCKY_NOOB
Customize Sidebar...

Website Feedback

Closed Threads



Active: 5781 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
28102 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 9h 20m
[ Submit Event ]
Live Streams
Refresh
StarCraft: Brood War
GuemChi 2193
soO 19
Dota 2
monkeys_forever785
NeuroSwarm174
League of Legends
JimRising 579
Counter-Strike
minikerr24
Super Smash Bros
hungrybox573
PPMD60
Other Games
summit1g10116
PiGStarcraft302
ToD175
Maynarde87
Organizations
Other Games
gamesdonequick2407
[ Show 11 non-featured ]
StarCraft 2
• Hupsaiya 114
• davetesta16
• AfreecaTV YouTube
• intothetv
• Kozan
• IndyKCrew
• Migwel
StarCraft: Brood War
• BSLYoutube
• STPLYoutube
• ZZZeroYoutube
Other Games
• imaqtpie779
Upcoming Events
Afreeca Starleague
9h 20m
Snow vs Shinee
Shine vs EffOrt
GSL
10h 20m
PiGosaur Cup
23h 20m
The PondCast
1d 9h
Kung Fu Cup
1d 10h
Replay Cast
1d 23h
KCM Race Survival
2 days
IntoTheTV X SOOP
2 days
Replay Cast
2 days
IntoTheTV X SOOP
3 days
[ Show More ]
Replay Cast
3 days
GSL
4 days
Replay Cast
4 days
GSL
5 days
Shopify Rebellion Sundays
5 days
Spirit vs Mixu
Replay Cast
5 days
WardiTV Weekly
6 days
Liquipedia Results

Completed

Proleague 2026-09-14
Blizzard Classic Cup 2026
Big Dog Cup 2026 Div 1

Ongoing

KCM Race Survival 2026 Season 3
K-JUNGMAN
ASL Season 22
Super Anchor Qualifying S3
CSL 2026 AUTUMN (S22)
Acropolis #5
Calamity Invitational
FISSURE Playground #3
BLAST Open Fall 2026
Esports World Cup 2026
BLAST Bounty Summer 2026
BLAST Bounty Summer Qual
Stake Ranked Episode 3
XSE Pro League 2026

Upcoming

Acropolis #5 - GSA
Acropolis #5 - GSB
Acropolis #5 - GSC
SC4ALL II: Brood War
HSC XXX
Stellar Fest 2: Lunar Cup
SC4ALL II: StarCraft II
Kung Fu Cup 2026 Grand Finals
RSL Offline Finals
Copium Cup
PGL Major Singapore 2026
Stake Ranked Episode 6
BLAST Rivals Fall 2026
IEM Beijing 2026
Stake Ranked Episode 5
PGL Masters Bucharest 2026
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
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.