Convert an UIImage in a texture
I haven't test the following but i will decompose the conversion in 3 steps:
Extract info for your image:
UIImage* image = [UIImage imageNamed:@"imageToApplyAsATexture.png"];
CGImageRef imageRef = [image CGImage];
int width = CGImageGetWidth(imageRef);
int height = CGImageGetHeight(imageRef);Allocate a
textureData
with the above properties:GLubyte* textureData = (GLubyte *)malloc(width * height * 4); // if 4 components per pixel (RGBA)
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
NSUInteger bytesPerPixel = 4;
NSUInteger bytesPerRow = bytesPerPixel * width;
NSUInteger bitsPerComponent = 8;
CGContextRef context = CGBitmapContextCreate(textureData, width, height,
bitsPerComponent, bytesPerRow, colorSpace,
kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(context);Set-up your texture:
GLuint textureID;
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
EDIT:
Read this tut; everything is explained from the conversion of one image to a texture and applying a texture in an iOS environment.
UIImage to MTLTexture when downloaded as PNG
In Metal
coordinates are reversed. However, you now have a much simpler way to load textures with MTKTextureLoader
:
import MetalKit
let textureLoader = MTKTextureLoader(device: device)
let texture: MTLTexture = textureLoader.newTextureWithContentsOfURL(filePath, options: nil)
This will create a new texture
for you with the appropriate coordinates using the image located at filePath
. If you don't want to use a NSURL
you also have the newTextureWithData
and newTextureWithCGImage
options.
In UIImage to Texture conversion, Texture is flipped vertically
This two lines fixed the problem
CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0,height);
CGContextConcatCTM(context, flipVertical);
iOS, SpriteKit convert SKTextureAtlas/SKTexture into UIImage
Ok, After weekend I finally got it working.
Important part is
guard let render = view.texture(from: sprite) else { return UIImage() }
return UIImage(cgImage: render.cgImage())
which I got thanks to this answer
Full working code:
func image(texture: SKTexture) -> UIImage {
let view = SKView(frame:CGRect(x: 0, y: 0, width: texture.size().width, height: texture.size().height))
let scene = SKScene(size: texture.size())
let sprite = SKSpriteNode(texture: texture)
sprite.position = CGPoint(x: view.frame.midX, y: view.frame.midY)
scene.addChild(sprite)
view.presentScene(scene)
guard let render = view.texture(from: sprite) else { return UIImage() }
return UIImage(cgImage: render.cgImage())
}
The reason I was looking to make it work is that I'm writing game with SpriteKit however UI is done with SwiftUI.
How to get UIImage from texture of an EAGLView?
http://www.bit-101.com/blog/?p=1861
MTLTexture displays UIImages incorrectly if converted to textures
There are two separate concerns here: matching the pixel format between your render pipeline state and your framebuffer, and matching the pixel format between your image data and the pixel format of the texture you create from it.
In the first case, it's sensible to use MTLPixelFormatBGRA8Unorm
. This has to be set on your CAMetalLayer
(or MTKView
) as well as your render pipeline state's primary color attachment. If they don't agree, you'll get the exception you mentioned. This configuration looks something like this:
metalView.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
// and elsewhere...
pipelineStateDescriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm;
In the latter case, what matters is that the component ordering of your image data matches the format you choose for your texture. The colorspace you get from your UIImage
is sRGB, so you need to specify MTLPixelFormatRGBA8Unorm
as your texture's pixel format (where you currently have MTLPixelFormatBGRA8Unorm
in your texture creation code), or swap the bytes in the red and blue channels manually.
The pixel formats of your view and the texture you create from the image don't have to be the same. Metal swizzles colors when you sample textures and when you write to the framebuffer, so within your shaders, you can always assume an RGBA ordering.
Add UIImage as texture to a Plane in RealityKit
Currently, you cannot use UIImage or CIImage as a shader's texture in RealityKit 2.0. In both versions of RealityKit, the texture must be loaded via the String type parameter of the load()
method.
RealityKit 2.0
To assign a texture to a shader in RealityKit 2.0 use the following approach:
let mesh: MeshResource = .generatePlane(width: 0.45, depth: 0.45)
var material = SimpleMaterial()
material.color = .init(tint: .white.withAlphaComponent(0.999),
texture: .init(try! .load(named: "texture.png")))
material.metallic = .float(1.0)
material.roughness = .float(0.0)
let model = ModelEntity(mesh: mesh, materials: [material])
RealityKit 1.0
To assign a texture to a shader in RealityKit 1.0 use this approach:
let scene = try! Experience.loadMyScene()
var material = SimpleMaterial()
material.baseColor = try! .texture(.load(named: "texture.png"))
material.metallic = MaterialScalarParameter(floatLiteral: 1.0)
material.roughness = MaterialScalarParameter(floatLiteral: 0.0)
material.tintColor = UIColor.white
let mesh: MeshResource = .generatePlane(width: 0.45, depth: 0.45)
let component = ModelComponent(mesh: mesh, materials: [material])
scene.myFavoriteScene?.children[0].components.set(component)
arView.scene.anchors.append(scene)
CGImage
Nonetheless, you can create a texture resource from an in-memory Core Graphics image:
static func generate(from: CGImage,
withName: String?,
options: TextureResource.CreateOptions) -> TextureResource
Also, you can use a URL parameter:
material.color.texture = .init(try! .load(contentsOf: url)) // RealityKit 2.0
Related Topics
Unnotificationattachment with Uiimage or Remote Url
Swiftui Drag Gesture Across Multiple Subviews
Unarchive Array with Nskeyedunarchiver Unarchivedobject(Ofclass:From:)
Detect App Launch from Widgetkit Widget Extension
Marking Some Xib/Storyboard Strings as Not Localizable
iOS 7 - Restrict Landscape Orientation Only in One View Controller
Returning Object from Callback in Swift
Jerky Scrolling After Updating Uitableviewcell in Place with Uitableviewautomaticdimension
How to Send Email Using Mfmailcomposeviewcontroller in Simulator
How to Decode Aac Audio Buffer to Pcm Buffer in iOS
How to Add an Identifier to Auto Layout Constraints in Interface Builder
Invalid Signature (Invalid Binary) on Itunes Connect
Is There a Simple Way to Edit/Modify a Uilocalnotification
Applicationwillterminate: Not Being Called
iOS Swift Navigate to Certain Viewcontroller Programmatically from Push Notification