ã¯ããã«
Unity ã§ãã¤ãã£ãå´ï¼C/C++ çï¼ã§ä½æãããã¯ã¹ãã£ãå©ç¨ããæ¹æ³ã¯ããã¤ããã£ã¦ããã©ã·ã¥ã¼ã«ããã°ããã«ã¾ã¨ãããã¦ãã¾ãã
- Unityでテクスチャを読む7つの方法 - テラシュールブログ
- Unityでテクスチャを読む7つの方法 4・5・6について - テラシュールブログ
- ネイティブで作成したテクスチャを使用する - テラシュールブログ
ç§ããã以å¤ã®æ¹æ³ã¨ãã¦ããã使ã Texture2D.SetPixels()
ã使ãæ¹æ³ã¨ Low-Level Native Plugin Interfaceï¼ä½ã¬ãã«ãã¤ãã£ããã©ã°ã¤ã³ã¤ã³ã¿ã¼ãã§ã¼ã¹ï¼ããã£ããã¨ç´¹ä»ãã¾ããã
- Unity で OpenCV で作成したテクスチャをネイティブプラグイン経由で利用してみた - 凹みTips
- Unity の Low-level Native Plugin Interface を調べてみた - 凹みTips
ããã§æ¬ã¨ã³ããªã§ã¯æãé«éã«ãã¤ãã£ãå´ã¨ããã¨ãåºæ¥ã Low-Level Native Plugin Interface åã³ CreateExternalTexture()
/ UpdateExternalTexture()
ã使ã£ãå©ç¨ä¾ã«ã¤ãã¦ãOpenCV ããåå¾ããã«ã¡ã©ç»ãå¹çããå©ç¨ãããµã³ãã«ãç´¹ä»ãããã¨æãã¾ãã
Unity å´ã®ã³ã¼ãã¯åããªã®ã§ããåãã©ãããã©ã¼ã æ¯ã«ãã¤ãã£ãå´ã®æ±ããå¤ããã®ã§ãã¾ãã¯ç°¡åã®ããã« Mac OS X ãä»®å®ãã¦é²ãã¦ããã¾ãã
追è¨ï¼2016/01/10ï¼
Windows ç·¨ãæ¸ãã¾ããã
追è¨ï¼2019/08/24ï¼
ã¾ããUnity 2017.2.0b10 ããã¯æ¬¡ã®ãããªãã©ãããã©ã¼ã éä¾å㪠API ãç¨æããã¦ãã¾ãã
ä»çµã¿
ä¾ãã° Texture2D.SetPixels()
ããã³ Texture2D.Apply()
ãå©ç¨ããæ¹æ³ã§ã¯ãã¾ããã¤ãã£ããããã¯ã¹ãã£ãã¼ã¿ã C# 㸠Color32[]
åã®ãã¤ã³ã¿ãéãã¦ã³ãã¼ããSetPixels()
ããã³ Apply()
ã§å¯¾è±¡ã®ãã¯ã¹ãã£ãæ´æ°ãGPU ã¸ã¢ãããã¼ããããã¨ããçµè·¯ããã©ãã¾ãã
ä¾
// é©å½ãªãã¯ã¹ã㣠var texture = new Texture2D(width, height, TextureFormat.RGB24, false); // ãã¯ã¹ãã£ã®ãµã¤ãºã¨åããµã¤ãºã® Color32[] åã®ã³ãã¼ããããã®é åãä½æãã // GC ãããªãããã«ãã¦é åã®å é ã®ãã¤ã³ã¿ãåå¾ var pixels = texture_.GetPixels32(); var handle = GCHandle.Alloc(pixels_, GCHandleType.Pinned); var pointer = pixels_handle_.AddrOfPinnedObject(); // é åã®ãã¤ã³ã¿ããã¤ãã£ãå´ã«æ¸¡ãã¦ãã¯ã¹ãã£ãæ´æ°ï¼ããã¯å¥ã¹ã¬ããã«åºæ¥ãï¼ updateTexture(pointer, width, height); // ãã¤ãã£ãããããã£ã pixels ããã¯ã¹ãã£ã«ã³ãã¼ã㦠// GPU å´ã¸ã¢ãããã¼ããã¦åæ ããï¼ãã®ã³ãã¼ãç¡é§ã§éãï¼ texture_.SetPixels32(pixels); texture_.Apply();
ãã®çµè·¯ã辿ã㨠Unity ãå é¨ã§ãã¯ã¹ãã£ã®ãã¼ã¿ããããªã«ãã³ãã«ããè£å´ã§åãã©ãããã©ã¼ã ã«åãããå¦çãè¡ã£ã¦ãããã¨ããå©ç¹ãããã¾ããã¦ã¼ã¶ã DirectX ã OpenGL ãæèããå¿ è¦ã¯ããã¾ãããããããªããé«éåã®ããã«ã¯ãããã®ä¸è¦ãªã³ãã¼ãé¿ããããã¯ãã§ããã¤ãã£ãããç´æ¥ GPU ã¸ãã¯ã¹ãã£ã®ãã¼ã¿ãã¢ãããã¼ãããã°è¯ãã¯ãã§ãã
ãããç解ããããã«å°ã Texture
ï¼Texture2D
㯠Texture
ã®æ´¾çã¯ã©ã¹ï¼ã®è©±ã«ãªãã®ã§ãããTexture
ã«ã¯ GetNativeTexturePtr()
ã¨ããé¢æ°ãç¨æããã¦ãã¦ããããå¼ã¶ã¨ System.IntPtr
åã®å¤ãè¿ã£ã¦ãã¾ãããã®å¤ã¯ãã¯ã¹ãã£ã®ãã³ãã«ã«ãªã£ã¦ãã¦ãä¾ãã° Windows ã§ããã° DirectX 11 ãªã ID3D11Texture2D*
ãMac ã LinuxãAndroid ãªã OpenGL ã¾ã㯠OpenGL ES 2.0 ã® GLuint
ãiOS ãªã Metal ã® id<MTLTexture>
ã¨ãã£ãæãã§ãã
ã¤ã¾ãããããã®ãã¯ã¹ãã£ãã³ãã«ãç´æ¥ãã¤ãã£ãå´ã§çæã㦠Unity å´ã«éç¥ããããUnity å´ã§çæãããã¯ã¹ãã£ã®ãã³ãã«ããã¤ãã£ãå´ã«æ¸¡ãã¦ããã«æç»ãã¦ãããã°ä¸çªéãããã§ãã
åè
ã CreativeExternalTexture()
ããã³ UpdateExternalTexture()
ãå©ç¨ãããã©ã·ã¥ã¼ã«ããã°ããã§è¨åããã¦ããæ¹æ³ã§ãå¾è
ã Low-Level Native Plugin Interface ã§ã¸ã§ãã¬âãã£ããã¯ã¹ãã£çæã®ããã«èª¬æããã¦ããæ¹æ³ã«ãªãã¾ãããã® 2 ã¤ã¯ä½æ³ã¯ç°ãªãã¾ãããæ ¹ã£ãã®ã¨ããã¯åãã§ãã
ã³ã¼ãéçã«ã¯ã»ã¼åããªã®ã§ããã¤ãã£ãå´ã®äºæ ã«åããã¦ä½¿ãåããã°è¯ãã¨æãã¾ãã
ã³ã¼ãï¼C++ å´ï¼
C++ å´ã§ã¯ãµã³ãã«ã¨ãã¦ä»¥ä¸ã®ãããªã³ã¼ããç¨æãã¦ã¿ã¾ãã
#include <opencv2/opencv.hpp> #include <OpenGL/gl.h> #include <thread> class Camera { public: explicit Camera(int device) : camera_(device) { startCapture(); } ~Camera() { stopCapture(); camera_.release(); } private: void startCapture() { thread_ = std::thread([this] { isRunning_ = true; while (isRunning_) { camera_ >> image_; } }); } void stopCapture() { isRunning_ = false; if (thread_.joinable()) { thread_.join(); } } public: void update() { glBindTexture(GL_TEXTURE_2D, texture_); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // ã«ã¡ã©ç»ã¯ 3 byte æ¯ã«è²ã並ã¶ã 1, 2, 4 ããå¢çã¯æå®ã§ããªãã®ã§ 1 ãæå® glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB8, // RGB ãããã 8 bit ã§è¨ 24 bit getWidth(), getHeight(), 0, GL_BGR, // OpenCV ã§ã¯è²ã¯ BGR ã®é ã«ä¸¦ã¶ GL_UNSIGNED_BYTE, image_.data); glBindTexture(GL_TEXTURE_2D, 0); } bool isOpened() const { return camera_.isOpened(); } int getWidth() const { return image_.cols; } int getHeight() const { return image_.rows; } int getTexturePtr() const { return texture_; } void setTexturePtr(void* ptr) { texture_ = (GLuint)(size_t)ptr; } void createTexture() { glGenTextures(1, &texture_); } private: cv::VideoCapture camera_; cv::Mat image_; GLuint texture_ = 0; std::thread thread_; bool isRunning_ = false; }; extern "C" { using DebugFuncPtr = void(*)(const char*); using UnityRenderEvent = void(*)(int); namespace { DebugFuncPtr debug; Camera* g_pCamera; GLuint g_pTexture; } void* getCamera(int device) { g_pCamera = new Camera(device); return g_pCamera; } void releaseCamera(void* ptr) { auto camera = reinterpret_cast<Camera*>(ptr); delete camera; } bool isCameraOpened(void* ptr) { auto camera = reinterpret_cast<Camera*>(ptr); return camera->isOpened(); } int getCameraWidth(void* ptr) { auto camera = reinterpret_cast<Camera*>(ptr); return camera->getWidth(); } int getCameraHeight(void* ptr) { auto camera = reinterpret_cast<Camera*>(ptr); return camera->getHeight(); } int getCameraTexturePtr(void* ptr) { auto camera = reinterpret_cast<Camera*>(ptr); return camera->getTexturePtr(); } void updateCamera(void* ptr) { auto camera = reinterpret_cast<Camera*>(ptr); camera->update(); } void setCameraTexturePtr(void* ptr, void* pTexture) { auto camera = reinterpret_cast<Camera*>(ptr); camera->setTexturePtr(pTexture); } void createTexture(void* ptr) { auto camera = reinterpret_cast<Camera*>(ptr); camera->createTexture(); } void onRenderEvent(int eventId) { g_pCamera->update(); } UnityRenderEvent getRenderEventFunc() { return onRenderEvent; } }
OpenCV ã§ã®ã«ã¡ã©ãã£ããã£ç¨ã® cv::VideoCapture
ããã£ããã£ããç»ã®ä¿åç¨ã® cv::Mat
ãOpenGL ã®ãã¯ã¹ãã£ãæã GLuint
ãã¾ã¨ããã¯ã©ã¹ Camera
ãä½æãããã®ã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ãçæã»ç ´æ£ã»æä½ãã API ã C# åãã«å
¬éãã¦ããå½¢ã«ãªãã¾ããããã¯ã°ã©ã¦ã³ãã®ã¹ã¬ããã§ã«ã¡ã©ç»ãéææ´æ°ããã¡ã¤ã³ã¹ã¬ããããå¼ã°ãã Camera::update()
㧠OpenGL ã®ä¸çã¸ãã¯ã¹ãã£ãå
¬éãã¾ãã
ããã XCode ã§ãã«ããã¾ããããã¸ã§ã¯ãã¯é©å½ã«é©å½ã«ããããè¨å®ãã¦ä¸ããã
ãã«ãã㦠Unity ã® Assets/Plugins/x86_64
以ä¸ã«çæããã bundle ãç½®ãã¾ãã
ã³ã¼ãï¼C# å´ï¼
Unity å´ã®ãã¯ã¹ãã£ãå©ç¨
次㫠Unity å´ã§ãã¯ã¹ãã£ãçæãããã®ãã³ãã«ã渡ãã³ã¼ããæ¸ãã¦ã¿ã¾ãããã
using UnityEngine; using System; using System.Runtime.InteropServices; public class OpenCvCamera : MonoBehaviour { [DllImport ("opencv_camera")] private static extern IntPtr getCamera(int device); [DllImport ("opencv_camera")] private static extern void releaseCamera(IntPtr ptr); [DllImport ("opencv_camera")] private static extern int getCameraWidth(IntPtr ptr); [DllImport ("opencv_camera")] private static extern int getCameraHeight(IntPtr ptr); [DllImport ("opencv_camera")] private static extern void updateCamera(IntPtr ptr); [DllImport ("opencv_camera")] private static extern void setCameraTexturePtr(IntPtr ptr, IntPtr texture); private IntPtr camera_ = IntPtr.Zero; void Start() { camera_ = getCamera(0); var tex = new Texture2D( getCameraWidth(camera_), getCameraWidth(camera_), TextureFormat.RGB24, false, /* mipmap */ true /* linear */); GetComponent<Renderer>().material.mainTexture = tex; setCameraTexturePtr(camera_, tex.GetNativeTexturePtr()); } void OnDestroy() { releaseCamera(camera_); } void Update() { updateCamera(camera_); } }
ã«ã¡ã©ã«åãããã«æ¨ªã»ç¸¦å¹ ããã³ãã©ã¼ããããæå®ãããã¯ã¹ãã£ãçæãã¦ãã¾ãããã®ã¹ã¯ãªãããé©å½ãªãªãã¸ã§ã¯ãã«ã¢ã¿ãããã¦å®è¡ããã¨ä»¥ä¸ã®ããã«ãªãã¾ãã
External Texture ãçæ
C++ å´ã§æ¢ã«ãã¯ã¹ãã£ãçææ¸ã¿ã§ããã°ããã®ãã¯ã¹ãã£ãã³ãã«ãè²°ã£ã¦ãã¦ä»¥ä¸ã®ããã« CreateExternalTexture()
ãå©ç¨ã㦠Unity ã®ä¸çã§ä½¿ããããã«ã©ããããUpdateExternalTexture()
ãã¾ãï¼æåã¯ããã¯æ´æ°ã®ãã³ã«è¡ããªãã¨åéããã¦ãã¾ããããååã®ã¿ã§åé¡ããã¾ããï¼ã
using UnityEngine; using System; using System.Runtime.InteropServices; public class OpenCvCamera : MonoBehaviour { [DllImport ("opencv_camera")] private static extern IntPtr getCamera(int device); [DllImport ("opencv_camera")] private static extern void releaseCamera(IntPtr ptr); [DllImport ("opencv_camera")] private static extern void createTexture(IntPtr ptr); [DllImport ("opencv_camera")] private static extern int getCameraWidth(IntPtr ptr); [DllImport ("opencv_camera")] private static extern int getCameraHeight(IntPtr ptr); [DllImport ("opencv_camera")] private static extern void updateCamera(IntPtr ptr); [DllImport ("opencv_camera")] private static extern int getCameraTexturePtr(IntPtr ptr); private IntPtr camera_ = IntPtr.Zero; void Start() { camera_ = getCamera(0); createTexture(camera_); var ptr = (IntPtr)getCameraTexturePtr(camera_); var tex = Texture2D.CreateExternalTexture( getCameraWidth(camera_), getCameraWidth(camera_), TextureFormat.RGB24, false, true, ptr); tex.UpdateExternalTexture(ptr); GetComponent<Renderer>().material.mainTexture = tex; } void OnDestroy() { releaseCamera(camera_); } void Update() { updateCamera(camera_); } }
çµæã¯åãã«ãªãã¾ãã
ã¬ã³ããªã³ã°ã¹ã¬ããããå®è¡
Low-Level Native Plugin Interface ãå©ç¨ã㦠Unity ã®ã¬ã³ããªã³ã°ã¹ã¬ããã§å®è¡ããããã«å¤æ´ãããã¨ã§é«éåãæãã¾ãï¼ã¬ã³ããªã³ã°ã¹ã¬ãããã«ãã«ãã®å ´åã¯ãã¡ã§ããï¼ã以ä¸ã®ããã«ã³ã¼ããä¿®æ£ãã¾ãã
using UnityEngine; using System.Collections; using System; using System.Runtime.InteropServices; public class OpenCvCamera : MonoBehaviour { [DllImport ("opencv_camera")] private static extern IntPtr getCamera(int device); [DllImport ("opencv_camera")] private static extern void releaseCamera(IntPtr ptr); [DllImport ("opencv_camera")] private static extern void createTexture(IntPtr ptr); [DllImport ("opencv_camera")] private static extern int getCameraWidth(IntPtr ptr); [DllImport ("opencv_camera")] private static extern int getCameraHeight(IntPtr ptr); [DllImport ("opencv_camera")] private static extern void updateCamera(IntPtr ptr); [DllImport ("opencv_camera")] private static extern int getCameraTexturePtr(IntPtr ptr); [DllImport ("opencv_camera")] private static extern IntPtr getRenderEventFunc(); private IntPtr camera_ = IntPtr.Zero; void Start() { camera_ = getCamera(0); createTexture(camera_); var ptr = (IntPtr)getCameraTexturePtr(camera_); var tex = Texture2D.CreateExternalTexture( getCameraWidth(camera_), getCameraWidth(camera_), TextureFormat.RGB24, false, true, ptr); tex.UpdateExternalTexture(ptr); GetComponent<Renderer>().material.mainTexture = tex; StartCoroutine(OnRender()); } void OnDestroy() { releaseCamera(camera_); } IEnumerator OnRender() { for (;;) { yield return new WaitForEndOfFrame(); GL.IssuePluginEvent(getRenderEventFunc(), 0); } } }
GL.IssuePluginEvent(System.IntPtr func, int eventId)
ã§ç¬¬ï¼å¼æ°ã«ãã¤ãã£ãå´ããããã£ãé¢æ°ãã¤ã³ã¿ã渡ããã¨ã§ããã®é¢æ°ãã¬ã³ããªã³ã°ã¹ã¬ããã§å®è¡ã§ãã¾ããUnity 5.2 ãããå㯠UnityRenderEvent()
ã¨ããåºå®ã®ååã®é¢æ°ãå¼ã¶å½¢å¼ã§ããããUnity 5.2 ãããã®å½¢å¼ã¸ã¨å¤æ´ã«ãªãã¾ãããæ£ç¢ºã«ã¯ UnityPluginLoad(IUnityInterfaces*)
ããã³ UnityPluginUnload()
ããã¤ãã£ãå´ã§å®ç¾©ããã°ã©ãã£ãã¯ãã©ã¤ãã調ã¹ãªããã°ãªããªãï¼OpenGL ã DirectX ã®ãã¼ã¸ã§ã³çã«å¿ããå¦çãè¡ããªããã°ãªããªãï¼ã®ã§ãããæ¬ã¨ã³ããªã§ã¯åãæ¢ãã Mac OS X ãä»®å®ãã¦ããã®ã§ãããã¯çç¥ãã¾ãã
ããã«ããã¿ã¤ã ã©ã¤ã³ãè¦ã¦ã¿ãã¨ä»¥ä¸ã®ããã«æ¹åããã¦ãããã¨ãåããã¾ãã
ã¡ã¤ã³ã¹ã¬ããã§å®è¡
ã¬ã³ããªã³ã°ã¹ã¬ããã§å®è¡
ã¬ã³ããªã³ã°ã¹ã¬ããã«ç©ºããããã°ãä½ããªãã·ã¼ã³ã¨åçã®ããã©ã¼ãã³ã¹ãæãã¾ãã
空ã®ã·ã¼ã³
ãããã«
ã«ã¡ã©ãå©ç¨ããç»åã®åãè¾¼ã¿ãåç»ãã³ã¼ãå¦çãã¸ã§ãã¬ã¼ãã£ããã¯ã¹ãã£ã®çæãªã©ã«åºãå½¹ã«ç«ã¤ã¨æãã¾ããæéãã§ããã Windows ç·¨ãªã©ãæ¸ãããã¨æãã¾ãã
æå¾ã«ãªãã¾ããããTwitter ã§å°ã£ã¦ãããå©ãã¦ä¸ãã£ãçæ§ããããã¨ããããã¾ããï¼-人-ï¼ã