C# 在屏幕点读取像素颜色(有效)

C# 在屏幕点读取像素颜色(有效),c#,android,c++,unity3d,C#,Android,C++,Unity3d,我需要在屏幕点读取C Unity3D中的像素颜色 我正在使用渲染纹理和ReadPixels方法。 即使渲染纹理大小为128x128px,每0.5f秒使用一次也会对性能造成不利影响,我正在尝试另一种方法来更快地获取这些数据。 我在某个地方读到,可以直接使用glReadPixels,但我不知道如何使用它 我需要检测屏幕上的这个位置点是否有什么东西 这是我目前掌握的代码 using UnityEngine; using System; using System.Collections; public

我需要在屏幕点读取C Unity3D中的像素颜色

我正在使用渲染纹理和ReadPixels方法。 即使渲染纹理大小为128x128px,每0.5f秒使用一次也会对性能造成不利影响,我正在尝试另一种方法来更快地获取这些数据。 我在某个地方读到,可以直接使用glReadPixels,但我不知道如何使用它

我需要检测屏幕上的这个位置点是否有什么东西

这是我目前掌握的代码

using UnityEngine;
using System;
using System.Collections;

public class ColController : MonoBehaviour
{
    public Camera collCamera;
    public Texture2D tex2d;


    void Start()
    {
        collCamera = GetComponent<Camera>();
        tex2d = new Texture2D(collCamera.targetTexture.width, collCamera.targetTexture.height, TextureFormat.ARGB32, false);

        RenderTexture.active = collCamera.targetTexture;
        StartCoroutine (Execute ());

    }

    IEnumerator Execute()
    {
        while (true) {

                yield return new WaitForEndOfFrame ();
                tex2d = GetRTPixels (collCamera.targetTexture);
                yield return new WaitForSeconds (0.5f);

        }
    }


    static public Texture2D GetRTPixels(RenderTexture rt)
    {
        RenderTexture currentActiveRT = RenderTexture.active;

        RenderTexture.active = rt;

        // Create a new Texture2D and read the RenderTexture image into it
        Texture2D tex = new Texture2D(rt.width, rt.height);
        tex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);

        RenderTexture.active = currentActiveRT;
        return tex;
    }

    void Update() {
        screenPos = collCamera.WorldToScreenPoint (player.transform.position);
        positionColor = tex2d.GetPixel ((int)screenPos.x, (int)screenPos.y);

    }


}
你必须使用glReadPixels。通过在OnPostRender函数中从C调用它,它过去更容易实现,但是您不能再这样做了。您必须使用GL.IssuePluginEvent调用将截图的函数

您还需要统一C++ + HealSersiUnuty.h和iunyDigaStudio .h位于\Edgel\Data \PuxLIPAPI . 我创建了一个名为UnityPluginHeaders的文件夹,并将IUnityInterface.h和IUnityGraphics.h头文件放在其中,以便可以使用include UnityPluginHeaders/IUnityInterface.h和include UnityPluginHeaders/IUnityGraphics.h导入它们

C++ScreenPointPixel.h:

C++ScreenPointPixel.cpp:


你用C++和OpenGL做这个,然后从C调用它。我现在也在做同样的事情来扩展我的相机捕获插件。你知道C++吗?我想在我完成我的答案后再加一个答案,但是我想确保我不是在浪费时间。程序员很遗憾我不知道C++,但是如果我理解正确,这应该是短代码来实现“是”。所以我应该处理它,或者从现在开始学习C++:代码看起来很像,但是指针更多。不管怎样,GLADEDIGONG和C++是获得最快截图的方法。新C++程序员最大的问题是不能编译代码。你试过Texture2D.ReadPixels吗?@Programmer你是对的,这可能是编译的问题,但我会试试。这对我来说非常重要,因为Texture2D.Readpixels在桌面上大约需要10毫秒,在我的目标Android设备上需要2-3倍的时间。每0.5秒运行一次肯定太慢了。@Programmer太棒了!我将等待你的答复。
#ifndef ANDROIDSCREENSHOT_NATIVE_LIB_H
#define ANDROIDSCREENSHOT_NATIVE_LIB_H

#define DLLExport __declspec(dllexport)

extern "C"
{
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WINAPI_FAMILY)
DLLExport void initScreenPointPixel(void* buffer, int x, int y, int width, int height);
DLLExport void updateScreenPointPixelBufferPointer(void* buffer);
DLLExport void updateScreenPointPixelCoordinate(int x, int y);
DLLExport void updateScreenPointPixelSize(int width, int height);
int GetScreenPixels(void* buffer, int x, int y, int width, int height);

#else
void initScreenPointPixel(void *buffer, int x, int y, int width, int height);
void updateScreenPointPixelBufferPointer(void *buffer);
void updateScreenPointPixelCoordinate(int x, int y);
void updateScreenPointPixelSize(int width, int height);

int GetScreenPixels(void *buffer, int x, int y, int width, int height);
#endif
}
#endif //ANDROIDSCREENSHOT_NATIVE_LIB_H
#include "ScreenPointPixel.h"

#include <string>
#include <stdlib.h>

//For Debugging
//#include "DebugCPP.h"
//http://stackoverflow.com/questions/43732825/use-debug-log-from-c/43735531#43735531

//Unity Headers
#include "UnityPluginHeaders/IUnityInterface.h"
#include "UnityPluginHeaders/IUnityGraphics.h"


//Headers for Windows
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(_WIN64) || defined(WINAPI_FAMILY)
#include <windows.h>
#include <gl/GL.h>
#include <gl/GLU.h>
#include <stdlib.h>
#include "glext.h"
#pragma comment(lib, "opengl32.lib")

//--------------------------------------------------

//Headers for Android
#elif defined(ANDROID) || defined(__ANDROID__)
#include <jni.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
//Link lGLESv2 in the CMakeList.txt file
//LOCAL_LDLIBS += −lGLESv2

//--------------------------------------------------

//Headers for MAC and iOS
//http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system
#elif defined(__APPLE__) && defined(__MACH__)
//Apple OSX and iOS (Darwin)
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
//iOS in Xcode simulator
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#elif TARGET_OS_IPHONE == 1
//iOS on iPhone, iPad, etc.
#include <OpenGLES/ES2/gl.h>
#include <OpenGLES/ES2/glext.h>
#elif TARGET_OS_MAC == 1
#include <OpenGL/gl.h>
#include <OpenGL/glu.h>
#include <GLUT/glut.h>
#endif

//--------------------------------------------------

//Headers for Linux
#elif defined(__linux__)
#include <GL/gl.h>
#include <GL/glu.h>
#endif

static void* screenPointPixelData = nullptr;
static int _x;
static int _y;
static int _width;
static int _height;

//----------------------------Enable Screenshot-----------------------------
void initScreenPointPixel(void* buffer, int x, int y, int width, int height) {
    screenPointPixelData = buffer;
    _x = x;
    _y = y;
    _width = width;
    _height = height;
}

void updateScreenPointPixelBufferPointer(void* buffer) {
    screenPointPixelData = buffer;
}

void updateScreenPointPixelCoordinate(int x, int y) {
    _x = x;
    _y = y;
}

void updateScreenPointPixelSize(int width, int height) {
    _width = width;
    _height = height;
}

int GetScreenPixels(void* buffer, int x, int y, int width, int height) {
    if (glGetError())
        return -1;

    //glReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, buffer);
    glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);

    if (glGetError())
        return -2;
    return 0;
}

//----------------------------UNITY RENDERING CALLBACK-----------------------------

// Plugin function to handle a specific rendering event
static void UNITY_INTERFACE_API OnRenderEventScreenPointPixel(int eventID)
{
    //Put rendering code below
    if (screenPointPixelData == nullptr) {
        //Debug::Log("Pointer is null", Color::Red);
        return;
    }
    int result = GetScreenPixels(screenPointPixelData, _x, _y, _width, _height);

    //std::string log_msg = "Cobol " + std::to_string(result);
    //Debug::Log(log_msg, Color::Green);
}

// Freely defined function to pass a callback to plugin-specific scripts
extern "C" UnityRenderingEvent UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API
GetRenderEventScreenPointPixelFunc()
{
    return OnRenderEventScreenPointPixel;
}
using System;
using System.Collections;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.UI;

public class ScreenPointPixel : MonoBehaviour
{
    [DllImport("ScreenPointPixel-lib", CallingConvention = CallingConvention.Cdecl)]
    public static extern void initScreenPointPixel(IntPtr buffer, int x, int y, int width, int height);
    //-------------------------------------------------------------------------------------
    [DllImport("ScreenPointPixel-lib", CallingConvention = CallingConvention.Cdecl)]
    public static extern void updateScreenPointPixelBufferPointer(IntPtr buffer);
    //-------------------------------------------------------------------------------------
    [DllImport("ScreenPointPixel-lib", CallingConvention = CallingConvention.Cdecl)]
    public static extern void updateScreenPointPixelCoordinate(int x, int y);
    //-------------------------------------------------------------------------------------
    [DllImport("ScreenPointPixel-lib", CallingConvention = CallingConvention.Cdecl)]
    public static extern void updateScreenPointPixelSize(int width, int height);
    //-------------------------------------------------------------------------------------

    //-------------------------------------------------------------------------------------
    [DllImport("ScreenPointPixel-lib", CallingConvention = CallingConvention.StdCall)]
    private static extern IntPtr GetRenderEventScreenPointPixelFunc();
    //-------------------------------------------------------------------------------------
    int width = 500;
    int height = 500;

    //Where Pixel data will be saved
    byte[] screenData;
    //Where handle that pins the Pixel data will stay
    GCHandle pinHandler;

    //Used to test the color
    public RawImage rawImageColor;

    // Use this for initialization
    void Awake()
    {
        Resolution res = Screen.currentResolution;
        width = res.width;
        height = res.height;

        //Allocate array to be used
        screenData = new byte[width * height * 4];

        //Pin the Array so that it doesn't move around
        pinHandler = GCHandle.Alloc(screenData, GCHandleType.Pinned);

        //Register the screenshot and pass the array that will receive the pixels
        IntPtr arrayPtr = pinHandler.AddrOfPinnedObject();

        initScreenPointPixel(arrayPtr, 0, 0, width, height);

        StartCoroutine(caller());
    }

    IEnumerator caller()
    {
        while (true)
        {
            //Use mouse position as the pixel position
            //Input.tou


#if UNITY_ANDROID || UNITY_IOS || UNITY_WSA_10_0
            if (!(Input.touchCount > 0))
            {
                yield return null;
                continue;
            }

            //Use touch position as the pixel position
            int x = Mathf.FloorToInt(Input.GetTouch(0).position.x);
            int y = Mathf.FloorToInt(Input.GetTouch(0).position.y);
#else
            //Use mouse position as the pixel position
            int x = Mathf.FloorToInt(Input.mousePosition.x);
            int y = Mathf.FloorToInt(Input.mousePosition.y);
#endif
            //Change this to any location from the screen you want
            updateScreenPointPixelCoordinate(x, y);

            //Must be 1 and 1
            updateScreenPointPixelSize(1, 1);

            //Take screenshot of the screen
            GL.IssuePluginEvent(GetRenderEventScreenPointPixelFunc(), 1);

            //Get the Color
            Color32 tempColor = new Color32();
            tempColor.r = screenData[0];
            tempColor.g = screenData[1];
            tempColor.b = screenData[2];
            tempColor.a = screenData[3];

            //Test it by assigning it to a raw image
            rawImageColor.color = tempColor;

            //Wait for a frame
            yield return null;
        }
    }

    void OnDisable()
    {
        //Unpin the array when disabled
        pinHandler.Free();
    }
}