gpt4 book ai didi

objective-c - GLSL - 如何访问纹理的像素数据是 GLSL 着色器?

转载 作者:行者123 更新时间:2023-12-02 17:47:52 27 4
gpt4 key购买 nike

我想要做的是,在 OpenGL 着色器中访问纹理的像素数据。之后,将它们的红色分量进行比较,以便我可以获得具有最大红色分量的像素的坐标。我可以用 Objective C 来做,有 CPU 处理能力。代码如下所示。

- (void)processNewPixelBuffer:(CVPixelBufferRef)pixelBuffer
{
short maxR = 0;
NSInteger x = -1, y = -1;

CVPixelBufferLockBaseAddress(pixelBuffer, 0);
height = CVPixelBufferGetHeight(pixelBuffer);
width = CVPixelBufferGetWidth(pixelBuffer);

size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
uint8_t *src_buff = CVPixelBufferGetBaseAddress(pixelBuffer);

short** rawData = malloc(sizeof(short*) * height);
for (int i = 0; i < height; i++){
rawData[i] = malloc((sizeof(short) * width));
for (int j = 0; j < width; j++)
rawData[i][j] = (short)src_buff[(i + width * j) * 4];
}

for (int j = 0; j < height; j++)
for (int i = 0; i < width; i++)
if (rawData[i][j] >= maxR) {
maxR = rawData[i][j];
x = i;
y = j;
}

free(rawData);
}

那么,我的问题是,如何使用 GPU 来执行此过程?我可以将 pixelBuffer 作为 OpenGL Shader 中的纹理。

顶点着色器

attribute vec4 position;
attribute vec4 inputTextureCoordinate;

varying vec2 textureCoordinate;

void main()
{
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
}

片段着色器

varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture; //The input sample, in RGBA format

void main()
{
// Code here
}

如何修改着色器以便找出具有最大红色分量的像素?然后,我想将该像素变为红色,将其他像素变为白色。这可能吗?

最佳答案

您可以做的是使用经典的缩小着色器。您将屏幕大小的四边形渲染为输入纹理尺寸一半的纹理/屏幕(最好使用 FBO),然后在片段着色器中为每个像素计算 2x2 纹素 block 的最大值,输出最大值和其对应的纹理坐标:

//no need for any textrue coords, we render screen-aligned anyway
uniform sampler2D inputImageTexture; //The input sample, in RGBA format
uniform vec2 invImageSize; // (1/width, 1/height)

void main()
{
vec2 coord = (2.0 * floor(gl_FragCoord.xy) + 0.5) * invImageSize;
float ll = texture2D(inputImageTexture, coord).r;
float lr = texture2D(inputImageTexture, coord+vec2(invImageSize, 0.0)).r;
float ul = texture2D(inputImageTexture, coord+vec2(0.0, invImageSize)).r;
float ur = texture2D(inputImageTexture, coord+vec2(invImageSize, invImageSize)).r;

vec4 color = vec4(ll, coord, 1.0);
if(lr > color.r)
color.xyz = vec3(lr, coord+vec2(invImageSize, 0.0));
if(ul > color.r)
color.xyz = vec3(ul, coord+vec2(0.0, invImageSize));
if(ur > color.r)
color.xyz = vec3(ur, coord+vec2(invImageSize, invImageSize));
gl_FragColor = color;
}

然后您在下一步中使用此输出纹理作为输入纹理并再次渲染成一半大小的纹理,直到您处于 1x1 纹理(或者更确切地说是您可以在 CPU 上处理的小纹理)。但是当然,在第二个和所有后续 channel 中,您必须输出存储的纹理坐标而不是计算的坐标。

vec2 coord = (2.0 * floor(gl_FragCoord.xy) + 0.5) * invImageSize;
vec4 ll = texture2D(inputImageTexture, coord);
vec4 lr = texture2D(inputImageTexture, coord+vec2(invImageSize, 0.0));
vec4 ul = texture2D(inputImageTexture, coord+vec2(0.0, invImageSize));
vec4 ur = texture2D(inputImageTexture, coord+vec2(invImageSize, invImageSize));

ll = (lr.r > ll.r) ? lr : ll;
ll = (ul.r > ll.r) ? ul : ll;
ll = (ur.r > ll.r) ? ur : ll;
gl_FragColor = ll;

当你最终拥有最大红色部分的纹素坐标(作为 [0,1] 中的归一化纹理坐标)时,你只需要在该位置绘制一个完全白色的屏幕/纹理大小的四边形和一个红点.但我不能向您保证,与纯 CPU 解决方案相比,这种多遍算法(与任务的简单性相比,它相当麻烦)真的会给您带来任何好处。您不能在一次通过中神奇地读取每个输出像素的所有图像像素并决定其颜色,这不是(或应该)使用片段着色器的方式。

编辑:顺便说一句。可能不需要将所有数据复制到 CPU 解决方案中的额外临时缓冲区中,至少不需要通过使用一个奇怪的数组数组来将它散布在内存中的一个临时缓冲区,该数组应该是一个内存块(或没有)直接处理输入时),更不用说大量内存分配了。因此,在考虑将任何东西转移到 GPU 上之前,先修复您的 CPU 解决方案。

关于objective-c - GLSL - 如何访问纹理的像素数据是 GLSL 着色器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12488049/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com