コード例 #1
0
def test_billboard_actor(interactive=False):
    scene = window.Scene()
    scene.background((1, 1, 1))
    centers = np.array([[0, 0, 0], [5, -5, 5], [-7, 7, -7], [10, 10, 10],
                        [10.5, 11.5, 11.5], [12, -12, -12], [-17, 17, 17],
                        [-22, -22, 22]])
    colors = np.array([[1, 1, 0], [0, 0, 0], [1, 0, 1], [0, 0, 1], [1, 1, 1],
                       [1, 0, 0], [0, 1, 0], [0, 1, 1]])
    scales = [6, .4, 1.2, 1, .2, .7, 3, 2]

    fake_sphere = \
        """
        float len = length(point);
        float radius = 1.;
        if(len > radius)
            {discard;}

        vec3 normalizedPoint = normalize(vec3(point.xy, sqrt(1. - len)));
        vec3 direction = normalize(vec3(1., 1., 1.));
        float df_1 = max(0, dot(direction, normalizedPoint));
        float sf_1 = pow(df_1, 24);
        fragOutput0 = vec4(max(df_1 * color, sf_1 * vec3(1)), 1);
        """

    billboard_actor = actor.billboard(centers, colors=colors, scales=scales,
                                      fs_impl=fake_sphere)
    scene.add(billboard_actor)
    scene.add(actor.axes())
    if interactive:
        window.show(scene)

    arr = window.snapshot(scene)
    report = window.analyze_snapshot(arr, colors=colors)
    npt.assert_equal(report.objects, 8)
コード例 #2
0
ファイル: test_actors.py プロジェクト: MarcCote/fury
def test_billboard_actor(interactive=False):
    scene = window.Scene()
    scene.background((1, 1, 1))
    centers = np.array([[2, 0, 0], [0, 2, 0], [0, 0, 0]])
    colors = np.array([[255, 0, 0], [0, 255, 0], [0, 0, 255]])
    scale = [1, 2, 1]

    fake_sphere = \
    """
    float len = length(point);
    float radius = 1.;
    if(len > radius)
        {discard;}

    vec3 normalizedPoint = normalize(vec3(point.xy, sqrt(1. - len)));
    vec3 direction = normalize(vec3(1., 1., 1.));
    float df = max(0, dot(direction, normalizedPoint));
    float sf = pow(df, 24);
    fragOutput0 = vec4(max(df * color, sf * vec3(1)), 1);
    """

    billboard_actor = actor.billboard(centers,
                                      colors=colors.astype(np.uint8),
                                      scale=scale,
                                      fs_impl=fake_sphere)
    scene.add(billboard_actor)
    scene.add(actor.axes())
    if interactive:
        window.show(scene)
コード例 #3
0
def update_frame():
    global high_perc, high_ranges, low_perc, low_ranges, max_centers, \
        min_centers, scene, spheres_actor, slider_clipping_plane_thrs_x, \
        slider_clipping_plane_thrs_y, slider_clipping_plane_thrs_z

    slider_clipping_plane_thrs_x.on_change = lambda slider: None
    slider_clipping_plane_thrs_y.on_change = lambda slider: None
    slider_clipping_plane_thrs_z.on_change = lambda slider: None

    centers, colors, radius = read_data()

    scene.rm(spheres_actor)

    spheres_actor = actor.billboard(centers,
                                    colors,
                                    scales=radius,
                                    fs_dec=_RANGE_CENTERS,
                                    fs_impl=_FAKE_SPHERE)

    spheres_mapper = spheres_actor.GetMapper()
    spheres_mapper.AddObserver(vtk.vtkCommand.UpdateShaderEvent,
                               vtk_shader_callback)

    scene.add(spheres_actor)

    min_centers = np.min(centers, axis=0)
    max_centers = np.max(centers, axis=0)

    low_ranges = np.array(
        [np.percentile(centers[:, i], v) for i, v in enumerate(low_perc)])
    high_ranges = np.array(
        [np.percentile(centers[:, i], v) for i, v in enumerate(high_perc)])

    slider_clipping_plane_thrs_x.left_disk_value = low_ranges[0]
    slider_clipping_plane_thrs_x.right_disk_value = high_ranges[0]
    slider_clipping_plane_thrs_x.min_value = min_centers[0]
    slider_clipping_plane_thrs_x.max_value = max_centers[0]
    slider_clipping_plane_thrs_x.on_change = change_clipping_plane_x

    slider_clipping_plane_thrs_y.left_disk_value = low_ranges[1]
    slider_clipping_plane_thrs_y.right_disk_value = high_ranges[1]
    slider_clipping_plane_thrs_y.min_value = min_centers[1]
    slider_clipping_plane_thrs_y.max_value = max_centers[1]
    slider_clipping_plane_thrs_y.on_change = change_clipping_plane_y

    slider_clipping_plane_thrs_z.left_disk_value = low_ranges[2]
    slider_clipping_plane_thrs_z.right_disk_value = high_ranges[2]
    slider_clipping_plane_thrs_z.min_value = min_centers[2]
    slider_clipping_plane_thrs_z.max_value = max_centers[2]
    slider_clipping_plane_thrs_z.on_change = change_clipping_plane_z
コード例 #4
0
ファイル: fury_protocol.py プロジェクト: fury-gl/fury-web
    def update_frame(self, data):
        if not self.is_valid_data(data):
            return
        folder = data.get('folder', None)
        fname = data.get('filename', None)

        centers, colors, radius = read_xml_data(folder=folder, filename=fname)
        ren_win = self.getView('-1')
        scene = ren_win.GetRenderers().GetFirstRenderer()
        self.disconnect_sliders()
        if self.spheres_actor is not None:
            scene.rm(self.spheres_actor)

        self.spheres_actor = actor.billboard(centers,
                                             colors,
                                             scales=radius,
                                             fs_dec=_RANGE_CENTERS,
                                             fs_impl=_FAKE_SPHERE)

        spheres_mapper = self.spheres_actor.GetMapper()
        spheres_mapper.AddObserver(vtk.vtkCommand.UpdateShaderEvent,
                                   self.vtk_shader_callback)

        scene.add(self.spheres_actor)

        self.min_centers = np.min(centers, axis=0)
        self.max_centers = np.max(centers, axis=0)

        self.low_ranges = np.array([
            np.percentile(centers[:, i], v)
            for i, v in enumerate(self.low_perc)
        ])
        self.high_ranges = np.array([
            np.percentile(centers[:, i], v)
            for i, v in enumerate(self.high_perc)
        ])
        self.connect_sliders()
        scene.ResetCamera()
コード例 #5
0
        if(opacity == 0)
            discard;
        float len = length(point);
        float radius = 1.;
        if(len > radius)
            discard;
        vec3 normalizedPoint = normalize(vec3(point.xy, sqrt(1. - len)));
        vec3 direction = normalize(vec3(1., 1., 1.));
        float df_1 = max(0, dot(direction, normalizedPoint));
        float sf_1 = pow(df_1, 24);
        fragOutput0 = vec4(max(df_1 * color, sf_1 * vec3(1)), 1);
        """

    global spheres_actor
    spheres_actor = actor.billboard(xyz,
                                    colors,
                                    scales=cell_radii,
                                    fs_impl=fake_sphere)
    scene.add(spheres_actor)

    show_m = window.ShowManager(scene,
                                reset_camera=False,
                                order_transparent=True,
                                max_peels=0)
    show_m.initialize()

    global panel
    panel = ui.Panel2D((256, 144),
                       position=(40, 5),
                       color=(1, 1, 1),
                       opacity=.1,
                       align='right')
コード例 #6
0
ファイル: fury_server.py プロジェクト: fury-gl/fury-web
    def initialize(self):
        # Bring used components
        self.registerVtkWebProtocol(protocols.vtkWebMouseHandler())
        self.registerVtkWebProtocol(protocols.vtkWebViewPort())
        # Image delivery
        # 1. Original method where the client ask for each image individually
        #self.registerVtkWebProtocol(protocols.vtkWebViewPortImageDelivery())
        # 2. Improvement on the initial protocol to allow images to be pushed
        # from the server without any client request (i.e.: animation, LOD, …)
        self.registerVtkWebProtocol(
            protocols.vtkWebPublishImageDelivery(decode=False))
        # Protocol for sending geometry for the vtk.js synchronized render
        # window
        # For local rendering using vtk.js
        #self.registerVtkWebProtocol(protocols.vtkWebViewPortGeometryDelivery())
        #self.registerVtkWebProtocol(protocols.vtkWebLocalRendering())

        # Custom API
        self.registerVtkWebProtocol(FuryProtocol())

        # Tell the C++ web app to use no encoding.
        # ParaViewWebPublishImageDelivery must be set to decode=False to match.
        # RAW instead of base64
        self.getApplication().SetImageEncoding(0)

        # Update authentication key to use
        self.updateSecret(_WebSpheres.authKey)

        # Create default pipeline (Only once for all the session)
        if not _WebSpheres.view:
            # FURY specific code
            scene = window.Scene()
            scene.background((1, 1, 1))

            n_points = 10000
            translate = 100
            centers = translate * np.random.rand(n_points, 3) - translate / 2
            colors = 255 * np.random.rand(n_points, 3)
            radius = np.random.rand(n_points)
            fake_sphere = \
                """
                float len = length(point);
                float radius = 1.;
                if(len > radius)
                    {discard;}

                vec3 normalizedPoint = normalize(vec3(point.xy, sqrt(1. - len)));
                vec3 direction = normalize(vec3(1., 1., 1.));
                float df_1 = max(0, dot(direction, normalizedPoint));
                float sf_1 = pow(df_1, 24);
                fragOutput0 = vec4(max(df_1 * color, sf_1 * vec3(1)), 1);
                """
            spheres_actor = actor.billboard(centers,
                                            colors=colors,
                                            scales=radius,
                                            fs_impl=fake_sphere)

            scene.add(spheres_actor)
            scene.add(actor.axes())

            showm = window.ShowManager(scene)
            # For debugging purposes
            #showm.render()

            ren_win = showm.window

            ren_win_interactor = vtk.vtkRenderWindowInteractor()
            ren_win_interactor.SetRenderWindow(ren_win)
            ren_win_interactor.GetInteractorStyle().\
                SetCurrentStyleToTrackballCamera()
            ren_win_interactor.EnableRenderOff()

            # VTK Web application specific
            _WebSpheres.view = ren_win
            self.getApplication().GetObjectIdMap().SetActiveObject(
                'VIEW', ren_win)
コード例 #7
0
if __name__ == '__main__':
    global high_perc, high_ranges, idx_xml, low_perc, low_ranges, \
        panel, scene, size, spheres_actor, xml_files

    xml_files = glob.glob(os.path.join(_DATA_DIR, '*.xml'))

    idx_xml = 0

    centers, colors, radius = read_data()

    scene = window.Scene()

    spheres_actor = actor.billboard(centers,
                                    colors,
                                    scales=radius,
                                    fs_dec=_RANGE_CENTERS,
                                    fs_impl=_FAKE_SPHERE)

    spheres_mapper = spheres_actor.GetMapper()
    spheres_mapper.AddObserver(vtk.vtkCommand.UpdateShaderEvent,
                               vtk_shader_callback)

    scene.add(spheres_actor)

    show_m = window.ShowManager(scene,
                                reset_camera=False,
                                order_transparent=True)
    show_m.initialize()

    panel = ui.Panel2D((480, 270),
コード例 #8
0
                         colors=edges_colors,
                         lod=False,
                         fake_tube=False,
                         linewidth=3,
                         opacity=0.1)

###############################################################################
# We use a billboard actor to render the spheres for nodes
# so that a shader is used to draw a sphere into each billboard.

billboard_sphere_dec = shader_load("billboard_spheres_dec.frag")
billboard_sphere_impl = shader_load("billboard_spheres_impl.frag")

nodes_actor = actor.billboard(centers,
                              colors=colors,
                              scales=1.0,
                              fs_dec=billboard_sphere_dec,
                              fs_impl=billboard_sphere_impl)

###############################################################################
# Preparing editable geometry for the nodes

vtk_centers_geometry = vtk_array_from_actor(nodes_actor, array_name="center")
centers_geometry = vtknp.vtk_to_numpy(vtk_centers_geometry)
centers_geometryOrig = np.array(centers_geometry)
centers_length = centers_geometry.shape[0] / positions.shape[0]

vtk_verts_geometry = vtk_vertices_from_actor(nodes_actor)
verts_geometry = vtknp.vtk_to_numpy(vtk_verts_geometry)
verts_geometryOrig = np.array(verts_geometry)
verts_length = verts_geometry.shape[0] / positions.shape[0]
コード例 #9
0
        if(!isVisible(centerVertexMCVSOutput))
            discard;
        float len = length(point);
        float radius = 1.;
        if(len > radius)
            discard;
        vec3 normalizedPoint = normalize(vec3(point.xy, sqrt(1. - len)));
        vec3 direction = normalize(vec3(1., 1., 1.));
        float df_1 = max(0, dot(direction, normalizedPoint));
        float sf_1 = pow(df_1, 24);
        fragOutput0 = vec4(max(df_1 * color, sf_1 * vec3(1)), 1);
        """

    spheres_actor = actor.billboard(centers,
                                    colors,
                                    scales=radius,
                                    fs_dec=range_centers,
                                    fs_impl=fake_sphere)

    scene.add(spheres_actor)

    min_centers = np.min(centers, axis=0)
    max_centers = np.max(centers, axis=0)

    global low_ranges, high_ranges
    low_ranges = np.percentile(centers, 50, axis=0)
    high_ranges = max_centers

    spheres_mapper = spheres_actor.GetMapper()
    spheres_mapper.AddObserver(vtk.vtkCommand.UpdateShaderEvent,
                               vtk_shader_callback)
コード例 #10
0
ファイル: viz_canvas.py プロジェクト: zoq/fury
def test_sh():
    from dipy.sims.voxel import multi_tensor, multi_tensor_odf, sticks_and_ball
    from dipy.data import get_sphere, get_fnames
    from dipy.core.gradients import gradient_table
    from dipy.io.gradients import read_bvals_bvecs

    _, fbvals, fbvecs = get_fnames('small_64D')
    bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs)
    gtab = gradient_table(bvals, bvecs)

    d = 0.0015
    S, sticks = sticks_and_ball(gtab,
                                d=d,
                                S0=1,
                                angles=[(0, 0), (30, 30)],
                                fractions=[60, 40],
                                snr=None)

    print(S)
    print(sticks)
    mevals = np.array([[0.0015, 0.0003, 0.0003], [0.0015, 0.0003, 0.0003]])
    angles = [(0, 0), (60, 0)]
    fractions = [50, 50]
    sphere = get_sphere('repulsion724')
    sphere = sphere.subdivide(2)
    odf = multi_tensor_odf(sphere.vertices, mevals, angles, fractions)

    print(odf)
    ren = window.Scene()

    odf_actor = actor.odf_slicer(odf[None, None, None, :],
                                 sphere=sphere,
                                 colormap='plasma')
    # odf_actor.RotateX(90)

    ren.add(odf_actor)
    # window.show(ren)

    odf_test_dec= \
    """
    // Constants, see here: http://en.wikipedia.org/wiki/Table_of_spherical_harmonics
#define k01 0.2820947918 // sqrt(  1/PI)/2
#define k02 0.4886025119 // sqrt(  3/PI)/2
#define k03 1.0925484306 // sqrt( 15/PI)/2
#define k04 0.3153915652 // sqrt(  5/PI)/4
#define k05 0.5462742153 // sqrt( 15/PI)/4
#define k06 0.5900435860 // sqrt( 70/PI)/8
#define k07 2.8906114210 // sqrt(105/PI)/2
#define k08 0.4570214810 // sqrt( 42/PI)/8
#define k09 0.3731763300 // sqrt(  7/PI)/4
#define k10 1.4453057110 // sqrt(105/PI)/4

// unrolled version of the above
float SH_0_0( in vec3 s ) { vec3 n = s.zxy; return  k01; }
float SH_1_0( in vec3 s ) { vec3 n = s.zxy; return -k02*n.y; }
float SH_1_1( in vec3 s ) { vec3 n = s.zxy; return  k02*n.z; }
float SH_1_2( in vec3 s ) { vec3 n = s.zxy; return -k02*n.x; }
float SH_2_0( in vec3 s ) { vec3 n = s.zxy; return  k03*n.x*n.y; }
float SH_2_1( in vec3 s ) { vec3 n = s.zxy; return -k03*n.y*n.z; }
float SH_2_2( in vec3 s ) { vec3 n = s.zxy; return  k04*(3.0*n.z*n.z-1.0); }
float SH_2_3( in vec3 s ) { vec3 n = s.zxy; return -k03*n.x*n.z; }
float SH_2_4( in vec3 s ) { vec3 n = s.zxy; return  k05*(n.x*n.x-n.y*n.y); }
float SH_3_0( in vec3 s ) { vec3 n = s.zxy; return -k06*n.y*(3.0*n.x*n.x-n.y*n.y); }
float SH_3_1( in vec3 s ) { vec3 n = s.zxy; return  k07*n.z*n.y*n.x; }
float SH_3_2( in vec3 s ) { vec3 n = s.zxy; return -k08*n.y*(5.0*n.z*n.z-1.0); }
float SH_3_3( in vec3 s ) { vec3 n = s.zxy; return  k09*n.z*(5.0*n.z*n.z-3.0); }
float SH_3_4( in vec3 s ) { vec3 n = s.zxy; return -k08*n.x*(5.0*n.z*n.z-1.0); }
float SH_3_5( in vec3 s ) { vec3 n = s.zxy; return  k10*n.z*(n.x*n.x-n.y*n.y); }
float SH_3_6( in vec3 s ) { vec3 n = s.zxy; return -k06*n.x*(n.x*n.x-3.0*n.y*n.y); }

vec3 map( in vec3 p )
{
    vec3 p00 = p - vec3( 0.00, 2.5,0.0);
	vec3 p01 = p - vec3(-1.25, 1.0,0.0);
	vec3 p02 = p - vec3( 0.00, 1.0,0.0);
	vec3 p03 = p - vec3( 1.25, 1.0,0.0);
	vec3 p04 = p - vec3(-2.50,-0.5,0.0);
	vec3 p05 = p - vec3(-1.25,-0.5,0.0);
	vec3 p06 = p - vec3( 0.00,-0.5,0.0);
	vec3 p07 = p - vec3( 1.25,-0.5,0.0);
	vec3 p08 = p - vec3( 2.50,-0.5,0.0);
	vec3 p09 = p - vec3(-3.75,-2.0,0.0);
	vec3 p10 = p - vec3(-2.50,-2.0,0.0);
	vec3 p11 = p - vec3(-1.25,-2.0,0.0);
	vec3 p12 = p - vec3( 0.00,-2.0,0.0);
	vec3 p13 = p - vec3( 1.25,-2.0,0.0);
	vec3 p14 = p - vec3( 2.50,-2.0,0.0);
	vec3 p15 = p - vec3( 3.75,-2.0,0.0);

	float r, d; vec3 n, s, res;

    #ifdef SHOW_SPHERES
	#define SHAPE (vec3(d-0.35, -1.0+2.0*clamp(0.5 + 16.0*r,0.0,1.0),d))
	#else
	#define SHAPE (vec3(d-abs(r), sign(r),d))
	#endif
	d=length(p00); n=p00/d; r = SH_0_0( n ); s = SHAPE; res = s;
	d=length(p01); n=p01/d; r = SH_1_0( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p02); n=p02/d; r = SH_1_1( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p03); n=p03/d; r = SH_1_2( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p04); n=p04/d; r = SH_2_0( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p05); n=p05/d; r = SH_2_1( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p06); n=p06/d; r = SH_2_2( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p07); n=p07/d; r = SH_2_3( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p08); n=p08/d; r = SH_2_4( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p09); n=p09/d; r = SH_3_0( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p10); n=p10/d; r = SH_3_1( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p11); n=p11/d; r = SH_3_2( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p12); n=p12/d; r = SH_3_3( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p13); n=p13/d; r = SH_3_4( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p14); n=p14/d; r = SH_3_5( n ); s = SHAPE; if( s.x<res.x ) res=s;
	d=length(p15); n=p15/d; r = SH_3_6( n ); s = SHAPE; if( s.x<res.x ) res=s;

	return vec3( res.x, 0.5+0.5*res.y, res.z );
}

vec3 intersect( in vec3 ro, in vec3 rd )
{
	vec3 res = vec3(1e10,-1.0, 1.0);

	float maxd = 10.0;
    float h = 1.0;
    float t = 0.0;
    vec2  m = vec2(-1.0);
    for( int i=0; i<200; i++ )
    {
        if( h<0.001||t>maxd ) break;
	    vec3 res = map( ro+rd*t );
        h = res.x;
		m = res.yz;
        t += h*0.3;
    }
	if( t<maxd && t<res.x ) res=vec3(t,m);


	return res;
}

vec3 calcNormal( in vec3 pos )
{
    vec3 eps = vec3(0.001,0.0,0.0);

	return normalize( vec3(
           map(pos+eps.xyy).x - map(pos-eps.xyy).x,
           map(pos+eps.yxy).x - map(pos-eps.yxy).x,
           map(pos+eps.yyx).x - map(pos-eps.yyx).x ) );
}

    """



    odf_test_impl = \
    """

        // camera matrix
        vec3 ww = vec3(0.0,0.0,0.0); //MCDCMatrix (2);
        vec3 uu = vec3(0.0,0.0,0.0); //MCDCMatrix (0);
        vec3 vv = vec3(0.0,0.0,0.0); //MCDCMatrix (1);
        vec3 tot = vec3(0.0);
        vec2 p = (-vec2(0.5, 0.5) + (2.0*point,0)) / 0.5;
        vec3 ro = vec3(0.0,0.0,0.0);

        // create view ray
        vec3 rd = normalize( p.x*uu + p.y*vv + 2.0*ww );

        // background
        vec3 col = vec3(0.3) * clamp(1.0-length(point)*0.5,0.0,1.0);

        // raymarch
        vec3 tmat = intersect(ro,rd);
        if( tmat.y>-0.5 )
        {
            // geometry
            vec3 pos = ro + tmat.x*rd;
            vec3 nor = calcNormal(pos);
            vec3 ref = reflect( rd, nor );

            // material
            vec3 mate = 0.5*mix( vec3(1.0,0.6,0.15), vec3(0.2,0.4,0.5), tmat.y );

            float occ = clamp( 2.0*tmat.z, 0.0, 1.0 );
            float sss = pow( clamp( 1.0 + dot(nor,rd), 0.0, 1.0 ), 1.0 );

            // lights
            vec3 lin  = 2.5*occ*vec3(1.0,1.00,1.00)*(0.6+0.4*nor.y);
                 lin += 1.0*sss*vec3(1.0,0.95,0.70)*occ;

            // surface-light interacion
            col = mate.xyz * lin;
        }

        // gamma
        col = pow( clamp(col,0.0,1.0), vec3(0.4545) );
        tot += col;
    fragOutput0 = vec4( tot, 1.0 );
    """

    scene = window.Scene()
    scene.background((0.8, 0.8, 0.8))
    centers = np.array([[2, 0, 0], [0, 0, 0], [-2, 0, 0]])
    # np.random.rand(3, 3) * 3
    # colors = np.array([[255, 0, 0], [0, 255, 0], [0, 0, 255]])
    colors = np.random.rand(3, 3) * 255
    scale = 1  # np.random.rand(3) * 5

    # https://www.shadertoy.com/view/MstXWS
    # https://www.shadertoy.com/view/XsX3R4

    fs_dec = \
        """
        uniform mat4 MCDCMatrix;
        uniform mat4 MCVCMatrix;


        float sdRoundBox( vec3 p, vec3 b, float r )
        {
            vec3 q = abs(p) - b;
            return length(max(q,0.0)) + min(max(q.x,max(q.y,q.z)),0.0) - r;
        }

        float sdEllipsoid( vec3 p, vec3 r )
        {
        float k0 = length(p/r);
        float k1 = length(p/(r*r));
        return k0*(k0-1.0)/k1;
        }
        float sdCylinder(vec3 p, float h, float r)
        {
            vec2 d = abs(vec2(length(p.xz),p.y)) - vec2(h,r);
            return min(max(d.x,d.y),0.0) + length(max(d,0.0));
        }
        float sdSphere(vec3 pos, float r)
        {
            float d = length(pos) - r;

            return d;
        }
        float map( in vec3 pos)
        {
            float d = sdSphere(pos-0.5, .2);
            float d1 = sdCylinder(pos+0.5, 0.05, .5);
            float d2 = sdEllipsoid(pos + vec3(-0.5,0.5,0), vec3(0.2,0.3,0.5));
            float d3 = sdRoundBox(pos + vec3(0.5,-0.5,0), vec3(0.2,0.1,0.3), .05);


            //.xy

            return min(min(min(d, d1), d2), d3);
        }

        vec3 calcNormal( in vec3 pos )
        {
            vec2 e = vec2(0.0001,0.0);
            return normalize( vec3(map(pos + e.xyy) - map(pos - e.xyy ),
                                   map(pos + e.yxy) - map(pos - e.yxy),
                                   map(pos + e.yyx) - map(pos - e.yyx)
                                   )
                            );
        }

        float castRay(in vec3 ro, vec3 rd)
        {
            float t = 0.0;
            for(int i=0; i < 100; i++)
            {
                vec3 pos = ro + t * rd;
                vec3 nor = calcNormal(pos);

                float h = map(pos);
                if (h < 0.001) break;

                t += h;
                if (t > 20.0) break;
            }
            return t;
        }
        """

    fake_sphere = \
    """

    vec3 uu = vec3(MCVCMatrix[0][0], MCVCMatrix[1][0], MCVCMatrix[2][0]); // camera right
    vec3 vv = vec3(MCVCMatrix[0][1], MCVCMatrix[1][1], MCVCMatrix[2][1]); //  camera up
    vec3 ww = vec3(MCVCMatrix[0][2], MCVCMatrix[1][2], MCVCMatrix[2][2]); // camera direction
    vec3 ro = MCVCMatrix[3].xyz * mat3(MCVCMatrix);  // camera position

    // create view ray
    vec3 rd = normalize( point.x*-uu + point.y*-vv + 7*ww);
    vec3 col = vec3(0.0);

    float t = castRay(ro, rd);
    if (t < 20.0)
    {
        vec3 pos = ro + t * rd;
        vec3 nor = calcNormal(pos);
        vec3 sun_dir = vec3(MCVCMatrix[0][2], MCVCMatrix[1][2], MCVCMatrix[2][2]); //normalize()
        float dif = clamp( dot(nor, sun_dir), 0.0, 1.0);
        //vec3 sun_dif = normalize()
        col = color * dot(color,nor); // (color + diffuseColor + ambientColor + specularColor)*nor.zzz;//vec3(1.0);
        fragOutput0 = vec4(col, 1.0);
    }
    else{
        //fragOutput0 = vec4(0,1,0, 1.0);
        discard;
        }


    /*float radius = 1.;
    if(len > radius)
        {discard;}

    //err, lightColor0 vertexColorVSOutput normalVCVSOutput, ambientIntensity; diffuseIntensity;specularIntensity;specularColorUniform;
    float c = len;
    fragOutput0 =  vec4(c,c,c, 1);




    vec3 normalizedPoint = normalize(vec3(point.xy, sqrt(1. - len)));
    vec3 direction = normalize(vec3(1., 1., 1.));
    float df = max(0, dot(direction, normalizedPoint));
    float sf = pow(df, 24);
    fragOutput0 = vec4(max(df * color, sf * vec3(1)), 1);*/
    """

    billboard_actor = actor.billboard(centers,
                                      colors=colors.astype(np.uint8),
                                      scale=scale,
                                      fs_dec=fs_dec,
                                      fs_impl=fake_sphere)
    scene.add(billboard_actor)
    scene.add(actor.axes())
    scene.camera_info()
    matrix = scene.camera().GetViewTransformMatrix()
    mat = np.zeros((4, 4))
    for i in range(4):
        for j in range(4):
            mat[i, j] = matrix.GetElement(i, j)
    print(mat)
    print(np.dot(-mat[:3, 3], mat[:3, :3]))  # camera position
    window.show(scene)