【问题标题】:iPad texture loading differences (32-bit vs. 64-bit)iPad 纹理加载差异(32 位与 64 位)
【发布时间】:2014-02-10 22:35:43
【问题描述】:

我正在开发一个绘图应用程序,我注意到 32 位 iPad 与 64 位 iPad 上加载的纹理存在显着差异。

这是在 32 位 iPad 上绘制的纹理:

这是在 64 位 iPad 上绘制的纹理:

64 位是我想要的,但似乎它可能会丢失一些数据?

我用这段代码创建了一个默认的画笔纹理:

UIGraphicsBeginImageContext(CGSizeMake(64, 64));
CGContextRef defBrushTextureContext = UIGraphicsGetCurrentContext();
UIGraphicsPushContext(defBrushTextureContext);

size_t num_locations = 3;
CGFloat locations[3] = { 0.0, 0.8, 1.0 };
CGFloat components[12] = { 1.0,1.0,1.0, 1.0,
    1.0,1.0,1.0, 1.0,
    1.0,1.0,1.0, 0.0 };
CGColorSpaceRef myColorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef myGradient = CGGradientCreateWithColorComponents (myColorspace, components, locations, num_locations);

CGPoint myCentrePoint = CGPointMake(32, 32);
float myRadius = 20;

CGGradientDrawingOptions options = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
CGContextDrawRadialGradient (UIGraphicsGetCurrentContext(), myGradient, myCentrePoint,
                             0, myCentrePoint, myRadius,
                             options);

CFRelease(myGradient);
CFRelease(myColorspace);
UIGraphicsPopContext();

[self setBrushTexture:UIGraphicsGetImageFromCurrentImageContext()];

UIGraphicsEndImageContext();

然后像这样实际设置画笔纹理:

-(void) setBrushTexture:(UIImage*)brushImage{
// save our current texture.
currentTexture = brushImage;

// first, delete the old texture if needed
if (brushTexture){
    glDeleteTextures(1, &brushTexture);
    brushTexture = 0;
}

// fetch the cgimage for us to draw into a texture
CGImageRef brushCGImage = brushImage.CGImage;

// Make sure the image exists
if(brushCGImage) {
    // Get the width and height of the image
    GLint width = CGImageGetWidth(brushCGImage);
    GLint height = CGImageGetHeight(brushCGImage);

    // Texture dimensions must be a power of 2. If you write an application that allows users to supply an image,
    // you'll want to add code that checks the dimensions and takes appropriate action if they are not a power of 2.

    // Allocate  memory needed for the bitmap context
    GLubyte* brushData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
    // Use  the bitmatp creation function provided by the Core Graphics framework.
    CGContextRef brushContext = CGBitmapContextCreate(brushData, width, height, 8, width * 4, CGImageGetColorSpace(brushCGImage), kCGImageAlphaPremultipliedLast);
    // After you create the context, you can draw the  image to the context.
    CGContextDrawImage(brushContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), brushCGImage);
    // You don't need the context at this point, so you need to release it to avoid memory leaks.
    CGContextRelease(brushContext);

    // Use OpenGL ES to generate a name for the texture.
    glGenTextures(1, &brushTexture);
    // Bind the texture name.
    glBindTexture(GL_TEXTURE_2D, brushTexture);
    // Set the texture parameters to use a minifying filter and a linear filer (weighted average)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    // Specify a 2D texture image, providing the a pointer to the image data in memory
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, brushData);
    // Release  the image data; it's no longer needed
    free(brushData);
}
}

更新:

我已将 CGFloats 更新为 GLfloats,但没有成功。也许这个渲染代码有问题?

if(frameBuffer){
    // draw the stroke element
    [self prepOpenGLStateForFBO:frameBuffer];
    [self prepOpenGLBlendModeForColor:element.color];
    CheckGLError();
}

// find our screen scale so that we can convert from
// points to pixels
GLfloat scale = self.contentScaleFactor;

// fetch the vertex data from the element
struct Vertex* vertexBuffer = [element generatedVertexArrayWithPreviousElement:previousElement forScale:scale];

glLineWidth(2);

// if the element has any data, then draw it
if(vertexBuffer){
    glVertexPointer(2, GL_FLOAT, sizeof(struct Vertex), &vertexBuffer[0].Position[0]);
    glColorPointer(4, GL_FLOAT, sizeof(struct Vertex), &vertexBuffer[0].Color[0]);
    glTexCoordPointer(2, GL_FLOAT, sizeof(struct Vertex), &vertexBuffer[0].Texture[0]);
    glDrawArrays(GL_TRIANGLES, 0, (GLint)[element numberOfSteps] * (GLint)[element numberOfVerticesPerStep]);
    CheckGLError();
}

if(frameBuffer){
    [self unprepOpenGLState];
}

顶点结构如下:

struct Vertex{
    GLfloat Position[2];    // x,y position
    GLfloat Color [4];      // rgba color
    GLfloat Texture[2];    // x,y texture coord
};

更新:

这个问题实际上并不是基于 32 位、64 位,而是 A7 GPU 和 GL 驱动程序的不同之处。我通过在 64 位 iPad 上运行 32 位构建和 64 位构建发现了这一点。在应用程序的两个版本上,纹理最终看起来完全相同。

【问题讨论】:

  • CGFloat 在 32 位 iOS 目标上是单精度的,在 64 位上是双精度的。您没有在直接与 GL 交互的任何地方使用此 typedef,是吗?另一方面,GL 总是为 GLfloat 使用 32 位,如果你混合匹配 typedef,就会发生这种事情。
  • 我没有看到任何与您发布的内容立即看起来有问题的内容。我怀疑@Andon 是对的——检查代码中其他地方的CGFloat 使用情况,特别是在你定义画笔正在绘制的帧缓冲区的地方。
  • 谢谢。我已经这样做了,但我仍然注意到同样的行为。我已经用进一步的解释更新了这个问题。
  • 您是否使用着色器来渲染纹理?如果是这样,请将其发布并检查其中的精度。 64 位 iPad 会忽略 lowp 而使用 mediump,这有时会导致渲染差异。
  • 对我来说确实是个精度问题。 OpenGL ES 1.1 在 A7 GPU 上模拟(意味着它在内部使用着色器)。您可以发布更多 OpenGL 设置,包括使用的混合状态吗?此外,您应该在设置 GL_TEXTURE_MIN_FILTER 的同时将 GL_TEXTURE_MAG_FILTER 设置为线性。

标签: ios objective-c opengl-es core-graphics


【解决方案1】:

我希望你检查两件事。

  1. 在 OpenGL 中检查您的 Alpha 混合逻辑(或选项)。

  2. 检查与拖动速度成正比的插值逻辑。

您似乎没有第二个或无效,这是绘图应用程序所需的

【讨论】:

    【解决方案2】:

    我认为问题不在于纹理,而在于您将线元素合成到的帧缓冲区。

    您的代码片段看起来像是逐段绘制,因此有几个重叠的段绘制在彼此之上。如果帧缓冲区的深度较低,则会出现伪影,尤其是在混合区域的较亮区域。

    您可以使用 Xcode 的 OpenGL 调试器检查帧缓冲区。通过在设备上运行您的代码来激活它,然后单击“Capture OpenGL ES Frame”小按钮:。

    在“Debug Navigator”中选择一个“glBindFramebuffer”命令,在控制台区域查看帧缓冲区描述:

    有趣的部分是GL_FRAMEBUFFER_INTERNAL_FORMAT

    【讨论】:

    • 我看到的内部格式和你一样,但你建议我做什么?
    • @Jordan 你在两个设备上看到相同的内部格式吗?
    • 是的,我在 32 位和 64 位 iPad 上看到相同的格式。
    【解决方案3】:

    在我看来,问题在于您在合成不同图像通道时使用的混合模式。我假设您上传纹理仅用于显示,并保留您合成不同绘图操作的内存图像,或者您使用 glReadPixels 读回图像内容? 基本上,您的第二张图像看起来像一个像预乘 alpha 图像一样绘制的直 alpha 图像。 为确保不是纹理问题,请在上传到纹理之前将 NSImage 保存到文件中,并检查图像是否确实正确。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-21
      • 1970-01-01
      • 1970-01-01
      • 2010-12-18
      • 1970-01-01
      • 2021-05-05
      • 1970-01-01
      相关资源
      最近更新 更多