Why does SpriteKit use floats for position even though there can't be a decimal point in pixels?
I am building a game in SpriteKit and am wondering whether I should make the character position in ints to optimize it but am not sure whether there will be any performance improvements.
Is it worth converting the character positions to ints to optimize?
In general, it's simpler to use floats than integers when dealing with graphics above the bit-twiddling level. Note that Core Graphics also uses floats for coordinates.
The reason it's simpler is that you want to do things like scale (by a non-integer factor) and rotate coordinates, images, paths, etc. If you use integers, the rounding errors accumulate by a noticeable amount quickly. If you use floats, the rounding errors take much longer to become noticeable - usually they don't become noticeable at all.
Also consider that an SKNode has xScale and yScale properties. If you scale up a node, the fractional part of its children's positions can have a large effect on their positions on the screen.
You should not convert your character positions to ints. SpriteKit uses floats, so you'll end up converting them back to floats to use them with SpriteKit, the CPU has floating point support, and the GPU is designed to perform massive amounts of floating point arithmetic.
The other answers are good, but keep in mind that you are NOT working in pixels: you are working in points. Depending on the device, points will hold more or less pixels. The reason behind that was to accommodate the retina displays that had the save physical size. You work with points, and when you add pixels, everything still lines up because the number of pixels per point increased, but the number of points in the screen stayed the same.
SpriteKit uses floats because floats are not that huge, and numbers you will be using will not be as huge either since the max size for the iPad in itself is 2048 by 1536, there is no need to declare them as integers when floats work just fine for those sizes.
There is no use converting to integers. I've made a game in SpriteKit and it works just fine using CGFloats.
If you convert to integers, do note that almost anything dealing with a sprite's image or object's size will be in floats.
Related
Surprisingly I couldn't find any meaty info about this, so here I am.
I understand that 1 unit in the editor = 1 meter, but does large worlds affect performance? I mean, they obviously do in sandbox games and other games packed with content. But what if it's mostly empty? My current project is a 2D Gravity Wars clone game with moving planets. Should I make it as small and condensed as possible, or is there room to scale things up?
Basically, do large distances in a mostly empty world affect in-game performance?
Simple answer ... No.
The only thing you lose with big numbers when we are talking about float based vectors is precision.
So the real question becomes ... how accurate do you want your logic to be?
I tend to build stuff placing verts on round value points then scale for size rather than space vertex info at scaled points ... if that makes sense / helps?
In my application, I render plane over plane. Lower plane has Z = 0, second one has Z = 0.5. If I render them (lower first), I got missing part of render, as shown on picture
On iPhone 4 and desktop (using ES emulator), there is everything correct and no problem. What could cause this bevaiour ?
Same problem occurs also for other parts of scene, like tracks, tubes (green and blue on this picture). Problem occurs, when I move camera
Ok... I have solved this. There was problem in my shader that caused depth buffer to be filled incorectly.
I have used
precision mediump float;
and that caused geometry to be not precise and Z = 0 vs Z = 0.5 has been mixed together.
Changing precision to highp solved the issue.
Bottom line. This "optimalization" was huge mistake and never use mediump in Vertex Shader (unless you are facing some performance impact and even that its not worth it. The difference in rendering is not noticable)
(This is in response to your own answer, which is only partially correct)
You've got a case of Z-fighting going on, due to the mapping of your scene's Z values, to the z-buffer. This may be a non-linear mapping (1/f(Z) is common), but I'm not sure on floating point z-buffers.
Your scene is really simple, and while chunking more z-buffer range at the problem is a partial solution, it's at the cost of performance, and not really understanding the issue. You may well run into this same problem again even with the highest possible precision z-buffer you can use on your platform!
Look at your scenes; you want to map the z-range in the 3D scene, to the maximum possible range of values the z-buffer can store, else you're wasting chunks of the range of numbers the z-buffer can store. Calculating this mapping per-frame can be useful, depending on what you want to do with the z-buffer later on.
Have a look here for some calculations. Note, that with a floating point z-buffer, you may well be worse off than with an integer one if you're chucking away a lot of small numbers - that's where the vast majority of possible storable values of a floating point number are!
Technically the x, y, width, and height represent a set of dimensions that relate to pixels. I
can't have 200.23422 pixels so why do they use floats instead of ints?
The reason for the floats are that modern CPUs and GPUs a are optimized to work with many floating point numbers in parallel. This is true for iOS as well as Mac.
With Quartz you don't address individual pixels, but everything you draw is always antialiased. When you have a coordinate 1.0, 1.0 then this actually adds color to the 2x2 pixels at the coordinate origin.
This is why you might get blurry lines if you draw at integer coordinates. On non-retina you habe to draw offset by 0.5. Technically you would need to offset by 0.25 to draw exact pixels on Retina displays. Though there it does not really matter that much because you don't really see it any more at that pixel size.
Long story short: you don't address pixels direcrly, but the Graphics engine maps between floating point coordinates and pixels for you.
Resolution independence.
You want to keep your mathematical representation of your UI as accurate as practicable, only translating to pixel int values when you actually need to draw to the output device (and even then, not really). That's so that you can apply any number of transformations to your views and still get an accurate result.
Moreover it is possible to render lines, for example, at half-pixel widths and even less with a visible result - the system uses intelligent antialiasing to display a fine line.
It's the same principle as vector drawing has been using for decades (Adobe's PostScript, SVG etc). In fact Quartz is based on PDF, which is the modern version of PostScript. NeXT used Display PostScript in it's time, and then it was considered pretty revolutionary.
The dimensions are actually points that on non-retina screens have a 1 to 1 relation to pixels, but for retina screens 1 point = 2 pixels. So on a retina screen you can actually increment by half a point.
Is it possible for the Unity TerrainData structure to take absolute elevations? I have a terrain generator that generates absolute elevations, but they are huge. The perlin octave with the highest amplitude is the one that decides what altitude the entire map is at, with an amplitude of 2500 and wavelength 10000. In order for my map to tile properly and transition between altitudes seamlessly, I need to be able to use this system of absolute altitude. I would scale down my generator's output to fit in the limited space (between 0 and 1), and stretch the y scale of the TerrainData, but it will lose too much precision.
What can I do? Is there a way I can use elevations that may vary by as much as 2500 meters?
One thing that might be important is that there will never be that much variation in the space of a single Terrain object, but across many, many Terrain objects, it is possible for the player to traverse that kind of altitude.
I've tested changing different variables, and I've reached the following conclusion...
Heightmap Resolution does not mean precision of data (some people I asked believed it determined the number of possible height values). It means the number of samples per row and column. This, along with size determines how far apart samples are, and effectively how large the polygons of the terrain are. It's my impression that there is no way to improve precision, although I now know how to increase the height of the terrain object. Instead, since I will never have 2500 meters of elevation difference in the same terrain object, each piece of terrain generated by my generator I will put in a terrain object that is positioned and sized to contain all of the data in that square. The data will also have to be converted so that it will fit, but other than that, I see no drawbacks to this method.
Important note: Resolution must be 2^n + 1 where n is any number. If you provide a different value for resolution, the next permitted value down will be selected (always the one below your choice).
I'm working on an iPhone App that relies heavily on OpenGL. Right now it runs a bit slow on the iPhone 3G, but looks snappy on the new 32G iPod Touch. I assume this is hardware related. Anyway, I want to get the iPhone performance to resemble the iPod Touch performance. I believe I'm doing a lot of things sub-optimally in OpenGL and I'd like advice on what improvements will give me the most bang for the buck.
My scene rendering goes something like this:
Repeat 35 times
glPushMatrix
glLoadIdentity
glTranslate
Repeat 7 times
glBindTexture
glVertexPointer
glNormalPointer
glTexCoordPointer
glDrawArrays(GL_TRIANGLES, ...)
glPopMatrix
My Vertex, Normal and Texture Coords are already interleaved.
So, what steps should I take to speed this up? What step would you try first?
My first thought is to eliminate all those glBindTexture() calls by using a Texture Atlas.
What about some more efficient matrix operations? I understand the gl*() versions aren't too efficient.
What about VBOs?
Update
There are 8260 triangles.
Texture sizes are 64x64 pngs. There are 58 different textures.
I have not run instruments.
Update 2
After running the OpenGL ES Instrument on the iPhone 3G I found that my Tiler Utilization is in the 90-100% range, and my Render Utilization is in the 30% range.
Update 3
Texture Atlasing had no noticeable affect on the problem. Utilization ranges are still as noted above.
Update 4
Converting my Vertex and Normal pointers to GL_SHORT seemed to improve FPS, but the Tiler Utilization is still in the 90% range a lot of the time. I'm still using GL_FLOAT for my texture coordinates. I suppose I could knock those down to GL_SHORT and save four more bytes per vertex.
Update 5
Converting my texture coordinates to GL_SHORT yielded another performance increase. I'm now consistently getting >30 FPS. Tiler Utilization is still around 90%, but frequently drops down in the the 70-80% range. The Renderer Utilization is hovering around 50%. I suppose this might have something to do with scaling the texture coordinates from GL_TEXTURE Matrix Mode.
I'm still seeking additional improvements. I'd like to get closer to 40 FPS, as that's what my iPod Touch gets and it's silky smooth there. If anyone is still paying attention, what other low-hanging fruit can I pick?
With a tiler utilization still above 90%, you’re likely still vertex throughput-bound. Your renderer utilization is higher because the GPU is rendering more frames. If your primary focus is improving performance on older devices, then the key is still to cut down on the amount of vertex data needed per triangle. There are two sides to this:
Reducing the amount of data per vertex: Now that all of your vertex attributes are already GL_SHORTs, the next thing to pursue is finding a way to do what you want using fewer attributes or components. For example, if you can live without specular highlights, using DOT3 lighting instead of OpenGL ES fixed-function lighting would replace your 3 shorts (+ 1 short of padding) for normals with 2 shorts for an extra texture coordinate. As an additional bonus, you’d be able to light your models per-pixel.
Reducing the number of vertices needed per triangle: When drawing with indexed triangles, you should make sure that your indices are sorted for maximum reuse. Running your geometry through Imagination Technologies’ PVRTTriStrip tool would probably be your best bet here.
If you only have 58 different 64x64 textures, a texture atlas seems like a good idea, since they'd all fit in a single 512x512 texture... if you don't rely on texture wrap modes, I'd certainly at least try this.
What format are your textures in? You might try using a compressed PVRTC texture; I think that's less load on the Tiler, and I've been pleasantly surprised by the image quality even for 2-bit-per-pixel textures. (Good for natural images, not good if you're doing something that looks like an 8-bit video game)
The first thing I would do is run Instruments profiling on the hardware device that is slow. It should show you pretty quickly where the bottlenecks are for your particular case.
Update after instruments results:
This question has a similar result in Instruments to you, perhaps the advice is also applicable in your case (basically reducing number vertex data)
The biggest win in graphics programming comes down to this:
Batch, Batch, Batch
TextureAtlasing will make a bigger difference than most anything else you can do. Switching textures is like stopping a speeding train to let on new passengers every time.
Combine all those textures into an atlas and cut your draw calls down a lot.
This web-based tool may be helpful: http://zwoptex.zwopple.com/
Have you looked over the "OpenGL ES Programming Guide for iPhone OS" in the dev center? There are sections on Best Practices for Vertex Data and Texture Data.
Is your data formatted to be able to use triangle strips?
In terms of least effort, the modification sequence for you would probably be:
Reducing vertex attribute size
VBOs
Note that when you do these, you need to make sure that components are aligned on their native alignment, i.e. the floats or full ints are on 4-byte boundaries, the shorts are on 2-byte boundaries. If you don't do this it will tank your performance. It might be helpful to mentally map it by typing out your attribute ordering as a struct definition so you can sanity check your layout and alignment.
making sure your data is stripped to share vertices
using a texture atlas to reduce texture swaps
To try converting your textures to 16-bit RGB565 format, see this code in Apple's venerable Texture2D.m, search for kTexture2DPixelFormat_RGB565
http://code.google.com/p/cocos2d-iphone/source/browse/branches/branch-0.1/OpenGLSupport/Texture2D.m
(this code loads PNGs and converts them to RGB565 at texture creation time; I don't know if there's an RGB565 file format as such)
For more information on PVRTC compressed textures (which looked way better than I expected when I used them, even at 2 bits per pixel) see Apple's PVRTextureLoader sample:
http://developer.apple.com/iPhone/library/samplecode/PVRTextureLoader/index.html
it has both the code for loading PVRTC textures in your app and also instructions for using the texturetool to convert your .png files into .pvr files.