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