Three.js: Add fast atan2 to Three.Math

Created on 9 Feb 2017  路  7Comments  路  Source: mrdoob/three.js

(* This section is for bug reports and feature requests only. This is NOT a help site. Do not ask help questions here. If you need help, please use stackoverflow. *)

Description of the problem

Three.js has 30 uses of Math.atan/atan2:
grep atan three/build/three.js | wc

But JavaScript's Math.atan2(y, x) is extraordinarily slow. In a recent test of 100K 2-triangle geometries (BufferGeometry) the Math.atan2 function was 17-20% of the cpu cost!

This issue is to add a fast, sufficiently accurate atan/atan2 to Three.Math.

Two sites discuss this, many more I'm sure:
https://jsperf.com/is-atan2-fast/9
http://math.stackexchange.com/questions/1098487/atan2-faster-approximation

Three.js version
  • [ ] Dev
  • [x] r84
  • [ ] ...
Browser
  • [ ] All of them
  • [x] Chrome
  • [ ] Firefox
  • [ ] Internet Explorer
OS
  • [ ] All of them
  • [x] OS X Sierra
  • [ ] Windows
  • [ ] Linux
  • [ ] Android
  • [ ] IOS
Hardware Requirements (graphics card, VR Device, ...)

Up to date system on a 1-year old iMac

All 7 comments

Probably Euler and Quaternion are the most critical users.
https://github.com/mrdoob/three.js/search?utf8=%E2%9C%93&q=atan2

@s3ththompson Any plans on speeding up V8's Math.atan2()?

@mrdoob Good question! Do you have a reduced test case that does some non-trivial workload? We can definitely look into it. cc @hashseed @bmeurer

Math.atan2 is currently implemented using the fdlibm algorithm for good precision, which is arguably not the fastest implementation. The concrete implementation can be found in ieee754.cc. I guess if you can provide a good replacement that is faster and has roughly the same precision, we'd be open to use that.

In a recent test of 100K 2-triangle geometries (BufferGeometry) the Math.atan2 function was 17-20% of the cpu cost!

@backspaces Did you have 100K objects in your scene?

Can you identify a three.js example for which atan2 is problematic?

Thanks a lot for the insights @s3ththompson @bmeurer!

When I had to use atan in some primitive shader language that did not have it (cough... flash... cough) I ported this code from Eugene Zatepyakin, Joa Ebert and Patrick Le Clec'h (no idea where they took it from):

        public static function atan2(y:Number, x:Number):Number {
            var sign:Number = 1.0 - (int(y < 0.0) << 1)
            var absYandR:Number = y * sign + 2.220446049250313e-16
            var partSignX:Number = (int(x < 0.0) << 1) // [0.0/2.0]
            var signX:Number = 1.0 - partSignX // [1.0/-1.0]
            absYandR = (x - signX * absYandR) / (signX * x + absYandR)
            return ((partSignX + 1.0) * 0.7853981634 + (0.1821 * absYandR * absYandR - 0.9675) * absYandR) * sign
        }

it is going to be pretty fast (in something like c) and quite precise too.

Was this page helpful?
0 / 5 - 0 ratings