11#include " orbbec.hpp"
22#include < libobsensor/ObSensor.hpp>
3+ #include " godot_cpp/classes/rendering_server.hpp"
34#include < godot_cpp/variant/packed_vector3_array.hpp>
45#include < stdlib.h>
56
@@ -40,41 +41,7 @@ PackedStringArray OrbbecDevices::get_devices_serial_numbers() {
4041 return serials;
4142};
4243
43- OrbbecPointCloud::OrbbecPointCloud () {
44- // create a random thinning mask.
45- for (int i=0 ; i < thinning_mask_size; ++i) {
46- thinning_mask[i] = static_cast <float >(rand ()) / static_cast <float >(RAND_MAX );
47- }
48- }
49-
50- void OrbbecPointCloud::set_thinning (float thin) {
51- thinning = thin;
52- }
53-
54- float OrbbecPointCloud::get_thinning () {
55- return thinning;
56- }
57-
58- PackedStringArray OrbbecPointCloud::get_device_stream_formats () {
59- // TODO: make this dynamic when we support more camera types.
60- // I tried to make this a static const inline and it made godot crash everytime.
61- // This will have to be good enough.
62- return PackedStringArray {" 1024x1024 (WFOV Unbinned)" , " 512x512 (WFOV Binned)" , " 640x576 (NFOV Unbinned)" , " 320x288 (NFOV Binned)" };
63- }
64-
65- void OrbbecPointCloud::_bind_methods () {
66- godot::ClassDB::bind_method (D_METHOD (" start_stream" , " xres" , " yres" , " framerate" ), &OrbbecPointCloud::start_stream);
67- godot::ClassDB::bind_method (D_METHOD (" stop_stream" ), &OrbbecPointCloud::stop_stream);
68- godot::ClassDB::bind_method (D_METHOD (" set_device_from_ip" , " ip" ), &OrbbecPointCloud::set_device_from_ip);
69- godot::ClassDB::bind_method (D_METHOD (" set_device_from_serial_number" , " serial_number" ), &OrbbecPointCloud::set_device_from_serial_number);
70- godot::ClassDB::bind_method (D_METHOD (" get_thinning" ), &OrbbecPointCloud::get_thinning);
71- godot::ClassDB::bind_method (D_METHOD (" set_thinning" , " p_thinning" ), &OrbbecPointCloud::set_thinning);
72- godot::ClassDB::bind_method (D_METHOD (" get_device_stream_formats" ), &OrbbecPointCloud::get_device_stream_formats);
73- ADD_PROPERTY (PropertyInfo (Variant::FLOAT , " thinning" ), " set_thinning" , " get_thinning" );
74- ADD_SIGNAL (MethodInfo (" point_cloud_frame" , PropertyInfo (Variant::PACKED_VECTOR3_ARRAY , " points" ), PropertyInfo (Variant::PACKED_FLOAT32_ARRAY , " raw_buffer" )));
75- }
76-
77- void OrbbecPointCloud::set_device_from_predicate (predicate_type predicate) {
44+ void OrbbecPointCloudBase::set_device_from_predicate (predicate_type predicate) {
7845 std::shared_ptr<ob::DeviceList> devices = ob_ctx.queryDeviceList ();
7946 for (uint32_t i = 0 ; i < devices->getCount (); ++i) {
8047 if (predicate (devices, i)) {
@@ -90,33 +57,170 @@ void OrbbecPointCloud::set_device_from_predicate(predicate_type predicate) {
9057 }
9158}
9259
93- void OrbbecPointCloud ::set_device_from_ip (String ip) {
60+ void OrbbecPointCloudBase ::set_device_from_ip (String ip) {
9461 set_device_from_predicate ([&](std::shared_ptr<ob::DeviceList> devices, uint32_t idx) {
9562 return devices->getIpAddress (idx) == ip;
9663 });
9764}
9865
99- void OrbbecPointCloud ::set_device_from_serial_number (String serial_number) {
66+ void OrbbecPointCloudBase ::set_device_from_serial_number (String serial_number) {
10067 set_device_from_predicate ([&](std::shared_ptr<ob::DeviceList> devices, uint32_t idx) {
10168 return devices->getSerialNumber (idx) == serial_number;
10269 });
10370}
10471
105- void OrbbecPointCloud ::stop_stream () {
72+ void OrbbecPointCloudBase ::stop_stream () {
10673 // deleting the pipeline makes the stream stop.
10774 pipeline.reset ();
10875 // probably don't need to do this but it can't hurt too much
10976 config.reset ();
11077}
11178
79+ PackedStringArray OrbbecPointCloudBase::get_device_stream_formats () {
80+ // TODO: make this dynamic when we support more camera types.
81+ // I tried to make this a static const inline and it made godot crash everytime.
82+ // This will have to be good enough.
83+ return PackedStringArray {" 1024x1024 (WFOV Unbinned)" , " 512x512 (WFOV Binned)" , " 640x576 (NFOV Unbinned)" , " 320x288 (NFOV Binned)" };
84+ }
85+
86+ void OrbbecPointCloudBase::_bind_methods () {
87+ godot::ClassDB::bind_method (D_METHOD (" stop_stream" ), &OrbbecPointCloudBase::stop_stream);
88+ godot::ClassDB::bind_method (D_METHOD (" set_device_from_ip" , " ip" ), &OrbbecPointCloudBase::set_device_from_ip);
89+ godot::ClassDB::bind_method (D_METHOD (" set_device_from_serial_number" , " serial_number" ), &OrbbecPointCloudBase::set_device_from_serial_number);
90+ godot::ClassDB::bind_method (D_METHOD (" get_device_stream_formats" ), &OrbbecPointCloudBase::get_device_stream_formats);
91+ }
92+
93+ void OrbbecPointCloudGPU::allocate_point_cloud_buffer () {
94+ if (rd == nullptr ) {
95+ print_line (" please set a rendering device before starting a point cloud stream" );
96+ return ;
97+ }
98+ uint32_t bytes_needed = xres * yres * floats_per_points * bytes_per_float;
99+ std::cout << bytes_needed << " \n " ;
100+
101+ PackedByteArray empty_bytes{};
102+ empty_bytes.resize (bytes_needed);
103+ point_bytes.resize (bytes_needed);
104+ std::cout << " resized" << " \n " ;
105+ if (!rd->has_feature (RenderingDevice::Features::SUPPORTS_BUFFER_DEVICE_ADDRESS )) {
106+ std::cout << " supports" << " \n " ;
107+ point_buffer = rd->storage_buffer_create (bytes_needed, empty_bytes);
108+ print_line (" your GPU doesn't support getting device address. You won't be able to access the point cloud buffer by its gpu address." );
109+ } else {
110+ point_buffer = rd->storage_buffer_create (bytes_needed, empty_bytes, 0 , RenderingDevice::BufferCreationBits::BUFFER_CREATION_DEVICE_ADDRESS_BIT );
111+ }
112+ }
113+
114+ void OrbbecPointCloudGPU::_enter_tree () {
115+ if (rd != nullptr ) {
116+ allocate_point_cloud_buffer ();
117+ }
118+ }
119+
120+ void OrbbecPointCloudGPU::_exit_tree () {
121+ if (rd != nullptr ) {
122+ // delete buffer with num_points points
123+ rd->free_rid (point_buffer);
124+ }
125+ }
126+
127+ void OrbbecPointCloudGPU::set_rendering_device (RenderingDevice* rendering_device) {
128+ rd = rendering_device;
129+ }
130+
131+ RenderingDevice* OrbbecPointCloudGPU::get_rendering_device () {
132+ return rd;
133+ }
134+
135+ void OrbbecPointCloudGPU::_bind_methods () {
136+ godot::ClassDB::bind_method (D_METHOD (" start_stream" , " xres" , " yres" , " framerate" ), &OrbbecPointCloudBase::start_stream);
137+ godot::ClassDB::bind_method (D_METHOD (" get_rendering_device" ), &OrbbecPointCloudGPU::get_rendering_device);
138+ godot::ClassDB::bind_method (D_METHOD (" set_rendering_device" , " p_rendering_device" ), &OrbbecPointCloudGPU::set_rendering_device);
139+ godot::ClassDB::bind_method (D_METHOD (" get_num_points" ), &OrbbecPointCloudGPU::get_num_points);
140+ godot::ClassDB::bind_method (D_METHOD (" get_point_buffer_rid" ), &OrbbecPointCloudGPU::get_point_buffer_rid);
141+ godot::ClassDB::bind_method (D_METHOD (" update_point_cloud_buffer" ), &OrbbecPointCloudGPU::update_point_cloud_buffer);
142+ ADD_SIGNAL (MethodInfo (" point_cloud_frame" , PropertyInfo (Variant::RID , " point_cloud_buffer" ), PropertyInfo (Variant::PACKED_BYTE_ARRAY , " orbbec_bytes" )));
143+ }
144+
145+ RID OrbbecPointCloudGPU::get_point_buffer_rid () {
146+ return point_buffer;
147+ }
148+
149+ uint32_t OrbbecPointCloudGPU::get_num_points () {
150+ return xres*yres;
151+ }
152+
153+ void OrbbecPointCloudGPU::update_point_cloud_buffer () {
154+
155+ rd->buffer_update (point_buffer, 0 , point_bytes.size (), point_bytes);
156+ // not sure we need call_deferred here.
157+ emit_signal (" point_cloud_frame" , point_buffer, point_bytes);
158+ }
159+
160+ void OrbbecPointCloudGPU::start_stream (int xres, int yres, int framerate) {
161+ if (rd == nullptr ) {
162+ print_line (" please set a rendering device before starting a point cloud stream" );
163+ }
164+ if (!device) {
165+ print_line (" Not starting stream, please set a device." );
166+ return ;
167+ }
168+ try {
169+ point_cloud_filter->setCreatePointFormat (OB_FORMAT_POINT );
170+ pipeline = std::make_unique<ob::Pipeline>(device);
171+ pipeline->enableFrameSync ();
172+ config = std::make_shared<ob::Config>();
173+ config->enableVideoStream (OB_STREAM_DEPTH , xres, yres, framerate, OB_FORMAT_ANY );
174+ config->setFrameAggregateOutputMode (OB_FRAME_AGGREGATE_OUTPUT_ALL_TYPE_FRAME_REQUIRE );
175+ this ->xres = xres;
176+ this ->yres = yres;
177+ allocate_point_cloud_buffer ();
178+ pipeline->start (config, [&, this ](std::shared_ptr<ob::FrameSet> frameSet) {
179+ auto frame = point_cloud_filter->process (frameSet)->as <ob::PointsFrame>();
180+ // we unfortunately need one cpu copy. The function that creates a gpu buffer from a uint8_t* exists in godot but
181+ // is not exposed in godot-cpp...
182+ std::memcpy (point_bytes.ptrw (), frame->getData (), point_bytes.size ());
183+ // we can't update the point cloud buffer from a thread other than the main thread or the render thread.
184+ RenderingServer::get_singleton ()->call_on_render_thread (Callable (this , " update_point_cloud_buffer" ));
185+ });
186+ }
187+ catch (const std::exception & ex) {
188+ print_line (ex.what ());
189+ // free the gpu buffer. if we excepted before it was allocated, it will just print an error on the godot side, no big deal.
190+ rd->free_rid (point_buffer);
191+ }
192+ }
193+
194+ OrbbecPointCloud::OrbbecPointCloud () {
195+ // create a random thinning mask.
196+ for (int i=0 ; i < thinning_mask_size; ++i) {
197+ thinning_mask[i] = static_cast <float >(rand ()) / static_cast <float >(RAND_MAX );
198+ }
199+ }
200+
201+ void OrbbecPointCloud::set_thinning (float thin) {
202+ thinning = thin;
203+ }
204+
205+ float OrbbecPointCloud::get_thinning () {
206+ return thinning;
207+ }
208+
209+ void OrbbecPointCloud::_bind_methods () {
210+ godot::ClassDB::bind_method (D_METHOD (" get_thinning" ), &OrbbecPointCloud::get_thinning);
211+ godot::ClassDB::bind_method (D_METHOD (" start_stream" , " xres" , " yres" , " framerate" ), &OrbbecPointCloud::start_stream);
212+ godot::ClassDB::bind_method (D_METHOD (" set_thinning" , " p_thinning" ), &OrbbecPointCloud::set_thinning);
213+ ADD_PROPERTY (PropertyInfo (Variant::FLOAT , " thinning" ), " set_thinning" , " get_thinning" );
214+ ADD_SIGNAL (MethodInfo (" point_cloud_frame" , PropertyInfo (Variant::PACKED_VECTOR3_ARRAY , " points" ), PropertyInfo (Variant::PACKED_FLOAT32_ARRAY , " raw_buffer" )));
215+ }
216+
112217void OrbbecPointCloud::start_stream (int xres, int yres, int framerate) {
113218 if (!device) {
114219 print_line (" Not starting stream, please set a device." );
115220 return ;
116221 }
117222 try {
118223 // stolen from the savePointCloudToPly function of the orbbec sdk. I assume this value filters out irrelevant points ?
119- // populate_device_from_idx(idx);
120224 constexpr auto min_point_value = 1e-6f ;
121225 point_cloud_filter->setCreatePointFormat (OB_FORMAT_POINT );
122226 pipeline = std::make_unique<ob::Pipeline>(device);
0 commit comments