opengl_sphere.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
  3. //
  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
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #include <iostream>
  11. #include <algorithm>
  12. #include <GL/gl.h>
  13. #include <vtkActor.h>
  14. #include <vtkCamera.h>
  15. #include <vtkgl.h>
  16. #include <vtkInteractorStyleSwitch.h>
  17. #include <vtkMapper.h>
  18. #include <vtkObjectFactory.h>
  19. #include <vtkOpenGLExtensionManager.h>
  20. #include <vtkOpenGLRenderWindow.h>
  21. #include <vtkProperty.h>
  22. #include <vtkRenderer.h>
  23. #include <vtkRenderWindow.h>
  24. #include <vtkRenderWindowInteractor.h>
  25. #include <vtkSmartPointer.h>
  26. #include <boost/compute/system.hpp>
  27. #include <boost/compute/algorithm/iota.hpp>
  28. #include <boost/compute/interop/opengl.hpp>
  29. #include <boost/compute/interop/vtk.hpp>
  30. #include <boost/compute/utility/dim.hpp>
  31. #include <boost/compute/utility/source.hpp>
  32. namespace compute = boost::compute;
  33. // tesselates a sphere with radius, phi_slices, and theta_slices. returns
  34. // a shared opencl/opengl buffer containing the vertex data.
  35. compute::opengl_buffer tesselate_sphere(float radius,
  36. size_t phi_slices,
  37. size_t theta_slices,
  38. compute::command_queue &queue)
  39. {
  40. using compute::dim;
  41. const compute::context &context = queue.get_context();
  42. const size_t vertex_count = phi_slices * theta_slices;
  43. // create opengl buffer
  44. GLuint vbo;
  45. vtkgl::GenBuffersARB(1, &vbo);
  46. vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, vbo);
  47. vtkgl::BufferDataARB(vtkgl::ARRAY_BUFFER,
  48. sizeof(float) * 4 * vertex_count,
  49. NULL,
  50. vtkgl::STREAM_DRAW);
  51. vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, 0);
  52. // create shared opengl/opencl buffer
  53. compute::opengl_buffer vertex_buffer(context, vbo);
  54. // tesselate_sphere kernel source
  55. const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
  56. __kernel void tesselate_sphere(float radius,
  57. uint phi_slices,
  58. uint theta_slices,
  59. __global float4 *vertex_buffer)
  60. {
  61. const uint phi_i = get_global_id(0);
  62. const uint theta_i = get_global_id(1);
  63. const float phi = phi_i * 2.f * M_PI_F / phi_slices;
  64. const float theta = theta_i * 2.f * M_PI_F / theta_slices;
  65. float4 v;
  66. v.x = radius * cos(theta) * cos(phi);
  67. v.y = radius * cos(theta) * sin(phi);
  68. v.z = radius * sin(theta);
  69. v.w = 1.f;
  70. vertex_buffer[phi_i*phi_slices+theta_i] = v;
  71. }
  72. );
  73. // build tesselate_sphere program
  74. compute::program program =
  75. compute::program::create_with_source(source, context);
  76. program.build();
  77. // setup tesselate_sphere kernel
  78. compute::kernel kernel(program, "tesselate_sphere");
  79. kernel.set_arg<compute::float_>(0, radius);
  80. kernel.set_arg<compute::uint_>(1, phi_slices);
  81. kernel.set_arg<compute::uint_>(2, theta_slices);
  82. kernel.set_arg(3, vertex_buffer);
  83. // acqurire buffer so that it is accessible to OpenCL
  84. compute::opengl_enqueue_acquire_buffer(vertex_buffer, queue);
  85. // execute tesselate_sphere kernel
  86. queue.enqueue_nd_range_kernel(
  87. kernel, dim(0, 0), dim(phi_slices, theta_slices), dim(1, 1)
  88. );
  89. // release buffer so that it is accessible to OpenGL
  90. compute::opengl_enqueue_release_buffer(vertex_buffer, queue);
  91. return vertex_buffer;
  92. }
  93. // simple vtkMapper subclass to render the tesselated sphere on the gpu.
  94. class gpu_sphere_mapper : public vtkMapper
  95. {
  96. public:
  97. vtkTypeMacro(gpu_sphere_mapper, vtkMapper)
  98. static gpu_sphere_mapper* New()
  99. {
  100. return new gpu_sphere_mapper;
  101. }
  102. void Render(vtkRenderer *renderer, vtkActor *actor)
  103. {
  104. if(!m_initialized){
  105. Initialize(renderer, actor);
  106. m_initialized = true;
  107. }
  108. if(!m_tesselated){
  109. m_vertex_count = m_phi_slices * m_theta_slices;
  110. // tesselate sphere
  111. m_vertex_buffer = tesselate_sphere(
  112. m_radius, m_phi_slices, m_theta_slices, m_command_queue
  113. );
  114. // ensure tesselation is finished (seems to be required on AMD)
  115. m_command_queue.finish();
  116. // set tesselated flag to true
  117. m_tesselated = true;
  118. }
  119. // draw sphere
  120. glEnableClientState(GL_VERTEX_ARRAY);
  121. vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, m_vertex_buffer.get_opengl_object());
  122. glVertexPointer(4, GL_FLOAT, sizeof(float)*4, 0);
  123. glDrawArrays(GL_POINTS, 0, m_vertex_count);
  124. }
  125. void Initialize(vtkRenderer *renderer, vtkActor *actor)
  126. {
  127. // initialize opengl extensions
  128. vtkOpenGLExtensionManager *extensions =
  129. static_cast<vtkOpenGLRenderWindow *>(renderer->GetRenderWindow())
  130. ->GetExtensionManager();
  131. extensions->LoadExtension("GL_ARB_vertex_buffer_object");
  132. // initialize opencl/opengl shared context
  133. m_context = compute::opengl_create_shared_context();
  134. compute::device device = m_context.get_device();
  135. std::cout << "device: " << device.name() << std::endl;
  136. // create command queue for the gpu device
  137. m_command_queue = compute::command_queue(m_context, device);
  138. }
  139. double* GetBounds()
  140. {
  141. static double bounds[6];
  142. bounds[0] = -m_radius; bounds[1] = m_radius;
  143. bounds[2] = -m_radius; bounds[3] = m_radius;
  144. bounds[4] = -m_radius; bounds[5] = m_radius;
  145. return bounds;
  146. }
  147. protected:
  148. gpu_sphere_mapper()
  149. {
  150. m_radius = 5.0f;
  151. m_phi_slices = 100;
  152. m_theta_slices = 100;
  153. m_initialized = false;
  154. m_tesselated = false;
  155. }
  156. private:
  157. float m_radius;
  158. int m_phi_slices;
  159. int m_theta_slices;
  160. int m_vertex_count;
  161. bool m_initialized;
  162. bool m_tesselated;
  163. compute::context m_context;
  164. compute::command_queue m_command_queue;
  165. compute::opengl_buffer m_vertex_buffer;
  166. };
  167. int main(int argc, char *argv[])
  168. {
  169. // create gpu sphere mapper
  170. vtkSmartPointer<gpu_sphere_mapper> mapper =
  171. vtkSmartPointer<gpu_sphere_mapper>::New();
  172. // create actor for gpu sphere mapper
  173. vtkSmartPointer<vtkActor> actor =
  174. vtkSmartPointer<vtkActor>::New();
  175. actor->GetProperty()->LightingOff();
  176. actor->GetProperty()->SetInterpolationToFlat();
  177. actor->SetMapper(mapper);
  178. // create render window
  179. vtkSmartPointer<vtkRenderer> renderer =
  180. vtkSmartPointer<vtkRenderer>::New();
  181. renderer->SetBackground(.1, .2, .31);
  182. vtkSmartPointer<vtkRenderWindow> renderWindow =
  183. vtkSmartPointer<vtkRenderWindow>::New();
  184. renderWindow->SetSize(800, 600);
  185. renderWindow->AddRenderer(renderer);
  186. vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
  187. vtkSmartPointer<vtkRenderWindowInteractor>::New();
  188. vtkInteractorStyleSwitch *interactorStyle =
  189. vtkInteractorStyleSwitch::SafeDownCast(
  190. renderWindowInteractor->GetInteractorStyle()
  191. );
  192. interactorStyle->SetCurrentStyleToTrackballCamera();
  193. renderWindowInteractor->SetRenderWindow(renderWindow);
  194. renderer->AddActor(actor);
  195. // render
  196. renderer->ResetCamera();
  197. vtkCamera *camera = renderer->GetActiveCamera();
  198. camera->Elevation(-90.0);
  199. renderWindowInteractor->Initialize();
  200. renderWindow->Render();
  201. renderWindowInteractor->Start();
  202. return 0;
  203. }