123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- //---------------------------------------------------------------------------//
- // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com>
- //
- // Distributed under the Boost Software License, Version 1.0
- // See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt
- //
- // See http://boostorg.github.com/compute for more information.
- //---------------------------------------------------------------------------//
- #include <iostream>
- #include <algorithm>
- #include <GL/gl.h>
- #include <vtkActor.h>
- #include <vtkCamera.h>
- #include <vtkgl.h>
- #include <vtkInteractorStyleSwitch.h>
- #include <vtkMapper.h>
- #include <vtkObjectFactory.h>
- #include <vtkOpenGLExtensionManager.h>
- #include <vtkOpenGLRenderWindow.h>
- #include <vtkProperty.h>
- #include <vtkRenderer.h>
- #include <vtkRenderWindow.h>
- #include <vtkRenderWindowInteractor.h>
- #include <vtkSmartPointer.h>
- #include <boost/compute/system.hpp>
- #include <boost/compute/algorithm/iota.hpp>
- #include <boost/compute/interop/opengl.hpp>
- #include <boost/compute/interop/vtk.hpp>
- #include <boost/compute/utility/dim.hpp>
- #include <boost/compute/utility/source.hpp>
- namespace compute = boost::compute;
- // tesselates a sphere with radius, phi_slices, and theta_slices. returns
- // a shared opencl/opengl buffer containing the vertex data.
- compute::opengl_buffer tesselate_sphere(float radius,
- size_t phi_slices,
- size_t theta_slices,
- compute::command_queue &queue)
- {
- using compute::dim;
- const compute::context &context = queue.get_context();
- const size_t vertex_count = phi_slices * theta_slices;
- // create opengl buffer
- GLuint vbo;
- vtkgl::GenBuffersARB(1, &vbo);
- vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, vbo);
- vtkgl::BufferDataARB(vtkgl::ARRAY_BUFFER,
- sizeof(float) * 4 * vertex_count,
- NULL,
- vtkgl::STREAM_DRAW);
- vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, 0);
- // create shared opengl/opencl buffer
- compute::opengl_buffer vertex_buffer(context, vbo);
- // tesselate_sphere kernel source
- const char source[] = BOOST_COMPUTE_STRINGIZE_SOURCE(
- __kernel void tesselate_sphere(float radius,
- uint phi_slices,
- uint theta_slices,
- __global float4 *vertex_buffer)
- {
- const uint phi_i = get_global_id(0);
- const uint theta_i = get_global_id(1);
- const float phi = phi_i * 2.f * M_PI_F / phi_slices;
- const float theta = theta_i * 2.f * M_PI_F / theta_slices;
- float4 v;
- v.x = radius * cos(theta) * cos(phi);
- v.y = radius * cos(theta) * sin(phi);
- v.z = radius * sin(theta);
- v.w = 1.f;
- vertex_buffer[phi_i*phi_slices+theta_i] = v;
- }
- );
- // build tesselate_sphere program
- compute::program program =
- compute::program::create_with_source(source, context);
- program.build();
- // setup tesselate_sphere kernel
- compute::kernel kernel(program, "tesselate_sphere");
- kernel.set_arg<compute::float_>(0, radius);
- kernel.set_arg<compute::uint_>(1, phi_slices);
- kernel.set_arg<compute::uint_>(2, theta_slices);
- kernel.set_arg(3, vertex_buffer);
- // acqurire buffer so that it is accessible to OpenCL
- compute::opengl_enqueue_acquire_buffer(vertex_buffer, queue);
- // execute tesselate_sphere kernel
- queue.enqueue_nd_range_kernel(
- kernel, dim(0, 0), dim(phi_slices, theta_slices), dim(1, 1)
- );
- // release buffer so that it is accessible to OpenGL
- compute::opengl_enqueue_release_buffer(vertex_buffer, queue);
- return vertex_buffer;
- }
- // simple vtkMapper subclass to render the tesselated sphere on the gpu.
- class gpu_sphere_mapper : public vtkMapper
- {
- public:
- vtkTypeMacro(gpu_sphere_mapper, vtkMapper)
- static gpu_sphere_mapper* New()
- {
- return new gpu_sphere_mapper;
- }
- void Render(vtkRenderer *renderer, vtkActor *actor)
- {
- if(!m_initialized){
- Initialize(renderer, actor);
- m_initialized = true;
- }
- if(!m_tesselated){
- m_vertex_count = m_phi_slices * m_theta_slices;
- // tesselate sphere
- m_vertex_buffer = tesselate_sphere(
- m_radius, m_phi_slices, m_theta_slices, m_command_queue
- );
- // ensure tesselation is finished (seems to be required on AMD)
- m_command_queue.finish();
- // set tesselated flag to true
- m_tesselated = true;
- }
- // draw sphere
- glEnableClientState(GL_VERTEX_ARRAY);
- vtkgl::BindBufferARB(vtkgl::ARRAY_BUFFER, m_vertex_buffer.get_opengl_object());
- glVertexPointer(4, GL_FLOAT, sizeof(float)*4, 0);
- glDrawArrays(GL_POINTS, 0, m_vertex_count);
- }
- void Initialize(vtkRenderer *renderer, vtkActor *actor)
- {
- // initialize opengl extensions
- vtkOpenGLExtensionManager *extensions =
- static_cast<vtkOpenGLRenderWindow *>(renderer->GetRenderWindow())
- ->GetExtensionManager();
- extensions->LoadExtension("GL_ARB_vertex_buffer_object");
- // initialize opencl/opengl shared context
- m_context = compute::opengl_create_shared_context();
- compute::device device = m_context.get_device();
- std::cout << "device: " << device.name() << std::endl;
- // create command queue for the gpu device
- m_command_queue = compute::command_queue(m_context, device);
- }
- double* GetBounds()
- {
- static double bounds[6];
- bounds[0] = -m_radius; bounds[1] = m_radius;
- bounds[2] = -m_radius; bounds[3] = m_radius;
- bounds[4] = -m_radius; bounds[5] = m_radius;
- return bounds;
- }
- protected:
- gpu_sphere_mapper()
- {
- m_radius = 5.0f;
- m_phi_slices = 100;
- m_theta_slices = 100;
- m_initialized = false;
- m_tesselated = false;
- }
- private:
- float m_radius;
- int m_phi_slices;
- int m_theta_slices;
- int m_vertex_count;
- bool m_initialized;
- bool m_tesselated;
- compute::context m_context;
- compute::command_queue m_command_queue;
- compute::opengl_buffer m_vertex_buffer;
- };
- int main(int argc, char *argv[])
- {
- // create gpu sphere mapper
- vtkSmartPointer<gpu_sphere_mapper> mapper =
- vtkSmartPointer<gpu_sphere_mapper>::New();
- // create actor for gpu sphere mapper
- vtkSmartPointer<vtkActor> actor =
- vtkSmartPointer<vtkActor>::New();
- actor->GetProperty()->LightingOff();
- actor->GetProperty()->SetInterpolationToFlat();
- actor->SetMapper(mapper);
- // create render window
- vtkSmartPointer<vtkRenderer> renderer =
- vtkSmartPointer<vtkRenderer>::New();
- renderer->SetBackground(.1, .2, .31);
- vtkSmartPointer<vtkRenderWindow> renderWindow =
- vtkSmartPointer<vtkRenderWindow>::New();
- renderWindow->SetSize(800, 600);
- renderWindow->AddRenderer(renderer);
- vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
- vtkSmartPointer<vtkRenderWindowInteractor>::New();
- vtkInteractorStyleSwitch *interactorStyle =
- vtkInteractorStyleSwitch::SafeDownCast(
- renderWindowInteractor->GetInteractorStyle()
- );
- interactorStyle->SetCurrentStyleToTrackballCamera();
- renderWindowInteractor->SetRenderWindow(renderWindow);
- renderer->AddActor(actor);
- // render
- renderer->ResetCamera();
- vtkCamera *camera = renderer->GetActiveCamera();
- camera->Elevation(-90.0);
- renderWindowInteractor->Initialize();
- renderWindow->Render();
- renderWindowInteractor->Start();
- return 0;
- }
|