 
     addSphere: (opts) ->
         opts = defaults opts,
-            loc         : [0,0,0]
-            radius      : 5
-            texture     : required
-            in_frame    : true
+            loc             : [0,0,0]
+            radius          : 5
+            texture         : required
+            in_frame        : true
+            _basic_material : false
 
         geometry = new THREE.SphereGeometry opts.radius, 32, 32
 
-        material = new THREE.MeshPhongMaterial
-            transparent : opts.texture.opacity < 1
-            side        : THREE.DoubleSide
-
-        material.color.setRGB       opts.texture.color...
-        material.ambient.setRGB     opts.texture.ambient...
-        material.specular.setRGB    opts.texture.specular...
-        material.opacity          = opts.texture.opacity
-
-        mesh = new THREE.Mesh geometry, material
+        if opts._basic_material
+            material = new THREE.MeshBasicMaterial
+                transparent : opts.texture.opacity < 1
+
+            material.color.setRGB       opts.texture.color...
+
+        else
+            material = new THREE.MeshPhongMaterial
+                transparent : opts.texture.opacity < 1
+                side        : THREE.DoubleSide
+
+            material.color.setRGB       opts.texture.color...
+            material.ambient.setRGB     opts.texture.ambient...
+            material.specular.setRGB    opts.texture.specular...
+            material.opacity          = opts.texture.opacity
+
+        sphere = new THREE.Mesh geometry, material
+        sphere.position.set opts.loc...
+
         if opts.in_frame
-            @updateBoundingBox mesh
-        @scene.add mesh
-        return mesh
+            @updateBoundingBox sphere
+        @scene.add sphere
+        return sphere
 
     addPoint: (opts) ->
         opts = defaults opts,
             loc         : [0,0,0]
             size        : 5
             texture     : required
+            use_cloud   : false
             in_frame    : true
 
-        if not @_points?
-            @_points = []
-
-        # IMPORTANT: Below we use sprites instead of the more natural/faster PointCloudMaterial.
-        # Why?  Because usually people don't plot a huge number of points, and PointCloudMaterial is SQUARE.
-        # By using sprites, our points are round, which is something people really care about.
-
-        switch @opts.renderer
-
-            when 'webgl'
-                width         = 50
-                height        = 50
-                canvas        = document.createElement 'canvas'
-                canvas.width  = width
-                canvas.height = height
-
-                context       = canvas.getContext '2d'  # get the drawing context
-                centerX       = width/2
-                centerY       = height/2
-                radius        = 25
-
-                context.beginPath()
-                context.arc centerX, centerY, radius, 0, 2*Math.PI, false
-                context.fillStyle = rgb_to_hex opts.texture.color
-                context.fill()
-
-                texture = new THREE.Texture canvas
-                texture.needsUpdate = true
-                spriteMaterial = new THREE.SpriteMaterial
-                    map     : texture
-                particle = new THREE.Sprite spriteMaterial
-
-                position = @aspect_ratio_scale opts.loc...
-                particle.position.set position...
-                @_points.push [particle, opts.size/200]
-
-            when 'canvas'
-                # inspired by http://mrdoob.github.io/three.js/examples/canvas_particles_random.html
-                PI2 = Math.PI * 2
-                program = (context) ->
-                    context.beginPath()
-                    context.arc 0, 0, 0.5, 0, PI2, true
-                    context.fill()
-                material = new THREE.SpriteCanvasMaterial
-                    color   : new THREE.Color opts.texture.color
-                    program : program
-                particle = new THREE.Sprite texture
-                position = @aspect_ratio_scale opts.loc...
-                particle.position.set position...
-                @_points.push [particle, 4*opts.size/@opts.width]
-
-            else
-                throw "bug -- unkown dynamic renderer type = #{@opts.renderer}"
-
-        if opts.in_frame
-            @updateBoundingBox particle
-        @scene.add particle
-        return particle
+        if opts.use_cloud
+            if not @_cloud
+                @_cloud = {}
+
+            key = opts.size+opts.texture.color+opts.in_frame
+
+            if not (cloud = @_cloud[key])?
+                material = new THREE.PointCloudMaterial
+                    size            : opts.size*2
+                    sizeAttenuation : false
+                material.color.setRGB opts.texture.color...
+                cloud = (@_cloud[key] = new THREE.PointCloud(
+                                            new THREE.Geometry(), material))
+                @scene.add cloud
+
+            cloud.geometry.vertices.push @vector(opts.loc...)
+
+            if opts.in_frame
+                @updateBoundingBox cloud
+            return cloud
+        else
+            if not @_points?
+                @_points = []
+
+            opts.radius = opts.size/400
+            opts._basic_material = true
+
+            delete opts.size
+            delete opts.use_cloud
+
+            point = @addSphere opts
+
+            @_points.push point
+
+            return point
 
     addIndexFaceSet: (opts) ->
         opts = defaults opts,

        @light.position.set 0, d, 0

    updateBoundingBox: (obj) ->
        if not obj.geometry.boundingBox?
            obj.geometry.computeBoundingBox()
        if @boundingBox?
            @boundingBox.geometry.boundingBox.union obj.geometry.boundingBox
        else

        if not new_pos and not force
            return

        # rescale all objects in scene
        @rescaleObjects()

        @renderer.render @scene, @camera

    _rescaleFactor: ->
        if not @_center?
            return undefined
        else
            return @camera.position.distanceTo(@_center) / 3

    rescaleObjects: (force = false) ->
        scale = @_rescaleFactor()
        if not scale? or (Math.abs(@_lastScale - scale) < 0.000001 and not force)
            return
        if @_points?
            for z in @_points
                z.scale.set scale, scale, scale
        @_lastScale = scale

math3d.render_3d_scene = (opts) ->
    opts = defaults opts,
