I want to make a 3D metal compass in iOS which will have a movable cover.
That is when you touch it by 3 fingers and try to move your fingers upward the cover keeps moving with your fingers and after certain distance it gets opened.Once you pull it down using 3 fingers again, it gets closed. I have attached a sketch about what I'm thinking.
Is it possible using core animations and CALayers? Or would I have to use OpenGL ES?
First you should obviously create a textured 3d model in app like 3Ds Max or Maya. Then export it to some suitable format. The simplest one is OBJ (there are lots of examples about how to load it). There are two options about animation:
Do animation manually by rotating the cover object. It's probably the easiest way to do that.
Create animation in you 3D editor and then interpolate between frames. By doing this you can get much more realistic view. However in this case OBJ format is not suitable, but COLLADA is. To load it I suggest to use Assimp library.
And if you don't need some advanced interraction another option is to use pseude 3D: just pre render all the compass animation frames and use that animation applied to 2d texture.
Related
I am attempting to experiment with Apple’s Fox game SceneKit example (link below) by adding a model with a simple animation like the ‘panda.scn’ and ‘walk.scn’ assets.
I can create a static model with no joints or animation that works: e.g. In Maya (2017) I add a simple sphere, export selection to FBX_DAE (COLLADA) file, drag it into the project in XCode and convert it to a SCN file. I can then drag that model into the ‘level.scn’, position and scale it as I’d expect.
However as soon as I add any animation or joints to my model I lose the ability to position and scale the model in XCode.
In Maya I add two joints to my sphere select the sphere and joints and export as above. When I examine the model SCN in XCode (either in isolation or as a reference within another scene) I find that I cannot apply any translation or scaling. XCode lets me move the xyz locators in the GUI and update scale but the model does not change. I can see the mesh and joints in the outline view and I have tried moving the joints instead of the mesh, but they do nothing. I have even tried ignoring the GUI and positioning the model in code just as the panda character is set up, but applying positions or transforms to the node does nothing - it always appears at the origin and default scale.
Ignoring that for the moment, my understanding from looking at the ‘walk.scn’ file is that an animation is just an export of the joints with keyframes. I have tried to reproduce that by exporting only the joints to a separate DAE and importing it, then applying that in code as they do with the ‘walkAnimation’. This seems to do nothing as well.
I have experimented with various settings of the FBX_DAE export dialog including baking animations (By the way - what is the difference between baking an animation on export vs baking it in Maya before export? The former seems to do something and the other does nothing in my tests.)
I would dearly love a workflow for creating some simple character animations in Maya and getting them into SceneKit. Any help is greatly appreciated.
For reference:
Apple’s source: https://developer.apple.com/library/content/samplecode/Fox/Introduction/Intro.html
Maya scene for my trivial ball model with two joints:
http://pat.net/misc/ball1.mb
and the DAE output from Maya for that:
http://pat.net/misc/ball1.dae
UPDATE:
Mnuages's answer appears to be correct in that when I added a parent control over the geometry and joints SceneKit then allowed me to move them. But even after brushing up on my understanding of how these nodes and their transforms relate in Maya I do not feel that I have a real understanding of how SceneKit is interpreting them. (Would love to read some docs on that would illuminate this more if they exist).
UPDATE #2:
I was finally able to create an animation by doing the following: 1) Export either the full scene or just the joint with the animation being sure to select the "bake animation" option in the DAE export dialog or bake the entire animation using Key->Bake Animation. 2) It only works if I load the DAE file in scenekit instead of converting it to an SCN. Converting to SCN format seems to lose the animation.
what happens is that the node named joint1 is animated by the joint1-anim animation. So even if you move joint1 in the editor, what you see on screen is the result after the animation is evaluated.
If you create an intermediate node, say joint1-parent, and make joint1 as child node of joint1-parent, then you'll be able to translate and rotate joint1-parent freely and see the effects on joint1.
As for why moving pSphere does not change anything, it's the same idea. Just like the animation overrides the position, the skeleton will reposition the mesh.
I need to be able to interact with a representation of a cilinder that has many different parts in it. When the users taps over on of the small rectangles, I need to display a popover related to the specific piece (form).
The next image demonstrates a realistic 3d approach. But, I repeat, I need to solve the problem, the 3d is NOT required (would be really cool though). A representation that complies the functional needs will suffice.
The info about the parts to make the drawing comes from an API (size, position, etc)
I dont need it to be realistic really. The simplest aproximation would be to show a cilinder in a 2d representation, like a rectangle made out of interactable small rectangles.
So, as I mentioned, I think there are (as I see it) two opposite approaches: Realistic or Simplified
Is there a way to achieve a nice solution in the middle? What libraries, components, frameworks that I should look into?
My research has led me to SceneKit, but I still dont know if I will be able to interact with it. Interaction is a very important part as I need to display a popover when the user taps on any small rectangle over the cylinder.
Thanks
You don't need any special frameworks to achieve an interaction like this. This effect can be achieved with standard UIKit and UIView and a little trigonometry. You can actually draw exactly your example image using 2D math and drawing. My answer is not an exact formula but involves thinking about how the shapes are defined and break the problem down into manageable steps.
A cylinder can be defined by two offset circles representing the end pieces, connected at their radii. I will use an orthographic projection meaning the cylinder doesn't appear smaller as the depth extends into the background (but you could adapt to perspective if needed). You could draw this with CoreGraphics in a UIView drawRect.
A square slice represents an angle piece of the circle, offset by an amount smaller than the length of the cylinder, but in the same direction, as in the following diagram (sorry for imprecise drawing).
This square slice you are interested in is the area outlined in solid red, outside the radius of the first circle, and inside the radius of the imaginary second circle (which is just offset from the first circle by whatever length you want the slice).
To draw this area you simply need to draw a path of the outline of each arc and connect the endpoints.
To check if a touch is inside one of these square slices:
Check if the touch point is between angle a from the origin at a.
Check if the touch point is outside the radius of the inside circle.
Check if the touch point is inside the radius of the outside circle. (Note what this means if the circles are more than a radius apart.)
To find a point to display the popover you could average the end points on the slice or find the middle angle between the two edges and offset by half the distance.
Theoretically, doing this in Scene Kit with either SpriteKit or UIKit Popovers is ideal.
However Scene Kit (and Sprite Kit) seem to be in a state of flux wherein nobody from Apple is communicating with users about the raft of issues folks are currently having with both. From relatively stable and performant Sprite Kit in iOS 8.4 to a lot of lost performance in iOS 9 seems common. Scene Kit simply doesn't seem finished, and the documentation and community are both nearly non-existent as a result.
That being said... the theory is this:
Material IDs are what's used in traditional 3D apps to define areas of an object that have different materials. Somehow these Material IDs are called "elements" in SceneKit. I haven't been able to find much more about this.
It should be possible to detect the "element" that's underneath a touch on an object, and respond accordingly. You should even be able to change the state/nature of the material on that element to indicate it's the currently selected.
When wanting a smooth, well rounded cylinder as per your example, start with a cylinder that's made of only enough segments to describe/define the material IDs you need for your "rectangular" sections to be touched.
Later you can add a smoothing operation to the cylinder to make it round, and all the extra smoothing geometry in each quadrant of unique material ID should be responsive, regardless of how you add this extra detail to smooth the presentation of the cylinder.
Idea for the "Simplified" version:
if this representation is okey, you can use a UICollectionView.
Each cell can have a defined size thanks to
collectionView:layout:sizeForItemAtIndexPath:
Then each cell of the collection could be a small rectangle representing a
touchable part of the cylinder.
and using
collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath
To get the touch.
This will help you to display the popover at the right place:
CGRect rect = [collectionView layoutAttributesForItemAtIndexPath:indexPath].frame;
Finally, you can choose the appropriate popover (if the app has to work on iPhone) here:
https://www.cocoacontrols.com/search?q=popover
Not perfect, but i think this is efficient!
Yes, SceneKit.
When user perform a touch event, that mean you knew the 2D coordinate on screen, so your only decision is to popover a view or not, even a 3D model is not exist.
First, we can logically split the requirement into two pieces, determine the touching segment, showing right "color" in each segment.
I think the use of 3D model is to determine which piece of data to show in your case if I don't get you wrong. In that case, the SCNView's hit test method will do most of work for you. What you should do is to perform a hit test, take out the hit node and the hit's local 3D coordinate of this node, you can then calculate which segment is hit by this touch and do the decision.
Now how to draw the surface of the cylinder would be the only left question, right? There are various ways to do, for example simply paint each image you need and programmatically and attach it to the cylinder's material or have your image files on disk and use as material for the cylinder ...
I think the problem would be basically solved.
I'm trying to recreate the barrel effect that can be seen on the camera mode picker below:
(source: androidnova.org)
Do I have to use OpenGL in order to achieve this effect? What is the best approach?
I found a great library on GitHub that can be used to achieve this effect (https://github.com/Ciechan/BCMeshTransformView), but unfortunately it doesn't support animation and is therefore not usable.
I bet Apple used CGMeshTransform. It's just like BCMeshTransform, except it is a private API and fully integrates with Core Graphics. BCMeshTransformView was born when a developer discovered this.
The only easy option I see is:
Use CALayer.transform, which is a CATransform3D. You can use this to simulate the barrel effect you want by adjusting the z position and y rotation of each item on the barrel. Also add a semitransparent dark gradient (CAGradientLayer) to the wheel to simulate the effect of choices getting darker towards the edges. This will be simple to do, but won't look as smooth and realistic as an actual 3D barrel. Maybe it will look good enough to create a convincing illusion though? (To enable 3D transforms, you need to enable depth by using view.layer.transform.m34 = 1/500.f or similar)
http://www.thinkandbuild.it/introduction-to-3d-drawing-in-core-animation-part-1/
The hardest option is using a custom OpenGL view that makes a barrel shape and applies your contents on top of it as a texture. I would expect that you run into most of the complexities behind creating BCMeshTransformView, and have difficulty supporting animations just like BCMeshTransformView did.
You may still be able to use BCMeshTransformView though. BCMeshTransformView is slow at processing content animations such as color changes, but is very fast at processing geometry changes. So you could use it to do a barrel effect, as long as you define the barrel effect entirely in terms of mesh geometry changes (instead of as content changes like using a scroll view or adjusting subview positions). You would need to do gesture handling + scrolling yourself instead of using UIScrollView though, which is tricky and tedious to get right.
Considering the options, I would want to fudge it by using 3D transforms, then move to other options only if I can't create a convincing illusion using 3D transforms.
I'm trying to build a native viewer for cubic panoramas. Here is a web version of what I would like to achieve: http://www.apple.com/html5/showcase/vr/
This type of projection works as follows: The panorama consists of 6 square images which are projected on the inner surface of a cube. The camera is positioned in the center of the cube.
Currently, I'm using 6 CALayers and arrange them in 3D space so that they form a cube. Rotating them works fine using CATransform3DMakeTranslation etc.
The problem is that CALayers are not transparent when seen from behind (they show the same image as the front side). This sucks, because the user can't see the projections inside the cube because the view is blocked by other layers of the cube.
Is there a solution for this problem? I could think of the following:
a.) Maybe there's a setting in Core Animation to make layers transparent when viewed from behind?
b.) Continuously track the current view direction and manually set the CALayers hidden which would block the view.
What would be the best solution to solve this?
You can simply try setting the doubleSided property to NO.
I've got some data that I would like to render on top of a MKMapView using OpenGL. Currently I can sort of achieve this by placing a transparent OpenGL layer on top of the MKMapView and drawing to it using OpenGL commands.
However, the problem becomes synching the drawing of the OpenGL layer with the drawing that MKMapView does. I can kind of get around this by drawing on touch events, this works well until you "flick" the map which causes a continuous series of draws for the animation that I don't detect.
Another idea was to use a MKOverlayView and hope that OpenGL drawing could be done with it. But I'm not sure how exactly to app
I would recommend evaluating BA3's "Altus" mapping engine. It is built entirely in OpenGL, so in the worst case you may simple render to the same context. However, it would probably be better if you could take advantage of their support for geo-located raster, vector and marker elements.
Full disclosure: I'm friends with the authors, but have no financial interest.