| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752 |
- /*************************************************************************/
- /* arkit_interface.mm */
- /*************************************************************************/
- /* This file is part of: */
- /* GODOT ENGINE */
- /* https://godotengine.org */
- /*************************************************************************/
- /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
- /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
- /* */
- /* Permission is hereby granted, free of charge, to any person obtaining */
- /* a copy of this software and associated documentation files (the */
- /* "Software"), to deal in the Software without restriction, including */
- /* without limitation the rights to use, copy, modify, merge, publish, */
- /* distribute, sublicense, and/or sell copies of the Software, and to */
- /* permit persons to whom the Software is furnished to do so, subject to */
- /* the following conditions: */
- /* */
- /* The above copyright notice and this permission notice shall be */
- /* included in all copies or substantial portions of the Software. */
- /* */
- /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
- /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
- /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
- /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
- /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
- /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
- /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
- /*************************************************************************/
- #include "core/os/input.h"
- #include "core/os/os.h"
- #include "scene/resources/surface_tool.h"
- #include "servers/visual/visual_server_globals.h"
- #import <ARKit/ARKit.h>
- #import <UIKit/UIKit.h>
- #include <dlfcn.h>
- #include "arkit_interface.h"
- #include "arkit_session_delegate.h"
- // just a dirty workaround for now, declare these as globals. I'll probably encapsulate ARSession and associated logic into an mm object and change ARKitInterface to a normal cpp object that consumes it.
- ARSession *ar_session;
- ARKitSessionDelegate *ar_delegate;
- NSTimeInterval last_timestamp;
- /* this is called when we initialize or when we come back from having our app pushed to the background, just (re)start our session */
- void ARKitInterface::start_session() {
- // We're active...
- session_was_started = true;
- // Ignore this if we're not initialized...
- if (initialized) {
- print_line("Starting ARKit session");
- Class ARWorldTrackingConfigurationClass = NSClassFromString(@"ARWorldTrackingConfiguration");
- ARWorldTrackingConfiguration *configuration = [ARWorldTrackingConfigurationClass new];
- configuration.lightEstimationEnabled = light_estimation_is_enabled;
- if (plane_detection_is_enabled) {
- configuration.planeDetection = ARPlaneDetectionVertical | ARPlaneDetectionHorizontal;
- } else {
- configuration.planeDetection = 0;
- }
- // make sure our camera is on
- if (feed.is_valid()) {
- feed->set_active(true);
- }
- [ar_session runWithConfiguration:configuration];
- }
- }
- void ARKitInterface::stop_session() {
- session_was_started = false;
- // Ignore this if we're not initialized...
- if (initialized) {
- // make sure our camera is off
- if (feed.is_valid()) {
- feed->set_active(false);
- }
- [ar_session pause];
- }
- }
- void ARKitInterface::notification(int p_what) {
- // TODO, this is not being called, need to find out why, possibly because this is not a node.
- // in that case we need to find a way to get these notifications!
- switch (p_what) {
- case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
- print_line("Focus in");
- start_session();
- }; break;
- case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
- print_line("Focus out");
- stop_session();
- }; break;
- default:
- break;
- }
- }
- bool ARKitInterface::get_anchor_detection_is_enabled() const {
- return plane_detection_is_enabled;
- }
- void ARKitInterface::set_anchor_detection_is_enabled(bool p_enable) {
- if (plane_detection_is_enabled != p_enable) {
- plane_detection_is_enabled = p_enable;
- // Restart our session (this will be ignore if we're not initialised)
- if (session_was_started) {
- start_session();
- }
- }
- }
- int ARKitInterface::get_camera_feed_id() {
- if (feed.is_null()) {
- return 0;
- } else {
- return feed->get_id();
- }
- }
- bool ARKitInterface::get_light_estimation_is_enabled() const {
- return light_estimation_is_enabled;
- }
- void ARKitInterface::set_light_estimation_is_enabled(bool p_enable) {
- if (light_estimation_is_enabled != p_enable) {
- light_estimation_is_enabled = p_enable;
- // Restart our session (this will be ignore if we're not initialised)
- if (session_was_started) {
- start_session();
- }
- }
- }
- real_t ARKitInterface::get_ambient_intensity() const {
- return ambient_intensity;
- }
- real_t ARKitInterface::get_ambient_color_temperature() const {
- return ambient_color_temperature;
- }
- StringName ARKitInterface::get_name() const {
- return "ARKit";
- }
- int ARKitInterface::get_capabilities() const {
- return ARKitInterface::ARVR_MONO + ARKitInterface::ARVR_AR;
- }
- Array ARKitInterface::raycast(Vector2 p_screen_coord) {
- Array arr;
- Size2 screen_size = OS::get_singleton()->get_window_size();
- CGPoint point;
- point.x = p_screen_coord.x / screen_size.x;
- point.y = p_screen_coord.y / screen_size.y;
- ///@TODO maybe give more options here, for now we're taking just ARAchors into account that were found during plane detection keeping their size into account
- NSArray<ARHitTestResult *> *results = [ar_session.currentFrame hittest:point types:ARHitTestResultTypeExistingPlaneUsingExtent];
- for (ARHitTestResult *result in results) {
- Transform transform;
- matrix_float4x4 m44 = result.worldTransform;
- transform.basis.elements[0].x = m44.columns[0][0];
- transform.basis.elements[1].x = m44.columns[0][1];
- transform.basis.elements[2].x = m44.columns[0][2];
- transform.basis.elements[0].y = m44.columns[1][0];
- transform.basis.elements[1].y = m44.columns[1][1];
- transform.basis.elements[2].y = m44.columns[1][2];
- transform.basis.elements[0].z = m44.columns[2][0];
- transform.basis.elements[1].z = m44.columns[2][1];
- transform.basis.elements[2].z = m44.columns[2][2];
- transform.origin.x = m44.columns[3][0];
- transform.origin.y = m44.columns[3][1];
- transform.origin.z = m44.columns[3][2];
- /* important, NOT scaled to world_scale !! */
- arr.push_back(transform);
- }
- return arr;
- }
- void ARKitInterface::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_notification", "what"), &ARKitInterface::_notification);
- ClassDB::bind_method(D_METHOD("set_light_estimation_is_enabled", "enable"), &ARKitInterface::set_light_estimation_is_enabled);
- ClassDB::bind_method(D_METHOD("get_light_estimation_is_enabled"), &ARKitInterface::get_light_estimation_is_enabled);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_estimation"), "set_light_estimation_is_enabled", "get_light_estimation_is_enabled");
- ClassDB::bind_method(D_METHOD("get_ambient_intensity"), &ARKitInterface::get_ambient_intensity);
- ClassDB::bind_method(D_METHOD("get_ambient_color_temperature"), &ARKitInterface::get_ambient_color_temperature);
- ClassDB::bind_method(D_METHOD("raycast", "screen_coord"), &ARKitInterface::raycast);
- }
- bool ARKitInterface::is_stereo() {
- // this is a mono device...
- return false;
- }
- bool ARKitInterface::is_initialized() const {
- return initialized;
- }
- bool ARKitInterface::initialize() {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, false);
- if (!initialized) {
- print_line("initializing ARKit");
- // create our ar session and delegate
- Class ARSessionClass = NSClassFromString(@"ARSession");
- if (ARSessionClass == Nil) {
- void *arkit_handle = dlopen("/System/Library/Frameworks/ARKit.framework/ARKit", RTLD_NOW);
- if (arkit_handle) {
- ARSessionClass = NSClassFromString(@"ARSession");
- } else {
- print_line("ARKit init failed");
- return false;
- }
- }
- ar_session = [ARSessionClass new];
- ar_delegate = [ARKitSessionDelegate new];
- ar_delegate.arkit_interface = this;
- ar_session.delegate = ar_delegate;
- // reset our transform
- transform = Transform();
- // make this our primary interface
- arvr_server->set_primary_interface(this);
- // make sure we have our feed setup
- if (feed.is_null()) {
- feed.instance();
- feed->set_name("ARKit");
- CameraServer *cs = CameraServer::get_singleton();
- if (cs != NULL) {
- cs->add_feed(feed);
- }
- }
- feed->set_active(true);
- // yeah!
- initialized = true;
- // Start our session...
- start_session();
- }
- return true;
- }
- void ARKitInterface::uninitialize() {
- if (initialized) {
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- if (arvr_server != NULL) {
- // no longer our primary interface
- arvr_server->clear_primary_interface_if(this);
- }
- if (feed.is_valid()) {
- CameraServer *cs = CameraServer::get_singleton();
- if ((cs != NULL)) {
- cs->remove_feed(feed);
- }
- feed.unref();
- }
- remove_all_anchors();
- [ar_session release];
- [ar_delegate release];
- ar_session = NULL;
- ar_delegate = NULL;
- initialized = false;
- session_was_started = false;
- }
- }
- Size2 ARKitInterface::get_render_targetsize() {
- _THREAD_SAFE_METHOD_
- Size2 target_size = OS::get_singleton()->get_window_size();
- return target_size;
- }
- Transform ARKitInterface::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) {
- _THREAD_SAFE_METHOD_
- Transform transform_for_eye;
- ARVRServer *arvr_server = ARVRServer::get_singleton();
- ERR_FAIL_NULL_V(arvr_server, transform_for_eye);
- if (initialized) {
- float world_scale = arvr_server->get_world_scale();
- // just scale our origin point of our transform, note that we really shouldn't be using world_scale in ARKit but....
- transform_for_eye = transform;
- transform_for_eye.origin *= world_scale;
- transform_for_eye = p_cam_transform * arvr_server->get_reference_frame() * transform_for_eye;
- } else {
- // huh? well just return what we got....
- transform_for_eye = p_cam_transform;
- }
- return transform_for_eye;
- }
- CameraMatrix ARKitInterface::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
- // Remember our near and far, it will be used in process when we obtain our projection from our ARKit session.
- z_near = p_z_near;
- z_far = p_z_far;
- return projection;
- }
- void ARKitInterface::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
- _THREAD_SAFE_METHOD_
- // We must have a valid render target
- ERR_FAIL_COND(!p_render_target.is_valid());
- // Because we are rendering to our device we must use our main viewport!
- ERR_FAIL_COND(p_screen_rect == Rect2());
- // get the size of our screen
- Rect2 screen_rect = p_screen_rect;
- // screen_rect.position.x += screen_rect.size.x;
- // screen_rect.size.x = -screen_rect.size.x;
- // screen_rect.position.y += screen_rect.size.y;
- // screen_rect.size.y = -screen_rect.size.y;
- VSG::rasterizer->set_current_render_target(RID());
- VSG::rasterizer->blit_render_target_to_screen(p_render_target, screen_rect, 0);
- }
- ARVRPositionalTracker *ARKitInterface::get_anchor_for_uuid(const unsigned char *p_uuid) {
- if (anchors == NULL) {
- num_anchors = 0;
- max_anchors = 10;
- anchors = (anchor_map *)malloc(sizeof(anchor_map) * max_anchors);
- }
- ERR_FAIL_NULL_V(anchors, NULL);
- for (unsigned int i = 0; i < num_anchors; i++) {
- if (memcmp(anchors[i].uuid, p_uuid, 16) == 0) {
- return anchors[i].tracker;
- }
- }
- if (num_anchors + 1 == max_anchors) {
- max_anchors += 10;
- anchors = (anchor_map *)realloc(anchors, sizeof(anchor_map) * max_anchors);
- ERR_FAIL_NULL_V(anchors, NULL);
- }
- ARVRPositionalTracker *new_tracker = memnew(ARVRPositionalTracker);
- new_tracker->set_type(ARVRServer::TRACKER_ANCHOR);
- char tracker_name[256];
- sprintf(tracker_name, "Anchor %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", p_uuid[0], p_uuid[1], p_uuid[2], p_uuid[3], p_uuid[4], p_uuid[5], p_uuid[6], p_uuid[7], p_uuid[8], p_uuid[9], p_uuid[10], p_uuid[11], p_uuid[12], p_uuid[13], p_uuid[14], p_uuid[15]);
- String name = tracker_name;
- print_line("Adding tracker " + name);
- new_tracker->set_name(name);
- // add our tracker
- ARVRServer::get_singleton()->add_tracker(new_tracker);
- anchors[num_anchors].tracker = new_tracker;
- memcpy(anchors[num_anchors].uuid, p_uuid, 16);
- num_anchors++;
- return new_tracker;
- }
- void ARKitInterface::remove_anchor_for_uuid(const unsigned char *p_uuid) {
- if (anchors != NULL) {
- for (unsigned int i = 0; i < num_anchors; i++) {
- if (memcmp(anchors[i].uuid, p_uuid, 16) == 0) {
- // remove our tracker
- ARVRServer::get_singleton()->remove_tracker(anchors[i].tracker);
- memdelete(anchors[i].tracker);
- // bring remaining forward
- for (unsigned int j = i + 1; j < num_anchors; j++) {
- anchors[j - 1] = anchors[j];
- };
- // decrease count
- num_anchors--;
- return;
- }
- }
- }
- }
- void ARKitInterface::remove_all_anchors() {
- if (anchors != NULL) {
- for (unsigned int i = 0; i < num_anchors; i++) {
- // remove our tracker
- ARVRServer::get_singleton()->remove_tracker(anchors[i].tracker);
- memdelete(anchors[i].tracker);
- };
- free(anchors);
- anchors = NULL;
- num_anchors = 0;
- }
- }
- void ARKitInterface::process() {
- _THREAD_SAFE_METHOD_
- if (@available(iOS 11.0, *)) {
- if (initialized) {
- // get our next ARFrame
- ARFrame *current_frame = ar_session.currentFrame;
- if (last_timestamp != current_frame.timestamp) {
- // only process if we have a new frame
- last_timestamp = current_frame.timestamp;
- // get some info about our screen and orientation
- Size2 screen_size = OS::get_singleton()->get_window_size();
- UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
- // Grab our camera image for our backbuffer
- CVPixelBufferRef pixelBuffer = current_frame.capturedImage;
- if ((CVPixelBufferGetPlaneCount(pixelBuffer) == 2) && (feed != NULL)) {
- // Plane 0 is our Y and Plane 1 is our CbCr buffer
- // ignored, we check each plane separately
- // image_width = CVPixelBufferGetWidth(pixelBuffer);
- // image_height = CVPixelBufferGetHeight(pixelBuffer);
- // printf("Pixel buffer %i - %i\n", image_width, image_height);
- CVPixelBufferLockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
- // get our buffers
- unsigned char *dataY = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
- unsigned char *dataCbCr = (unsigned char *)CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 1);
- if (dataY == NULL) {
- print_line("Couldn't access Y pixel buffer data");
- } else if (dataCbCr == NULL) {
- print_line("Couldn't access CbCr pixel buffer data");
- } else {
- Ref<Image> img[2];
- size_t extraLeft, extraRight, extraTop, extraBottom;
- CVPixelBufferGetExtendedPixels(pixelBuffer, &extraLeft, &extraRight, &extraTop, &extraBottom);
- {
- // do Y
- int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 0);
- int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 0);
- int bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
- if ((image_width[0] != new_width) || (image_height[0] != new_height)) {
- printf("- Camera padding l:%lu r:%lu t:%lu b:%lu\n", extraLeft, extraRight, extraTop, extraBottom);
- printf("- Camera Y plane size: %i, %i - %i\n", new_width, new_height, bytes_per_row);
- image_width[0] = new_width;
- image_height[0] = new_height;
- img_data[0].resize(new_width * new_height);
- }
- PoolVector<uint8_t>::Write w = img_data[0].write();
- if (new_width == bytes_per_row) {
- memcpy(w.ptr(), dataY, new_width * new_height);
- } else {
- int offset_a = 0;
- int offset_b = extraLeft + (extraTop * bytes_per_row);
- for (int r = 0; r < new_height; r++) {
- memcpy(w.ptr() + offset_a, dataY + offset_b, new_width);
- offset_a += new_width;
- offset_b += bytes_per_row;
- }
- }
- img[0].instance();
- img[0]->create(new_width, new_height, 0, Image::FORMAT_R8, img_data[0]);
- }
- {
- // do CbCr
- int new_width = CVPixelBufferGetWidthOfPlane(pixelBuffer, 1);
- int new_height = CVPixelBufferGetHeightOfPlane(pixelBuffer, 1);
- int bytes_per_row = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer, 0);
- if ((image_width[1] != new_width) || (image_height[1] != new_height)) {
- printf("- Camera CbCr plane size: %i, %i - %i\n", new_width, new_height, bytes_per_row);
- image_width[1] = new_width;
- image_height[1] = new_height;
- img_data[1].resize(2 * new_width * new_height);
- }
- PoolVector<uint8_t>::Write w = img_data[1].write();
- if ((2 * new_width) == bytes_per_row) {
- memcpy(w.ptr(), dataCbCr, 2 * new_width * new_height);
- } else {
- int offset_a = 0;
- int offset_b = extraLeft + (extraTop * bytes_per_row);
- for (int r = 0; r < new_height; r++) {
- memcpy(w.ptr() + offset_a, dataCbCr + offset_b, 2 * new_width);
- offset_a += 2 * new_width;
- offset_b += bytes_per_row;
- }
- }
- img[1].instance();
- img[1]->create(new_width, new_height, 0, Image::FORMAT_RG8, img_data[1]);
- }
- // set our texture...
- feed->set_YCbCr_imgs(img[0], img[1]);
- // now build our transform to display this as a background image that matches our camera
- CGAffineTransform affine_transform = [current_frame displayTransformForOrientation:orientation viewportSize:CGSizeMake(screen_size.width, screen_size.height)];
- // we need to invert this, probably row v.s. column notation
- affine_transform = CGAffineTransformInvert(affine_transform);
- if (orientation != UIInterfaceOrientationPortrait) {
- affine_transform.b = -affine_transform.b;
- affine_transform.d = -affine_transform.d;
- affine_transform.ty = 1.0 - affine_transform.ty;
- } else {
- affine_transform.c = -affine_transform.c;
- affine_transform.a = -affine_transform.a;
- affine_transform.tx = 1.0 - affine_transform.tx;
- }
- Transform2D display_transform = Transform2D(
- affine_transform.a, affine_transform.b,
- affine_transform.c, affine_transform.d,
- affine_transform.tx, affine_transform.ty);
- feed->set_transform(display_transform);
- }
- // and unlock
- CVPixelBufferUnlockBaseAddress(pixelBuffer, kCVPixelBufferLock_ReadOnly);
- }
- // Record light estimation to apply to our scene
- if (light_estimation_is_enabled) {
- ambient_intensity = current_frame.lightEstimate.ambientIntensity;
- ///@TODO it's there, but not there.. what to do with this...
- // https://developer.apple.com/documentation/arkit/arlightestimate?language=objc
- // ambient_color_temperature = current_frame.lightEstimate.ambientColorTemperature;
- }
- // Process our camera
- ARCamera *camera = current_frame.camera;
- // strangely enough we have to states, rolling them up into one
- if (camera.trackingState == ARTrackingStateNotAvailable) {
- // no tracking, would be good if we black out the screen or something...
- tracking_state = ARVRInterface::ARVR_NOT_TRACKING;
- } else {
- if (camera.trackingState == ARTrackingStateNormal) {
- tracking_state = ARVRInterface::ARVR_NORMAL_TRACKING;
- } else if (camera.trackingStateReason == ARTrackingStateReasonExcessiveMotion) {
- tracking_state = ARVRInterface::ARVR_EXCESSIVE_MOTION;
- } else if (camera.trackingStateReason == ARTrackingStateReasonInsufficientFeatures) {
- tracking_state = ARVRInterface::ARVR_INSUFFICIENT_FEATURES;
- } else {
- tracking_state = ARVRInterface::ARVR_UNKNOWN_TRACKING;
- }
- // copy our current frame transform
- matrix_float4x4 m44 = camera.transform;
- if (orientation == UIInterfaceOrientationLandscapeLeft) {
- transform.basis.elements[0].x = m44.columns[0][0];
- transform.basis.elements[1].x = m44.columns[0][1];
- transform.basis.elements[2].x = m44.columns[0][2];
- transform.basis.elements[0].y = m44.columns[1][0];
- transform.basis.elements[1].y = m44.columns[1][1];
- transform.basis.elements[2].y = m44.columns[1][2];
- } else if (orientation == UIInterfaceOrientationPortrait) {
- transform.basis.elements[0].x = m44.columns[1][0];
- transform.basis.elements[1].x = m44.columns[1][1];
- transform.basis.elements[2].x = m44.columns[1][2];
- transform.basis.elements[0].y = -m44.columns[0][0];
- transform.basis.elements[1].y = -m44.columns[0][1];
- transform.basis.elements[2].y = -m44.columns[0][2];
- } else if (orientation == UIInterfaceOrientationLandscapeRight) {
- transform.basis.elements[0].x = -m44.columns[0][0];
- transform.basis.elements[1].x = -m44.columns[0][1];
- transform.basis.elements[2].x = -m44.columns[0][2];
- transform.basis.elements[0].y = -m44.columns[1][0];
- transform.basis.elements[1].y = -m44.columns[1][1];
- transform.basis.elements[2].y = -m44.columns[1][2];
- } else if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
- // this may not be correct
- transform.basis.elements[0].x = m44.columns[1][0];
- transform.basis.elements[1].x = m44.columns[1][1];
- transform.basis.elements[2].x = m44.columns[1][2];
- transform.basis.elements[0].y = m44.columns[0][0];
- transform.basis.elements[1].y = m44.columns[0][1];
- transform.basis.elements[2].y = m44.columns[0][2];
- }
- transform.basis.elements[0].z = m44.columns[2][0];
- transform.basis.elements[1].z = m44.columns[2][1];
- transform.basis.elements[2].z = m44.columns[2][2];
- transform.origin.x = m44.columns[3][0];
- transform.origin.y = m44.columns[3][1];
- transform.origin.z = m44.columns[3][2];
- // copy our current frame projection, investigate using projectionMatrixWithViewportSize:orientation:zNear:zFar: so we can set our own near and far
- m44 = [camera projectionMatrixForOrientation:orientation viewportSize:CGSizeMake(screen_size.width, screen_size.height) zNear:z_near zFar:z_far];
- projection.matrix[0][0] = m44.columns[0][0];
- projection.matrix[1][0] = m44.columns[1][0];
- projection.matrix[2][0] = m44.columns[2][0];
- projection.matrix[3][0] = m44.columns[3][0];
- projection.matrix[0][1] = m44.columns[0][1];
- projection.matrix[1][1] = m44.columns[1][1];
- projection.matrix[2][1] = m44.columns[2][1];
- projection.matrix[3][1] = m44.columns[3][1];
- projection.matrix[0][2] = m44.columns[0][2];
- projection.matrix[1][2] = m44.columns[1][2];
- projection.matrix[2][2] = m44.columns[2][2];
- projection.matrix[3][2] = m44.columns[3][2];
- projection.matrix[0][3] = m44.columns[0][3];
- projection.matrix[1][3] = m44.columns[1][3];
- projection.matrix[2][3] = m44.columns[2][3];
- projection.matrix[3][3] = m44.columns[3][3];
- }
- }
- }
- }
- }
- void ARKitInterface::_add_or_update_anchor(void *p_anchor) {
- _THREAD_SAFE_METHOD_
- ARAnchor *anchor = (ARAnchor *)p_anchor;
- unsigned char uuid[16];
- [anchor.identifier getUUIDBytes:uuid];
- ARVRPositionalTracker *tracker = get_anchor_for_uuid(uuid);
- if (tracker != NULL) {
- // lets update our mesh! (using Arjens code as is for now)
- // we should also probably limit how often we do this...
- // can we safely cast this?
- ARPlaneAnchor *planeAnchor = (ARPlaneAnchor *)anchor;
- if (planeAnchor.geometry.triangleCount > 0) {
- Ref<SurfaceTool> surftool;
- surftool.instance();
- surftool->begin(Mesh::PRIMITIVE_TRIANGLES);
- for (int j = planeAnchor.geometry.triangleCount * 3 - 1; j >= 0; j--) {
- int16_t index = planeAnchor.geometry.triangleIndices[j];
- simd_float3 vrtx = planeAnchor.geometry.vertices[index];
- simd_float2 textcoord = planeAnchor.geometry.textureCoordinates[index];
- surftool->add_uv(Vector2(textcoord[0], textcoord[1]));
- surftool->add_color(Color(0.8, 0.8, 0.8));
- surftool->add_vertex(Vector3(vrtx[0], vrtx[1], vrtx[2]));
- }
- surftool->generate_normals();
- tracker->set_mesh(surftool->commit());
- } else {
- Ref<Mesh> nomesh;
- tracker->set_mesh(nomesh);
- }
- // Note, this also contains a scale factor which gives us an idea of the size of the anchor
- // We may extract that in our ARVRAnchor class
- Basis b;
- matrix_float4x4 m44 = anchor.transform;
- b.elements[0].x = m44.columns[0][0];
- b.elements[1].x = m44.columns[0][1];
- b.elements[2].x = m44.columns[0][2];
- b.elements[0].y = m44.columns[1][0];
- b.elements[1].y = m44.columns[1][1];
- b.elements[2].y = m44.columns[1][2];
- b.elements[0].z = m44.columns[2][0];
- b.elements[1].z = m44.columns[2][1];
- b.elements[2].z = m44.columns[2][2];
- tracker->set_orientation(b);
- tracker->set_rw_position(Vector3(m44.columns[3][0], m44.columns[3][1], m44.columns[3][2]));
- }
- }
- void ARKitInterface::_remove_anchor(void *p_anchor) {
- _THREAD_SAFE_METHOD_
- ARAnchor *anchor = (ARAnchor *)p_anchor;
- unsigned char uuid[16];
- [anchor.identifier getUUIDBytes:uuid];
- remove_anchor_for_uuid(uuid);
- }
- ARKitInterface::ARKitInterface() {
- initialized = false;
- session_was_started = false;
- plane_detection_is_enabled = false;
- light_estimation_is_enabled = false;
- ar_session = NULL;
- z_near = 0.01;
- z_far = 1000.0;
- projection.set_perspective(60.0, 1.0, z_near, z_far, false);
- anchors = NULL;
- num_anchors = 0;
- ambient_intensity = 1.0;
- ambient_color_temperature = 1.0;
- image_width[0] = 0;
- image_width[1] = 0;
- image_height[0] = 0;
- image_height[1] = 0;
- }
- ARKitInterface::~ARKitInterface() {
- remove_all_anchors();
- // and make sure we cleanup if we haven't already
- if (is_initialized()) {
- uninitialize();
- }
- }
|