如何在 IOS Swift OpenglES 1.0/1.1/2.0 上将文本和图像绘制为纹理
How to draw text and image as textures on IOS Swift OpenglES 1.0/1.1/2.0
我正在尝试使用 OpenglES 1.0 渲染 png 图像的纹理,并在 Swift 上绘制字符串作为纹理。但是 none 我用谷歌搜索并在此处找到的示例无法正常工作。我花了足够多的时间来解决这个问题。
在屏幕上只显示非纹理抽屉,我删除了所有基于三角形的抽屉,相机角度或视图没有问题,问题是纹理渲染。
感谢任何能帮助我的人,这是我将 png 绘制为纹理的简化代码,但什么也没有显示,甚至没有显示白框;
这是渲染器class;
import GLKit
import SWXMLHash
class MapViewController: GLKViewController {
@IBOutlet var glView: GLKView!
var rViewController : UIViewController? = nil
var context : EAGLContext!
var ratio : Float!
var size : Float!
override func viewDidLoad() {
super.viewDidLoad()
self.context = EAGLContext.init(API: EAGLRenderingAPI.OpenGLES1)
if self.context == nil {
Util.log("failed to create context for self")
}
glView.context = self.context
EAGLContext.setCurrentContext(self.context)
glClearColor(0.95, 0.95, 0.95, 0.5)
glDisable(GLenum(GL_CULL_FACE))
glEnable(GLenum(GL_DEPTH_TEST))
glEnable(GLenum(GL_BLEND))
glBlendFunc(GLenum(GL_SRC_ALPHA), GLenum(GL_ONE_MINUS_SRC_ALPHA))
}
override func viewWillLayoutSubviews() {
if firstInit {
let width = glView.frame.size.width
let height = glView.frame.size.height
glViewport(0, 0, Int32(width), Int32(height))
let fieldOfView = GLKMathDegreesToRadians(60)
glEnable(GLenum(GL_NORMALIZE))
self.ratio = Float(width)/Float(height)
glMatrixMode(GLenum(GL_PROJECTION))
glLoadIdentity()
size = zNear * Float(tan(Double(fieldOfView/2.0)))
glFrustumf(-size, size, -size / (ratio), size / (ratio), zNear, zFar)
glMatrixMode(GLenum(GL_MODELVIEW))
glLoadIdentity()
}
}
override func glkView(view: GLKView, drawInRect rect: CGRect) {
glPushMatrix()
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
glClear(GLbitfield(GL_DEPTH_BUFFER_BIT))
glMatrixMode(GLenum(GL_MODELVIEW))
glLoadIdentity()
glEnableClientState(GLenum(GL_VERTEX_ARRAY))
glEnableClientState(GLenum(GL_COLOR_ARRAY))
glEnable(GLenum(GL_TEXTURE_2D))
// glEnable(GLenum(GL_BLEND))
// glEnableClientState(GLenum(GL_NORMAL_ARRAY))
glEnableClientState(GLenum(GL_TEXTURE_COORD_ARRAY))
let fl = CGPoint(x: 0, y: 0)
let drawer = IconDrawer(x: 0, y: 0, z: 0, size:150, roomCoords: fl, exampleimage)
drawer.draw()
glDisable(GLenum(GL_TEXTURE_2D))
glDisableClientState(GLenum(GL_TEXTURE_COORD_ARRAY))
glDisableClientState(GLenum(GL_VERTEX_ARRAY));
glDisableClientState(GLenum(GL_COLOR_ARRAY));
glPopMatrix();
}
}
这是抽屉class;
import Foundation
class IconDrawer : Mesh {
let normals : [GLfloat] = [
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0 ]
let textureCoordinates : [Float] = [0.0, 1.0,
1.0, 1.0,
1.0, 0.0,
0.0, 0.0]
let indices = [0, 1, 2, 0, 2, 3]
var coordinates : CGPoint? = nil
var texture:GLuint=0
static var currentScreenMid = CGPoint(x: 0, y: 0)
init(x : Float, y : Float, z : Float, size : Int, roomCoords : CGPoint, imageName : String) {
super.init()
// Mapping coordinates for the vertices
self.coordinates = roomCoords
let w = Float((size)/1000);
let h = Float((size)/1000);
let vertices : [Float] = [-w+x, -h+y, z+Zunit,
w+x, -h+y, z+Zunit,
w+x, h+y, z+Zunit,
-w+x, h+y, z+Zunit]
setIndices(indices);
setVertices(vertices);
setTextureCoordinates(textureCoordinates);
//PART 1 LOAD PNG
let image = UIImage(named : imageName)
let iwidth = CGImageGetWidth(image?.CGImage)
let iheight = CGImageGetHeight(image?.CGImage)
let imageData = malloc(iwidth * iheight * 4)
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue)
let imageContext : CGContextRef = CGBitmapContextCreate(imageData, iwidth, iheight, 8, iwidth * 4, CGColorSpaceCreateDeviceRGB(), bitmapInfo.rawValue)!
CGContextClearRect(imageContext, CGRectMake(0, 0, CGFloat(iwidth), CGFloat(iheight)))
CGContextTranslateCTM(imageContext, 0, CGFloat((iheight - iheight)))
CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, CGFloat(iwidth), CGFloat(iheight)), image?.CGImage)
glTexImage2D(GLenum(GL_TEXTURE_2D), GLint(0), GL_RGBA, Int32(iwidth), Int32(iheight), GLint(0), GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), imageData)
self.w = GLsizei(Int(image!.size.width))
self.h = GLsizei(Int(image!.size.height))
loadBitmap(imageData)
fl.bitmaps.append(imageData)
//PART 2 CREATE TEXTURE WITH THE IMAGE DATA
glGenTextures(1, &texture)
glBindTexture(GLenum(GL_TEXTURE_2D), texture)
glTexImage2D(GLenum(GL_TEXTURE_2D), Int32(0), GL_RGBA, GLsizei(Int(image!.size.width)), GLsizei(Int(image!.size.height)), Int32(0), GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), imageData)
glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), GLint(GL_LINEAR))
glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MAG_FILTER), GLint(GL_LINEAR))
if image != nil {
let imageRect = CGRectMake(0.0, 0.0, image!.size.width, image!.size.height);
UIGraphicsBeginImageContextWithOptions(image!.size, false, UIScreen.mainScreen().scale)
image?.drawInRect(imageRect)
UIGraphicsEndImageContext();
}
}
override func draw() {
//PART 3 RENDER
glEnableClientState(GLenum(GL_VERTEX_ARRAY));
glEnableClientState(GLenum(GL_NORMAL_ARRAY));
glEnableClientState(GLenum(GL_TEXTURE_COORD_ARRAY));
glEnable(UInt32(GL_TEXTURE_2D));
glEnable(UInt32(GL_BLEND));
glBlendFunc(UInt32(GL_SRC_ALPHA), UInt32(GL_ONE_MINUS_SRC_ALPHA));
Drawer.printGLErrors()
glBindTexture(GLenum(GL_TEXTURE_2D), texture)
Drawer.printGLErrors()
glVertexPointer(Int32(2), GLenum(GL_FLOAT), GLsizei(0), self.mVerticesBuffer!)
Drawer.printGLErrors()
glNormalPointer(GLenum(GL_FLOAT), GLsizei(0), normals)
Drawer.printGLErrors()
glTexCoordPointer(Int32(2), GLenum(GL_FLOAT), GLsizei(0), textureCoordinates)
Drawer.printGLErrors()
glDrawArrays(GLenum(GL_TRIANGLE_STRIP), 0, 4)
Drawer.printGLErrors()
}
}
您面临的问题是开箱即用的非 POT(2 的幂)纹理不支持。我相信有一些扩展,但我不会为此烦恼。
无论如何,纹理尺寸必须是 POT(2、4、8、16...),因此您有 2 个选择。您可以在获取原始图像数据指针时创建 POT 上下文,并将图像大小调整为所需的 POT 大小,并在此过程中缩放图像。一种更常见的方法是使用 NULL 数据指针创建足够大的纹理,然后使用 glTexSubImage
和原始图像大小参数将数据发送到纹理。此过程还需要您更改纹理坐标,因此您将拥有 imageWidth/textureWidth
而不是 1.0,高度也相同。第二个过程需要更多的努力,但通常用于升级为纹理图集过程(将多个图像放在同一个纹理上)。
那么最快的方法就是在 Photoshop 或其他软件中调整图像大小,例如将其调整为 128x128。只是注意 POT 尺寸不需要相同,128x64 也应该有效。
我正在尝试使用 OpenglES 1.0 渲染 png 图像的纹理,并在 Swift 上绘制字符串作为纹理。但是 none 我用谷歌搜索并在此处找到的示例无法正常工作。我花了足够多的时间来解决这个问题。
在屏幕上只显示非纹理抽屉,我删除了所有基于三角形的抽屉,相机角度或视图没有问题,问题是纹理渲染。
感谢任何能帮助我的人,这是我将 png 绘制为纹理的简化代码,但什么也没有显示,甚至没有显示白框;
这是渲染器class;
import GLKit
import SWXMLHash
class MapViewController: GLKViewController {
@IBOutlet var glView: GLKView!
var rViewController : UIViewController? = nil
var context : EAGLContext!
var ratio : Float!
var size : Float!
override func viewDidLoad() {
super.viewDidLoad()
self.context = EAGLContext.init(API: EAGLRenderingAPI.OpenGLES1)
if self.context == nil {
Util.log("failed to create context for self")
}
glView.context = self.context
EAGLContext.setCurrentContext(self.context)
glClearColor(0.95, 0.95, 0.95, 0.5)
glDisable(GLenum(GL_CULL_FACE))
glEnable(GLenum(GL_DEPTH_TEST))
glEnable(GLenum(GL_BLEND))
glBlendFunc(GLenum(GL_SRC_ALPHA), GLenum(GL_ONE_MINUS_SRC_ALPHA))
}
override func viewWillLayoutSubviews() {
if firstInit {
let width = glView.frame.size.width
let height = glView.frame.size.height
glViewport(0, 0, Int32(width), Int32(height))
let fieldOfView = GLKMathDegreesToRadians(60)
glEnable(GLenum(GL_NORMALIZE))
self.ratio = Float(width)/Float(height)
glMatrixMode(GLenum(GL_PROJECTION))
glLoadIdentity()
size = zNear * Float(tan(Double(fieldOfView/2.0)))
glFrustumf(-size, size, -size / (ratio), size / (ratio), zNear, zFar)
glMatrixMode(GLenum(GL_MODELVIEW))
glLoadIdentity()
}
}
override func glkView(view: GLKView, drawInRect rect: CGRect) {
glPushMatrix()
glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
glClear(GLbitfield(GL_DEPTH_BUFFER_BIT))
glMatrixMode(GLenum(GL_MODELVIEW))
glLoadIdentity()
glEnableClientState(GLenum(GL_VERTEX_ARRAY))
glEnableClientState(GLenum(GL_COLOR_ARRAY))
glEnable(GLenum(GL_TEXTURE_2D))
// glEnable(GLenum(GL_BLEND))
// glEnableClientState(GLenum(GL_NORMAL_ARRAY))
glEnableClientState(GLenum(GL_TEXTURE_COORD_ARRAY))
let fl = CGPoint(x: 0, y: 0)
let drawer = IconDrawer(x: 0, y: 0, z: 0, size:150, roomCoords: fl, exampleimage)
drawer.draw()
glDisable(GLenum(GL_TEXTURE_2D))
glDisableClientState(GLenum(GL_TEXTURE_COORD_ARRAY))
glDisableClientState(GLenum(GL_VERTEX_ARRAY));
glDisableClientState(GLenum(GL_COLOR_ARRAY));
glPopMatrix();
}
}
这是抽屉class;
import Foundation
class IconDrawer : Mesh {
let normals : [GLfloat] = [
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0,
0.0, 0.0, 1.0 ]
let textureCoordinates : [Float] = [0.0, 1.0,
1.0, 1.0,
1.0, 0.0,
0.0, 0.0]
let indices = [0, 1, 2, 0, 2, 3]
var coordinates : CGPoint? = nil
var texture:GLuint=0
static var currentScreenMid = CGPoint(x: 0, y: 0)
init(x : Float, y : Float, z : Float, size : Int, roomCoords : CGPoint, imageName : String) {
super.init()
// Mapping coordinates for the vertices
self.coordinates = roomCoords
let w = Float((size)/1000);
let h = Float((size)/1000);
let vertices : [Float] = [-w+x, -h+y, z+Zunit,
w+x, -h+y, z+Zunit,
w+x, h+y, z+Zunit,
-w+x, h+y, z+Zunit]
setIndices(indices);
setVertices(vertices);
setTextureCoordinates(textureCoordinates);
//PART 1 LOAD PNG
let image = UIImage(named : imageName)
let iwidth = CGImageGetWidth(image?.CGImage)
let iheight = CGImageGetHeight(image?.CGImage)
let imageData = malloc(iwidth * iheight * 4)
let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedLast.rawValue)
let imageContext : CGContextRef = CGBitmapContextCreate(imageData, iwidth, iheight, 8, iwidth * 4, CGColorSpaceCreateDeviceRGB(), bitmapInfo.rawValue)!
CGContextClearRect(imageContext, CGRectMake(0, 0, CGFloat(iwidth), CGFloat(iheight)))
CGContextTranslateCTM(imageContext, 0, CGFloat((iheight - iheight)))
CGContextDrawImage(imageContext, CGRectMake(0.0, 0.0, CGFloat(iwidth), CGFloat(iheight)), image?.CGImage)
glTexImage2D(GLenum(GL_TEXTURE_2D), GLint(0), GL_RGBA, Int32(iwidth), Int32(iheight), GLint(0), GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), imageData)
self.w = GLsizei(Int(image!.size.width))
self.h = GLsizei(Int(image!.size.height))
loadBitmap(imageData)
fl.bitmaps.append(imageData)
//PART 2 CREATE TEXTURE WITH THE IMAGE DATA
glGenTextures(1, &texture)
glBindTexture(GLenum(GL_TEXTURE_2D), texture)
glTexImage2D(GLenum(GL_TEXTURE_2D), Int32(0), GL_RGBA, GLsizei(Int(image!.size.width)), GLsizei(Int(image!.size.height)), Int32(0), GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), imageData)
glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), GLint(GL_LINEAR))
glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MAG_FILTER), GLint(GL_LINEAR))
if image != nil {
let imageRect = CGRectMake(0.0, 0.0, image!.size.width, image!.size.height);
UIGraphicsBeginImageContextWithOptions(image!.size, false, UIScreen.mainScreen().scale)
image?.drawInRect(imageRect)
UIGraphicsEndImageContext();
}
}
override func draw() {
//PART 3 RENDER
glEnableClientState(GLenum(GL_VERTEX_ARRAY));
glEnableClientState(GLenum(GL_NORMAL_ARRAY));
glEnableClientState(GLenum(GL_TEXTURE_COORD_ARRAY));
glEnable(UInt32(GL_TEXTURE_2D));
glEnable(UInt32(GL_BLEND));
glBlendFunc(UInt32(GL_SRC_ALPHA), UInt32(GL_ONE_MINUS_SRC_ALPHA));
Drawer.printGLErrors()
glBindTexture(GLenum(GL_TEXTURE_2D), texture)
Drawer.printGLErrors()
glVertexPointer(Int32(2), GLenum(GL_FLOAT), GLsizei(0), self.mVerticesBuffer!)
Drawer.printGLErrors()
glNormalPointer(GLenum(GL_FLOAT), GLsizei(0), normals)
Drawer.printGLErrors()
glTexCoordPointer(Int32(2), GLenum(GL_FLOAT), GLsizei(0), textureCoordinates)
Drawer.printGLErrors()
glDrawArrays(GLenum(GL_TRIANGLE_STRIP), 0, 4)
Drawer.printGLErrors()
}
}
您面临的问题是开箱即用的非 POT(2 的幂)纹理不支持。我相信有一些扩展,但我不会为此烦恼。
无论如何,纹理尺寸必须是 POT(2、4、8、16...),因此您有 2 个选择。您可以在获取原始图像数据指针时创建 POT 上下文,并将图像大小调整为所需的 POT 大小,并在此过程中缩放图像。一种更常见的方法是使用 NULL 数据指针创建足够大的纹理,然后使用 glTexSubImage
和原始图像大小参数将数据发送到纹理。此过程还需要您更改纹理坐标,因此您将拥有 imageWidth/textureWidth
而不是 1.0,高度也相同。第二个过程需要更多的努力,但通常用于升级为纹理图集过程(将多个图像放在同一个纹理上)。
那么最快的方法就是在 Photoshop 或其他软件中调整图像大小,例如将其调整为 128x128。只是注意 POT 尺寸不需要相同,128x64 也应该有效。