gpt4 book ai didi

macos - glTexSubImage2D 将 NSImage 移动一个像素

转载 作者:行者123 更新时间:2023-12-03 17:11:34 25 4
gpt4 key购买 nike

我正在开发一个可以创建自己的纹理图集的应用程序。图集中的元素大小可能有所不同,但都放置在网格图案中。

一切都工作正常,除了当我用新元素(来自 NSImage 的数据)覆盖图集的部分时,图像向右移动一个像素。

我用来将像素写入图集的代码是:

-(void)writeToPlateWithImage:(NSImage*)anImage atCoord:(MyGridPoint)gridPos;
{
static NSSize insetSize; //ultimately this is the size of the image in the box
static NSSize boundingBox; //this is the size of the box that holds the image in the grid
static CGFloat multiplier;
multiplier = 1.0;
NSSize plateSize = NSMakeSize(atlas.width, atlas.height);//Size of entire atlas

MyGridPoint _gridPos;

//make sure the column and row position is legal
_gridPos.column= gridPos.column >= m_numOfColumns ? m_numOfColumns - 1 : gridPos.column;
_gridPos.row = gridPos.row >= m_numOfRows ? m_numOfRows - 1 : gridPos.row;

_gridPos.column = gridPos.column < 0 ? 0 : gridPos.column;
_gridPos.row = gridPos.row < 0 ? 0 : gridPos.row;

insetSize = NSMakeSize(plateSize.width / m_numOfColumns, plateSize.height / m_numOfRows);
boundingBox = insetSize;

//…code here to calculate the size to make anImage so that it fits into the space allowed
//on the atlas.
//multiplier var will hold a value that sizes up or down the image…

insetSize.width = anImage.size.width * multiplier;
insetSize.height = anImage.size.height * multiplier;

//provide a padding around the image so that when mipmaps are created the image doesn’t ‘bleed’
//if it’s the same size as the grid’s boxes.
insetSize.width -= ((insetSize.width * (insetPadding / 100)) * 2);
insetSize.height -= ((insetSize.height * (insetPadding / 100)) * 2);

//roundUp() is a handy function I found somewhere (I can’t remember now)
//that makes the first param a multiple of the the second..
//here we make sure the image lines are aligned as it’s a RGBA so we make
//it a multiple of 4
insetSize.width = (CGFloat)roundUp((int)insetSize.width, 4);
insetSize.height = (CGFloat)roundUp((int)insetSize.height, 4);

NSImage *insetImage = [self resizeImage:[anImage copy] toSize:insetSize];
NSData *insetData = [insetImage TIFFRepresentation];
GLubyte *data = malloc(insetData.length);
memcpy(data, [insetData bytes], insetData.length);
insetImage = NULL;
insetData = NULL;
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, atlas.textureIndex);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //have also tried 2,4, and 8
GLint Xplace = (GLint)(boundingBox.width * _gridPos.column) + (GLint)((boundingBox.width - insetSize.width) / 2);
GLint Yplace = (GLint)(boundingBox.height * _gridPos.row) + (GLint)((boundingBox.height - insetSize.height) / 2);
glTexSubImage2D(GL_TEXTURE_2D, 0, Xplace, Yplace, (GLsizei)insetSize.width, (GLsizei)insetSize.height, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
free(data);
glBindTexture(GL_TEXTURE_2D, 0);
glGetError();
}

图像是 RGBA、8 位(由 PhotoShop 报告),这是我一直在使用的测试图像: enter image description here

这是我的应用程序中结果的屏幕截图:

enter image description here

我是否错误地解压了图像......?我知道 resizeImage: 函数可以工作,因为我已将其结果保存到磁盘并绕过它,因此问题出在 gl 代码中的某个地方...

编辑:只是为了澄清一下,正在渲染的图集部分比框图更大。因此,偏移发生在使用 glTexSubImage2D 写入的区域内。

编辑2:最后,通过偏移进入图集部分的复制数据进行排序。

我不完全明白为什么会这样,也许这是一个黑客而不是一个正确的解决方案,但它就是这样。

//resize the image to fit into the section of the atlas
NSImage *insetImage = [self resizeImage:[anImage copy] toSize:NSMakeSize(insetSize.width, insetSize.height)];
//pointer to the raw data
const void* insetDataPtr = [[insetImage TIFFRepresentation] bytes];
//for debugging, I placed the offset value next
int offset = 8;//it needed a 2 pixel (2 * 4 byte for RGBA) offset
//copy the data with the offset into a temporary data buffer
memcpy(data, insetDataPtr + offset, insetData.length - offset);
/*
.
. Calculate it's position with the texture
.
*/
//And finally overwrite the texture
glTexSubImage2D(GL_TEXTURE_2D, 0, Xplace, Yplace, (GLsizei)insetSize.width, (GLsizei)insetSize.height, GL_RGBA, GL_UNSIGNED_BYTE, data);

最佳答案

您可能遇到了我已经在这里回答的问题:stackoverflow.com/a/5879551/524368

这并不是真正的像素坐标,而是纹素的像素完美寻址。这对于纹理图集尤其重要。一个常见的误解是,许多人认为纹理坐标 0 和 1 恰好位于像素中心。但在 OpenGL 中情况并非如此,纹理坐标 0 和 1 恰好位于纹理环绕的像素之间的边界上。如果您构建纹理图集时假设 0 和 1 位于像素中心,那么在 OpenGL 中使用完全相同的寻址方案将导致图片模糊或像素移位。您需要考虑到这一点。

I still don't understand how that makes a difference to a sub-section of the texture that's being rendered.

理解 OpenGL 纹理与其说是图像,不如说是插值器的支持样本(因此着色器中的“采样器”制服)很有帮助。因此,为了获得真正清晰的图像,您必须以某种方式选择要从中采样的纹理坐标,以便插值器准确地在支持样本的位置进行评估。然而,这些样本的位置既不是整数坐标也不是简单的分数 (i/N)。

请注意,较新版本的 GLSL 提供纹理采样函数 texelFetch,它完全绕过插值器并直接寻址纹理像素。如果您需要像素完美的纹理,您可能会发现它更容易使用(如果可用)。

关于macos - glTexSubImage2D 将 NSImage 移动一个像素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24311419/

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