Skip to content

Commit 2b7ce7a

Browse files
committed
Spherical Harmonic static example
1 parent b35fcdc commit 2b7ce7a

File tree

6 files changed

+387
-0
lines changed

6 files changed

+387
-0
lines changed

fury/actor.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2498,3 +2498,66 @@ def texture_on_sphere(rgb, theta=60, phi=60, interpolate=True):
24982498
earthActor.SetTexture(atext)
24992499

25002500
return earthActor
2501+
2502+
2503+
def sdf_sh(centers, directions=(1, 0, 0), colors=(255, 0, 0), scale=1):
2504+
"""Create a SDF actor
2505+
2506+
Parameters
2507+
----------
2508+
centers : ndarray, shape (N, 3)
2509+
SDF primitive positions
2510+
colors : ndarray (N,3) or (N, 4) or tuple (3,) or tuple (4,)
2511+
RGB or RGBA (for opacity) R, G, B and A should be at the range [0, 1]
2512+
directions : ndarray, shape (N, 3)
2513+
The orientation vector of the cube.
2514+
scale : float
2515+
The size of the cube
2516+
2517+
2518+
Returns
2519+
-------
2520+
vtkActor
2521+
"""
2522+
2523+
verts, faces = fp.prim_box()
2524+
2525+
repeated = fp.repeat_primitive(verts, faces, centers=centers,
2526+
colors=colors, directions=directions,
2527+
scale=scale)
2528+
2529+
rep_verts, rep_faces, rep_colors, rep_centers = repeated
2530+
box_actor = get_actor_from_primitive(rep_verts, rep_faces, rep_colors)
2531+
2532+
vtk_center = numpy_support.numpy_to_vtk(rep_centers)
2533+
vtk_center.SetNumberOfComponents(3)
2534+
vtk_center.SetName("center")
2535+
box_actor.GetMapper().GetInput().GetPointData().AddArray(vtk_center)
2536+
2537+
vs_dec_code = fs.load("sdf_dec.vert")
2538+
vs_impl_code = fs.load("sdf_impl.vert")
2539+
fs_dec_code = fs.load("sdfsh_dec.frag")
2540+
fs_impl_code = fs.load("sdfsh_impl.frag")
2541+
2542+
mapper = box_actor.GetMapper()
2543+
mapper.MapDataArrayToVertexAttribute(
2544+
"center", "center", vtk.vtkDataObject.FIELD_ASSOCIATION_POINTS, -1)
2545+
2546+
mapper.AddShaderReplacement(
2547+
vtk.vtkShader.Vertex, "//VTK::ValuePass::Dec", True,
2548+
vs_dec_code, False)
2549+
2550+
mapper.AddShaderReplacement(
2551+
vtk.vtkShader.Vertex, "//VTK::ValuePass::Impl", True,
2552+
vs_impl_code, False)
2553+
2554+
mapper.AddShaderReplacement(
2555+
vtk.vtkShader.Fragment, "//VTK::ValuePass::Dec", True,
2556+
fs_dec_code, False)
2557+
2558+
mapper.AddShaderReplacement(
2559+
vtk.vtkShader.Fragment, "//VTK::Light::Impl", True,
2560+
fs_impl_code, False)
2561+
2562+
return box_actor
2563+

fury/shaders/sdf_dec.vert

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/* SDF vertex shader declaration */
2+
3+
//VTK::ValuePass::Dec
4+
5+
in vec3 center;
6+
out vec4 vertexMCVSOutput;
7+
8+
out vec3 centerWCVSOutput;

fury/shaders/sdf_impl.vert

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/* SDF vertex shader implementation */
2+
3+
//VTK::ValuePass::Impl
4+
5+
vertexMCVSOutput = vertexMC;
6+
centerWCVSOutput = center;

fury/shaders/sdfsh_dec.frag

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/* SDF fragment shader declaration */
2+
3+
4+
in vec4 vertexMCVSOutput;
5+
in vec3 centerWCVSOutput;
6+
7+
uniform mat4 MCVCMatrix;
8+
uniform mat4 MCWCMatrix;
9+
uniform mat3 WCVCMatrix;
10+
11+
12+
#define PI 3.1415926535898
13+
#define E 2.7182818284591
14+
15+
//DIPY default basis
16+
17+
18+
#define c01 2.82064703e-01
19+
#define c02 6.90495017e-02
20+
#define c03 -7.97628948e-02
21+
#define c04 9.29992151e-02
22+
#define c05 -1.98478828e-06
23+
#define c06 2.22295059e-06
24+
#define c07 2.21050672e-02
25+
#define c08 -3.61304561e-02
26+
#define c09 1.67251336e-02
27+
#define c10 2.27264752e-02
28+
#define c11 3.77708897e-02
29+
#define c12 -3.55761267e-06
30+
#define c13 -2.24799994e-05
31+
#define c14 4.40539515e-06
32+
#define c15 2.36901715e-06
33+
34+
35+
float P(int l, int m, float x)
36+
{
37+
float pmm = 1.0;
38+
if (m > 0)
39+
{
40+
float somx2 = sqrt((1.0-x)*(1.0+x));
41+
float fact = 1.0;
42+
for (int i = 1; i <= m; i++)
43+
{
44+
pmm *= (-fact) * somx2;
45+
fact += 2.0;
46+
}
47+
}
48+
if (l == m) return pmm;
49+
float pmmp1 = x * float(2*m + 1) * pmm;
50+
if (l == m+1) return pmmp1;
51+
float pll = 0.0;
52+
for (int ll = m+2; ll <= l; ll++)
53+
{
54+
pll = (float(2*ll-1)*x*pmmp1-float(ll+m-1)*pmm) / float(ll - m);
55+
pmm = pmmp1;
56+
pmmp1 = pll;
57+
}
58+
return pll;
59+
}
60+
61+
62+
63+
// Clenshaw Legendre normalized
64+
float Pgn(int l, int m, float x)
65+
{
66+
float p0 = 0.;
67+
float p1 = 0.;
68+
float p2 = 0.;
69+
70+
for (int k = l; k >= 0; k--)
71+
{
72+
float k1 = float(k + 1);
73+
float m1 = float(2 * m) + k1;
74+
float m2 = float(2 * (m + k) + 1);
75+
76+
p2 = p1;
77+
p1 = p0;
78+
79+
p0 = 0.;
80+
if (l == m + k)
81+
p0 += 1.;
82+
83+
float u0 = sqrt(
84+
(m2 * (m2 + 2.0)) /
85+
(k1 * m1)
86+
);
87+
88+
float u1 = sqrt(
89+
(k1 * m1 * (m2 + 4.0)) /
90+
((k1 + 1.0) * (m1 + 1.0) * m2)
91+
);
92+
p0 += p1 * u0 * x;
93+
p0 += -u1 * p2;
94+
}
95+
96+
for (int k = 1; k <= m; k++){
97+
p0 *= sqrt(
98+
(1.0 - 0.5/float(k)) * (1.0 - x) * (1.0 + x)
99+
);
100+
}
101+
102+
p0 *= sqrt((0.5 * float(m) + 0.25)/PI);
103+
return p0;
104+
}
105+
106+
107+
108+
float gammaln(float x){
109+
return log(x);
110+
}
111+
112+
float SHH(in int l, in int m, in vec3 s )
113+
{
114+
vec3 ns = normalize(s);
115+
float val = P(l, m, ns.x);
116+
val *= sqrt( (2*m + 1) / 4.0 / PI);
117+
val *= exp(0.5 * (gammaln(l - m + 1) - gammaln(l + m + 1)));
118+
val = val * exp(-1 * m * ns.y);
119+
return val;
120+
}
121+
122+
123+
124+
// Y_l_m(s), where l is the band and m the range in [-l..l]
125+
float SH( in int l, in int m, in vec3 s )
126+
{
127+
vec3 ns = s;
128+
//vec3 ns = normalize(s);
129+
130+
if (m < 0) {
131+
float c = ns.x;
132+
ns.x = ns.z;
133+
ns.z = c;
134+
m = -m;
135+
}
136+
137+
// spherical coordinates
138+
float thetax = ns.y;
139+
float phi = atan(ns.z, ns.x);
140+
141+
float pl = Pgn(l, m, thetax);
142+
143+
float r = pow(-1.0, float(m)) * cos(float(m) * phi) * pl;
144+
145+
return r;
146+
}
147+
148+
vec3 map( in vec3 position)
149+
{
150+
vec3 p00 = position - centerWCVSOutput;
151+
float r, d;
152+
vec3 n, s, res;
153+
154+
d = length(p00);
155+
n = p00/d;
156+
157+
158+
r = c01 * SH(0, 0, n);
159+
r += c02 * SH(2, -2, n);
160+
r += c03 * SH(2, -1, n);
161+
r += c04 * SH(2, 0, n);
162+
r += c05 * SH(2, 1, n);
163+
r += c06 * SH(2, 2, n);
164+
r += c07 * SH(4, -4, n);
165+
r += c08 * SH(4, -3, n);
166+
r += c09 * SH(4, -2, n);
167+
r += c10 * SH(4, -1, n);
168+
r += c11 * SH(4, 0, n);
169+
r += c12 * SH(4, 1, n);
170+
r += c13 * SH(4, 2, n);
171+
r += c14 * SH(4, 3, n);
172+
r += c15 * SH(4, 4, n);
173+
174+
#define SHAPE (vec3(d-abs(r), sign(r),d))
175+
176+
s = SHAPE;
177+
res = s;
178+
179+
return vec3(res.x, 0.5 + 0.5 * res.y, res.z);
180+
}
181+
182+
vec3 calculateNormal( in vec3 pos )
183+
{
184+
vec2 e = vec2(1.0,-1.0)*0.5773*0.0005;
185+
return normalize( e.xyy*map( pos + e.xyy ).x +
186+
e.yyx*map( pos + e.yyx ).x +
187+
e.yxy*map( pos + e.yxy ).x +
188+
e.xxx*map( pos + e.xxx ).x );
189+
190+
}
191+
192+
193+
vec3 castRay(in vec3 ro, vec3 rd)
194+
{
195+
vec3 res = vec3(1e10, -1.0, 1.0);
196+
197+
float t = 0.0;
198+
float h = 1.0;
199+
vec2 m = vec2(-1.0);
200+
201+
for(int i=0;i<200;i++){
202+
203+
if(h<0.001) break;
204+
205+
vec3 position = ro+t*rd;
206+
207+
vec3 res = map( position );
208+
209+
h = res.x;
210+
m = res.yz;
211+
t += h*0.3;
212+
}
213+
214+
if( t<res.x ) res = vec3(t, m);
215+
216+
217+
return res;
218+
}
219+

fury/shaders/sdfsh_impl.frag

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* SDF fragment shader implementation */
2+
3+
//VKT::Light::Impl
4+
5+
vec3 point = vertexMCVSOutput.xyz;
6+
7+
//ray origin
8+
vec4 ro = -MCVCMatrix[3] * MCVCMatrix; // camera position in world space
9+
10+
vec3 col = vertexColorVSOutput.rgb;
11+
12+
//ray direction
13+
vec3 rd = normalize(point - ro.xyz);
14+
15+
16+
vec3 t = castRay(ro.xyz, rd);
17+
18+
if(t.y > -0.05)
19+
{
20+
21+
vec3 pos = ro.xyz + t.x*rd;
22+
vec3 normal = calculateNormal(pos);
23+
vec3 ref = reflect( rd, normal );
24+
25+
26+
float occ = clamp( 2.0*t.z, 0.0, 1.0 );
27+
float sss = pow( clamp( 1.0 + dot(normal, rd), 0.0, 1.0 ), 1.0 );
28+
29+
// lights
30+
vec3 lin = 2.5*occ*vec3(1.0,1.00,1.00)*(0.6+0.4*normal.y);
31+
lin += 1.0*sss*vec3(1.0,0.95,0.70)*occ;
32+
33+
vec3 mater = 0.5*mix( vec3(1.0,0.6,0.15), vec3(0.2,0.4,0.5), t.y );
34+
35+
fragOutput0 = vec4( mater * lin , 1.0);
36+
//fragOutput0 = vec4( norm, 1.0);
37+
38+
}
39+
else{
40+
//fragOutput0 = vec4(0, 0, 0, 0.3);
41+
discard;
42+
}

test_sh.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from fury import actor, window, ui
2+
import numpy as np
3+
import itertools
4+
5+
6+
tb = ui.TextBlock2D(font_size=20, color=(1, 0.5, 1))
7+
panel = ui.Panel2D(position=(400,400), size = (500, 150))
8+
panel.add_element(tb, (0.2, 0.5))
9+
10+
11+
scene = window.Scene()
12+
scene.background((1.0, 0.8, 0.8))
13+
# dirs = np.random.rand(7, 3)
14+
# colors = np.random.rand(7, 3) * 255
15+
# centers = np.array([[2, 0, 0], [0, 0, 0], [-2, 0, 0], [0, 2, 0], [0, -2, 0],
16+
# [0, 0, -2], [0, 0, 2]])
17+
centers = np.array([[0, 0, 0]])
18+
sdfactor = actor.sdf_sh(centers=centers)
19+
20+
fpss = []
21+
22+
counter = itertools.count()
23+
showm = window.ShowManager(scene, reset_camera=False )
24+
25+
showm.initialize()
26+
27+
28+
scene.add(sdfactor)
29+
scene.add(panel)
30+
31+
32+
def timer_callback(_obj, _event):
33+
cnt = next(counter)
34+
showm.render()
35+
36+
if cnt % 1 == 0:
37+
fps = scene.frame_rate
38+
fpss.append(fps)
39+
msg = "FPS: " + str(fps)
40+
tb.message = msg
41+
42+
if(cnt==2000):
43+
showm.exit()
44+
45+
46+
47+
48+
showm.add_timer_callback(True, 10, timer_callback)
49+
showm.start()

0 commit comments

Comments
 (0)