The accepted answer will not work, guaranteed. Following is how to flip an image that is assigned as the value of the [material].diffuse.contents property; it assumes that two cubes in the scene, side-by-side:
// Define the matrices that perform the two orientation variants
SCNMatrix4 flip_horizontal;
flip_horizontal = SCNMatrix4Translate(SCNMatrix4MakeScale(-1, 1, 1), 1, 0, 0);
SCNMatrix4 flip_vertical;
flip_vertical = SCNMatrix4Translate(SCNMatrix4MakeScale(1, -1, 1), 0, 1, 0);
// Create the material objects for each cube, and assign an image as the contents
self.source_material = [SCNMaterial material];
self.source_material.diffuse.contents = [UIImage imageNamed:@"towelface.png"];
self.mirror_material = [SCNMaterial material];
self.mirror_material.diffuse.contents = self.source_material.diffuse.contents;
Pick only one of the following sections (as defined by the comments):
// PortraitOpposingDown
[self.mirror_material.diffuse setContentsTransform:SCNMatrix4Mult(self.source_material.diffuse.contentsTransform, flip_vertical)];
[self.source_material.diffuse setContentsTransform:SCNMatrix4Mult(self.mirror_material.diffuse.contentsTransform, flip_horizontal)];
// PortraitFacingDown
[self.source_material.diffuse setContentsTransform:SCNMatrix4Mult(self.source_material.diffuse.contentsTransform, flip_vertical)];
[self.mirror_material.diffuse setContentsTransform:SCNMatrix4Mult(self.source_material.diffuse.contentsTransform, flip_horizontal)];
// PortraitOpposingUp
[self.source_material.diffuse setContentsTransform:SCNMatrix4Mult(self.source_material.diffuse.contentsTransform, flip_horizontal)];
// PortraitFacingUp
[self.mirror_material.diffuse setContentsTransform:SCNMatrix4Mult(self.source_material.diffuse.contentsTransform, flip_horizontal)];
Insert the material at the desired index:
[cube[0] insertMaterial:self.source_material atIndex:0];
[cube[1] insertMaterial:self.mirror_material atIndex:0];
By the way, to insert a new image (such as for live video), simply replace the material at the index specified by the insertMaterial:atIndex
method; do not reorient the contentsTransform
. The following code shows you how; it assumes that your video camera is configured to output a sample buffer for each frame it captures to an AVCaptureVideoDataOutputSampleBufferDelegate
, and the requisite code (CreateCGImageFromCVPixelBuffer
) to create a CGImage
from a CVPixelBuffer
:
- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CGImageRef cgImage;
CreateCGImageFromCVPixelBuffer(pixelBuffer, &cgImage);
UIImage *image = [UIImage imageWithCGImage:cgImage];
dispatch_async(dispatch_get_main_queue(), ^{
self.source_material.diffuse.contents = image;
[cube[0] replaceMaterialAtIndex:0 withMaterial:self.source_material];
self.mirror_material.diffuse.contents = self.source_material.diffuse.contents;
[cube[1] replaceMaterialAtIndex:0 withMaterial:self.mirror_material];
});
CGImageRelease(cgImage);
}
If you'd like actual code instead of my assumptions of code on your end, please ask. Here's a short video showing this code in action, but with live video instead of a static image.