1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
17 #include <vtkCamera.h>
19 #include <vtkInteractorStyleSwitch.h>
20 #include <vtkMapper.h>
21 #include <vtkObjectFactory.h>
22 #include <vtkOpenGLExtensionManager.h>
23 #include <vtkOpenGLRenderWindow.h>
24 #include <vtkProperty.h>
25 #include <vtkRenderer.h>
26 #include <vtkRenderWindow.h>
27 #include <vtkRenderWindowInteractor.h>
28 #include <vtkSmartPointer.h>
30 #include <boost/compute/system.hpp>
31 #include <boost/compute/algorithm/iota.hpp>
32 #include <boost/compute/interop/opengl.hpp>
33 #include <boost/compute/interop/vtk.hpp>
34 #include <boost/compute/utility/dim.hpp>
35 #include <boost/compute/utility/source.hpp>
37 namespace compute
= boost::compute
;
39 // tesselates a sphere with radius, phi_slices, and theta_slices. returns
40 // a shared opencl/opengl buffer containing the vertex data.
41 compute::opengl_buffer
tesselate_sphere(float radius
,
44 compute::command_queue
&queue
)
48 const compute::context
&context
= queue
.get_context();
50 const size_t vertex_count
= phi_slices
* theta_slices
;
52 // create opengl buffer
54 vtkgl::GenBuffersARB(1, &vbo
);
55 vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER
, vbo
);
56 vtkgl::BufferDataARB(vtkgl::ARRAY_BUFFER
,
57 sizeof(float) * 4 * vertex_count
,
60 vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER
, 0);
62 // create shared opengl/opencl buffer
63 compute::opengl_buffer
vertex_buffer(context
, vbo
);
65 // tesselate_sphere kernel source
66 const char source
[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
67 __kernel
void tesselate_sphere(float radius
,
70 __global float4
*vertex_buffer
)
72 const uint phi_i
= get_global_id(0);
73 const uint theta_i
= get_global_id(1);
75 const float phi
= phi_i
* 2.f
* M_PI_F
/ phi_slices
;
76 const float theta
= theta_i
* 2.f
* M_PI_F
/ theta_slices
;
79 v
.x
= radius
* cos(theta
) * cos(phi
);
80 v
.y
= radius
* cos(theta
) * sin(phi
);
81 v
.z
= radius
* sin(theta
);
84 vertex_buffer
[phi_i
*phi_slices
+theta_i
] = v
;
88 // build tesselate_sphere program
89 compute::program program
=
90 compute::program::create_with_source(source
, context
);
93 // setup tesselate_sphere kernel
94 compute::kernel
kernel(program
, "tesselate_sphere");
95 kernel
.set_arg
<compute::float_
>(0, radius
);
96 kernel
.set_arg
<compute::uint_
>(1, phi_slices
);
97 kernel
.set_arg
<compute::uint_
>(2, theta_slices
);
98 kernel
.set_arg(3, vertex_buffer
);
100 // acqurire buffer so that it is accessible to OpenCL
101 compute::opengl_enqueue_acquire_buffer(vertex_buffer
, queue
);
103 // execute tesselate_sphere kernel
104 queue
.enqueue_nd_range_kernel(
105 kernel
, dim(0, 0), dim(phi_slices
, theta_slices
), dim(1, 1)
108 // release buffer so that it is accessible to OpenGL
109 compute::opengl_enqueue_release_buffer(vertex_buffer
, queue
);
111 return vertex_buffer
;
114 // simple vtkMapper subclass to render the tesselated sphere on the gpu.
115 class gpu_sphere_mapper
: public vtkMapper
118 vtkTypeMacro(gpu_sphere_mapper
, vtkMapper
)
120 static gpu_sphere_mapper
* New()
122 return new gpu_sphere_mapper
;
125 void Render(vtkRenderer
*renderer
, vtkActor
*actor
)
128 Initialize(renderer
, actor
);
129 m_initialized
= true;
133 m_vertex_count
= m_phi_slices
* m_theta_slices
;
136 m_vertex_buffer
= tesselate_sphere(
137 m_radius
, m_phi_slices
, m_theta_slices
, m_command_queue
140 // ensure tesselation is finished (seems to be required on AMD)
141 m_command_queue
.finish();
143 // set tesselated flag to true
148 glEnableClientState(GL_VERTEX_ARRAY
);
149 vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER
, m_vertex_buffer
.get_opengl_object());
150 glVertexPointer(4, GL_FLOAT
, sizeof(float)*4, 0);
151 glDrawArrays(GL_POINTS
, 0, m_vertex_count
);
154 void Initialize(vtkRenderer
*renderer
, vtkActor
*actor
)
156 // initialize opengl extensions
157 vtkOpenGLExtensionManager
*extensions
=
158 static_cast<vtkOpenGLRenderWindow
*>(renderer
->GetRenderWindow())
159 ->GetExtensionManager();
160 extensions
->LoadExtension("GL_ARB_vertex_buffer_object");
162 // initialize opencl/opengl shared context
163 m_context
= compute::opengl_create_shared_context();
164 compute::device device
= m_context
.get_device();
165 std::cout
<< "device: " << device
.name() << std::endl
;
167 // create command queue for the gpu device
168 m_command_queue
= compute::command_queue(m_context
, device
);
173 static double bounds
[6];
174 bounds
[0] = -m_radius
; bounds
[1] = m_radius
;
175 bounds
[2] = -m_radius
; bounds
[3] = m_radius
;
176 bounds
[4] = -m_radius
; bounds
[5] = m_radius
;
185 m_theta_slices
= 100;
186 m_initialized
= false;
187 m_tesselated
= false;
197 compute::context m_context
;
198 compute::command_queue m_command_queue
;
199 compute::opengl_buffer m_vertex_buffer
;
202 int main(int argc
, char *argv
[])
204 // create gpu sphere mapper
205 vtkSmartPointer
<gpu_sphere_mapper
> mapper
=
206 vtkSmartPointer
<gpu_sphere_mapper
>::New();
208 // create actor for gpu sphere mapper
209 vtkSmartPointer
<vtkActor
> actor
=
210 vtkSmartPointer
<vtkActor
>::New();
211 actor
->GetProperty()->LightingOff();
212 actor
->GetProperty()->SetInterpolationToFlat();
213 actor
->SetMapper(mapper
);
215 // create render window
216 vtkSmartPointer
<vtkRenderer
> renderer
=
217 vtkSmartPointer
<vtkRenderer
>::New();
218 renderer
->SetBackground(.1, .2, .31);
219 vtkSmartPointer
<vtkRenderWindow
> renderWindow
=
220 vtkSmartPointer
<vtkRenderWindow
>::New();
221 renderWindow
->SetSize(800, 600);
222 renderWindow
->AddRenderer(renderer
);
223 vtkSmartPointer
<vtkRenderWindowInteractor
> renderWindowInteractor
=
224 vtkSmartPointer
<vtkRenderWindowInteractor
>::New();
225 vtkInteractorStyleSwitch
*interactorStyle
=
226 vtkInteractorStyleSwitch::SafeDownCast(
227 renderWindowInteractor
->GetInteractorStyle()
229 interactorStyle
->SetCurrentStyleToTrackballCamera();
230 renderWindowInteractor
->SetRenderWindow(renderWindow
);
231 renderer
->AddActor(actor
);
234 renderer
->ResetCamera();
235 vtkCamera
*camera
= renderer
->GetActiveCamera();
236 camera
->Elevation(-90.0);
237 renderWindowInteractor
->Initialize();
238 renderWindow
->Render();
239 renderWindowInteractor
->Start();