Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Pixel perfect 2d in 4.3?

Discussion in '2D' started by DarkMarmot, Nov 13, 2013.

  1. DarkMarmot

    DarkMarmot

    Joined:
    Nov 13, 2013
    Posts:
    22
    Just wondering if there are any guidelines for making pixel perfect retro 2d games in the new unity 4.3?
    E.g, scaling/cropping and aligning a small 'screen' to fit a designated resolution without any blurring or artifacts?

    Thanks,
    Scott
     
  2. MagicFred

    MagicFred

    Joined:
    May 29, 2013
    Posts:
    2
    I have the same question: How to configure the main camera to have 1 pixel = 1 Unite?
    It will be very helpfull to have "clean" X/Y positions like 118 pixels or unite instead of 5.9885631...

    Thank you very much! :)
     
    Last edited: Nov 13, 2013
  3. hellobard

    hellobard

    Joined:
    Sep 26, 2012
    Posts:
    140
    Bump on this! I am also wondering how to set up pixel perfection across all mobile devices. Should one import Retina iPad sized sprites and then have Unity somehow scale them down? Or is there / will there be an atlas-switching setup like in NGUI/2d toolkit?
     
  4. fredstales

    fredstales

    Joined:
    Jun 4, 2013
    Posts:
    36
    Yeah I wonder this to, if there are any nice tools now in Unity to handle this.
     
  5. Loius

    Loius

    Joined:
    Aug 16, 2012
    Posts:
    546
    It's all math. Which I suck at, but I can try for ya.

    Sprites have a resolution in their import settings - it defaults to 100 pixels per unit.

    You know how high your screen is (Screen.Height), and an ortho camera's "size" indicates how tall of an area it displays.

    So in the game's startup somewhere, you need to do something similar to this:

    float UnitsPerPixel = 1f / 100f;
    float PixelsPerUnit = 100f / 1f; // yeah, yeah, 100
    Camera.main.orthographicSize =
    Screen.height / 2f // ortho-size is half the screen height...
    * UnitsPerPixel;

    So if you have a 640x480 resolution, you'll end up with an ortho size of 2.4 (that's half of 480, divided by 100)
     
    Last edited: Nov 13, 2013
  6. MagicFred

    MagicFred

    Joined:
    May 29, 2013
    Posts:
    2
    Yeah, it looks good for me: 640x960, main camera ortho size 4.8
    Thank you :)
     
  7. Nachtmahr

    Nachtmahr

    Joined:
    Apr 4, 2013
    Posts:
    1
    Not working like expected. I get one Pixel offset (tripple checked everything).

    However if I move the Camera Y around 0.0001 the offset fits again. The Texture then offsets again at 0.5f, 0.25f, 0.125f... you see the Pattern =)

    Has someone a solution without Offsetting my Camera on certain numbers?

    Edit: On the Default Sprite Material there is a Option called Pixel Snap that solved my issue. But it still appears in uneven hight resolutions like 481. In case someone want to take a look at the built-in shader you can Download them here: http://unity3d.com/unity/download/archive/

    $pixel_offset.png
     
    Last edited: Nov 14, 2013
  8. DarkMarmot

    DarkMarmot

    Joined:
    Nov 13, 2013
    Posts:
    22
    Thanks for the feedback!

    I'm working on a retro title and wanted to scale and center pixel perfect art for multiple devices.

    The following code assumes you have a max vertical art size you can set and a background that can bleed off the edges,
    art with filter mode 'point' and units to pixels = 1.

    It scales the art at some integer multiple to maintain pixel fidelity

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class ConfigCamera : MonoBehaviour {
    6.    
    7.     public float maxPixelHeight = 214f;
    8.  
    9.     void Awake () {
    10.         float scale = Mathf.Ceil(Screen.height / maxPixelHeight);
    11.         Camera.main.orthographicSize = Screen.height / 2f / scale;
    12.     }
    13.  
    14. }
    15.  
    I don't know if it needs any slight offsets or how to modify the pixel snap in the default shader...
    and if anyone has done any work on writing 'anchor' scripts to place ui elements as in some of the other 2d packages that would be pretty slick.

    Thanks,
    Scott
     
    kylexuanle likes this.
  9. matbrummitt

    matbrummitt

    Joined:
    Jan 12, 2010
    Posts:
    107
    I'm really struggling with this also.

    In Photoshop i've designed my level in a document size based on iPad Retina (2048x1536). I've imported some of my sprites into Unity and they take up a much bigger proportion of the camera's viewable area, than they do within photoshop.

    For example, one of my level props takes up approximately 17% of the document window in photoshop. With my game view set to the same dimensions as photoshop, the imported sprite takes up approximately 38% of the screen space. I've no idea how to get around this, and the code listed above does not seem to be working for me.

    EDIT: I have attached a crude example image, which hopefully demonstrates my issue. It shows the space one of my props takes up in photoshop, and then in Unity.

    EDIT2: I tried doubling the orthographic size, so my InitCamera class does the following:
    amera.main.orthographicSize = (Screen.height / 2) / _pixelsToUnits * _mod; // mod is set to 2.

    The above now resembles photoshop. However, i'm now unclear as to what happens when someone is playing on a non-retina iPad. If I change _mod to equal 1, the camera's viewable area is halved, and my prop bottom-right is not on screen anymore. This must be a common problem. Can anyone recommend a solution?

    Thanks for your help

    Mat
     

    Attached Files:

    Last edited: Nov 23, 2013
  10. DylanWilson

    DylanWilson

    Joined:
    Dec 5, 2013
    Posts:
    1
    Bump! I am also facing the same issue. Are there any good solutions?
     
  11. Saxi

    Saxi

    Joined:
    Jun 28, 2013
    Posts:
    381
    Really wish I could find a good tutorial on this, this is driving me nuts coming from other SDK. Everyone I talk to just gives me a generic answer "unity doesn't have default resolution and it will handle it automatically" but it does.
     
  12. Saxi

    Saxi

    Joined:
    Jun 28, 2013
    Posts:
    381
    I read PC you may need to offset by .5px but osx you don't. I assume mobile you don't either but not 100% sure. Still trying to figure this out.
     
  13. Vanz

    Vanz

    Joined:
    Nov 19, 2013
    Posts:
    374
    Unity developers could you please clarify this and maybe make a short tutorial as it appears quite a few of your users are struggling with this same topic...

    Thanks,

    Vanz
     
  14. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,539
    The only problem with that though, is I think you will loose the built-in draw-call batching of the current system by using multiple Sprite Materials for each texture. This greatly reduces performance, since the game needs to do a Draw Call for each material. The way the new integrated Sprite material works, is that it uses that single material for every texture you've set to Sprite. Meaning only 1 draw call is used for all your textures. The PixelSnap is a PRO feature, sadly =/

    And it may disable some of the other performance enhancements as well, like the automatic atlas creation.

    They go through some of the performance enhancements here:
     
    Last edited: Dec 15, 2013
  15. Amon

    Amon

    Joined:
    Oct 18, 2009
    Posts:
    1,384
    When using the monkey Language there is an import I use called Autofit. It was programmed for the monkey language by DruggedBunny a.k.a James L Boyd. He made it available to everyone and released it to the Public Domain.

    This code has never failed me when using Monkey for a 2d game. It is capable of zooming, autoscaling to fit device res with or without borders and has virtual controls that also work flawlessly on any res.

    The code is pasted below but I have also attached the monkey file.

    What brave soul is going to convert it to work with unity? :)

    Code (csharp):
    1.  
    2.  
    3.  
    4. Strict
    5.  
    6.  
    7. ' -----------------------------------------------------------------------------
    8. ' AutoFit - Virtual Display System... [Public domain code]
    9. ' -----------------------------------------------------------------------------
    10.  
    11.  
    12. ' Couldn't think of a better name!
    13.  
    14.  
    15. Import mojo.app
    16. Import mojo.graphics
    17. Import mojo.input
    18.  
    19.  
    20. ' Changes - made Strict and added VTouchX/Y.
    21.  
    22.  
    23. ' Changes - moved LOADS of locals in UpdateVirtualDisplay into fields
    24. ' and now perform very few checks/calculations on each call (most are
    25. ' only done when the device size or zoom level is changed).
    26.  
    27.  
    28.  
    29.  
    30.  
    31.  
    32.  
    33.  
    34. ' -----------------------------------------------------------------------------
    35. ' Usage. For details see function definitions...
    36. ' -----------------------------------------------------------------------------
    37.  
    38.  
    39.  
    40.  
    41.  
    42.  
    43.  
    44.  
    45.  
    46.  
    47. ' -----------------------------------------------------------------------------
    48. ' SetVirtualDisplay
    49. ' -----------------------------------------------------------------------------
    50.  
    51.  
    52. ' Call during OnCreate, passing intended width and height of game area. Design
    53. ' your game for this fixed display size and it will be scaled correctly on any
    54. ' device. You can pass no parameters for default 640 x 480 virtual device size.
    55.  
    56.  
    57. ' Optional zoom parameter default to 1.0.
    58.  
    59.  
    60. ' -----------------------------------------------------------------------------
    61. ' UpdateVirtualDisplay
    62. ' -----------------------------------------------------------------------------
    63.  
    64.  
    65. ' Call at start of OnRender, BEFORE ANYTHING ELSE, including Cls!
    66.  
    67.  
    68. ' -----------------------------------------------------------------------------
    69. ' VMouseX ()/VMouseY ()
    70. ' -----------------------------------------------------------------------------
    71.  
    72.  
    73. ' Call during OnUpdate (or OnRender) to get correctly translated MouseX ()/MouseY ()
    74. ' positions. By default, the results are bound to the display area within the
    75. ' borders. You can override this by passing False as an optional parameter,
    76. ' and the functions will then return values outside of the borders.
    77.  
    78.  
    79. ' -----------------------------------------------------------------------------
    80. ' VTouchX ()/VTouchY ()
    81. ' -----------------------------------------------------------------------------
    82.  
    83.  
    84. ' Call during OnUpdate (or OnRender) to get correctly translated TouchX ()/TouchY ()
    85. ' positions. By default, the results are bound to the display area within the
    86. ' borders. You can override this by passing False as an optional parameter,
    87. ' and the functions will then return values outside of the borders.
    88.  
    89.  
    90. ' -----------------------------------------------------------------------------
    91. ' VDeviceWidth ()/VDeviceHeight ()
    92. ' -----------------------------------------------------------------------------
    93.  
    94.  
    95. ' Call during OnUpdate (or OnRender) for the virtual device width/height. These
    96. ' are just the values you passed to SetVirtualDisplay.
    97.  
    98.  
    99. ' -----------------------------------------------------------------------------
    100. ' SetVirtualZoom
    101. ' -----------------------------------------------------------------------------
    102.  
    103.  
    104. ' Call in OnUpdate to set zoom level.
    105.  
    106.  
    107. ' -----------------------------------------------------------------------------
    108. ' AdjustVirtualZoom
    109. ' -----------------------------------------------------------------------------
    110.  
    111.  
    112. ' Call in OnUpdate to zoom in/out by given amount.
    113.  
    114.  
    115. ' -----------------------------------------------------------------------------
    116. ' GetVirtualZoom
    117. ' -----------------------------------------------------------------------------
    118.  
    119.  
    120. ' Call in OnUpdate or OnRender to retrieve current zoom level.
    121.  
    122.  
    123.  
    124.  
    125.  
    126.  
    127.  
    128.  
    129.  
    130.  
    131.  
    132.  
    133. ' -----------------------------------------------------------------------------
    134. ' Function definitions and parameters...
    135. ' -----------------------------------------------------------------------------
    136.  
    137.  
    138.  
    139.  
    140.  
    141.  
    142.  
    143.  
    144.  
    145.  
    146. ' -----------------------------------------------------------------------------
    147. ' SetVirtualDisplay: Call in OnCreate...
    148. ' -----------------------------------------------------------------------------
    149.  
    150.  
    151. ' Parameters: width and height of virtual game area, optional zoom...
    152.  
    153.  
    154. Function SetVirtualDisplay:Int (width:Int = 640, height:Int = 480, zoom:Float = 1.0)
    155.     New VirtualDisplay (width, height, zoom)
    156.     Return 0
    157. End
    158.  
    159.  
    160. ' -----------------------------------------------------------------------------
    161. ' SetVirtualZoom: Call in OnUpdate...
    162. ' -----------------------------------------------------------------------------
    163.  
    164.  
    165. ' Parameters: zoom level (1.0 being normal)...
    166.  
    167.  
    168. Function SetVirtualZoom:Int (zoom:Float)
    169.     VirtualDisplay.Display.SetZoom zoom
    170.     Return 0
    171. End
    172.  
    173.  
    174. ' -----------------------------------------------------------------------------
    175. ' AdjustVirtualZoom: Call in OnUpdate...
    176. ' -----------------------------------------------------------------------------
    177.  
    178.  
    179. ' Parameters: amount by which to change current zoom level. Positive values
    180. ' zoom in, negative values zoom out...
    181.  
    182.  
    183. Function AdjustVirtualZoom:Int (amount:Float)
    184.     VirtualDisplay.Display.AdjustZoom amount
    185.     Return 0
    186. End
    187.  
    188.  
    189. ' -----------------------------------------------------------------------------
    190. ' GetVirtualZoom: Call in OnUpdate or OnRender...
    191. ' -----------------------------------------------------------------------------
    192.  
    193.  
    194. ' Parameters: none...
    195.  
    196.  
    197. Function GetVirtualZoom:Float ()
    198.     Return VirtualDisplay.Display.GetZoom ()
    199. End
    200.  
    201.  
    202. ' -----------------------------------------------------------------------------
    203. ' UpdateVirtualDisplay: Call at start of OnRender...
    204. ' -----------------------------------------------------------------------------
    205.  
    206.  
    207. ' Parameters:
    208.  
    209.  
    210. ' Gah! Struggling to explain this! Just experiment!
    211.  
    212.  
    213. ' The 'zoomborders' parameter can be set to False to allow you to retain FIXED
    214. ' width/height borders for the current device size/ratio. Effectively, this
    215. ' means that as you zoom out, you can see more of the 'playfield' outside the
    216. ' virtual display, instead of having borders drawn to fill the outside area.
    217. ' See VMouseX ()/Y information for more details on how this can be used...
    218.  
    219.  
    220. ' The 'keepborders' parameter, if set to True, means the outer borders are
    221. ' kept no matter how ZOOMED IN the game is. Setting this to False means you
    222. ' can zoom into the game, the borders appearing to go 'outside' the screen
    223. ' as you zoom further in. You'll have to try it to get it, but it only
    224. ' affects zooming inwards.
    225.  
    226.  
    227. ' NB. *** TURNING 'keepborders' OFF ONLY TAKES EFFECT IF zoomborders IS
    228. ' SET TO TRUE! Borders will remain otherwise... ***
    229.  
    230.  
    231. Function UpdateVirtualDisplay:Int (zoomborders:Bool = True, keepborders:Bool = True)
    232.     VirtualDisplay.Display.UpdateVirtualDisplay zoomborders, keepborders
    233.     Return 0
    234. End
    235.  
    236.  
    237. ' -----------------------------------------------------------------------------
    238. ' Misc functions: Call in OnUpdate (optionally)...
    239. ' -----------------------------------------------------------------------------
    240.  
    241.  
    242. ' Mouse position within virtual display; the limit parameter allows you to only
    243. ' return values within the virtual display.
    244.  
    245.  
    246. ' Set the 'limit' parameter to False to allow returning of values outside
    247. ' the virtual display area. Combine this with ScaleVirtualDisplay's zoomborders
    248. ' parameter set to False if you want to be able to zoom way out and allow
    249. ' gameplay in the full zoomed-out area...
    250.  
    251.  
    252. Function VMouseX:Float (limit:Bool = True)
    253.     Return VirtualDisplay.Display.VMouseX (limit)
    254. End
    255.  
    256.  
    257. Function VMouseY:Float (limit:Bool = True)
    258.     Return VirtualDisplay.Display.VMouseY (limit)
    259. End
    260.  
    261.  
    262. Function VTouchX:Float (index:Int = 0, limit:Bool = True)
    263.     Return VirtualDisplay.Display.VTouchX (index, limit)
    264. End
    265.  
    266.  
    267. Function VTouchY:Float (index:Int = 0, limit:Bool = True)
    268.     Return VirtualDisplay.Display.VTouchY (index, limit)
    269. End
    270.  
    271.  
    272. ' Virtual display size...
    273.  
    274.  
    275. Function VDeviceWidth:Float ()
    276.     Return VirtualDisplay.Display.vwidth
    277. End
    278.  
    279.  
    280. Function VDeviceHeight:Float ()
    281.     Return VirtualDisplay.Display.vheight
    282. End
    283.  
    284.  
    285.  
    286.  
    287.  
    288.  
    289.  
    290.  
    291. Class VirtualDisplay
    292.  
    293.  
    294.     Global Display:VirtualDisplay
    295.    
    296.     Private
    297.    
    298.     Field vwidth:Float                  ' Virtual width
    299.     Field vheight:Float                 ' Virtual height
    300.  
    301.  
    302.     Field device_changed:Int                ' Device size changed
    303.     Field lastdevicewidth:Int               ' For device change detection
    304.     Field lastdeviceheight:Int              ' For device change detection
    305.    
    306.     Field vratio:Float                  ' Virtual ratio
    307.     Field dratio:Float                  ' Device ratio
    308.  
    309.  
    310.     Field scaledw:Float                 ' Width of *scaled* virtual display in real pixels
    311.     Field scaledh:Float                 ' Width of *scaled* virtual display in real pixels
    312.  
    313.  
    314.     Field widthborder:Float             ' Size of border at sides
    315.     Field heightborder:Float                ' Size of border at top/bottom
    316.  
    317.  
    318.     Field sx:Float                      ' Scissor area
    319.     Field sy:Float                      ' Scissor area
    320.     Field sw:Float                      ' Scissor area
    321.     Field sh:Float                      ' Scissor area
    322.  
    323.  
    324.     Field realx:Float                       ' Width of SCALED virtual display (real pixels)
    325.     Field realy:Float                       ' Height of SCALED virtual display (real pixels)
    326.  
    327.  
    328.     Field offx:Float                        ' Pixels between real borders and virtual borders
    329.     Field offy:Float                        ' Pixels between real borders and virtual borders
    330.  
    331.  
    332.     Field vxoff:Float                       ' Offsets by which view needs to be shifted
    333.     Field vyoff:Float                       ' Offsets by which view needs to be shifted
    334.  
    335.  
    336.     Field multi:Float                       ' Ratio scale factor
    337.     Field vzoom:Float                       ' Zoom scale factor
    338.     Field zoom_changed:Int                  ' Zoom changed
    339.     Field lastvzoom:Float                   ' Zoom change detection
    340.    
    341.     Field fdw:Float                     ' DeviceWidth () gets pre-cast to Float in UpdateVirtualDisplay
    342.     Field fdh:Float                     ' DeviceHeight () gets pre-cast to Float in UpdateVirtualDisplay
    343.    
    344.     Public
    345.    
    346.     Method New (width:Int, height:Int, zoom:Float)
    347.  
    348.  
    349.         ' Set virtual width and height...
    350.            
    351.         vwidth = width
    352.         vheight = height
    353.  
    354.  
    355.         vzoom = zoom
    356.         lastvzoom = vzoom + 1 ' Force zoom change detection! Best hack ever. (vzoom can be zero.)
    357.  
    358.  
    359.         ' Store ratio...
    360.        
    361.         vratio = vheight / vwidth
    362.  
    363.  
    364.         ' Create global VirtualDisplay object...
    365.        
    366.         Display = Self
    367.    
    368.     End
    369.  
    370.  
    371.     Method GetZoom:Float ()
    372.         Return vzoom
    373.     End
    374.    
    375.     Method SetZoom:Int (zoomlevel:Float)
    376.         If zoomlevel < 0.0 Then zoomlevel = 0.0
    377.         vzoom = zoomlevel
    378.         Return 0
    379.     End
    380.    
    381.     Method AdjustZoom:Int (amount:Float)
    382.         vzoom = vzoom + amount
    383.         If vzoom < 0.0 Then vzoom = 0.0
    384.         Return 0
    385.     End
    386.    
    387.     Method VMouseX:Float (limit:Bool)
    388.        
    389.         ' Position of mouse, in real pixels, from centre of screen (centre being 0)...
    390.        
    391.         Local mouseoffset:Float = MouseX () - Float (DeviceWidth ()) * 0.5
    392.        
    393.         ' This calculates the scaled position on the virtual display. Somehow...
    394.        
    395.         Local x:Float = (mouseoffset / multi) / vzoom + (VDeviceWidth () * 0.5)
    396.  
    397.  
    398.         ' Check if mouse is to be limited to virtual display area...
    399.        
    400.         If limit
    401.    
    402.             Local widthlimit:Float = vwidth - 1
    403.    
    404.             If x > 0
    405.                 If x < widthlimit
    406.                     Return x
    407.                 Else
    408.                     Return widthlimit
    409.                 Endif
    410.             Else
    411.                 Return 0
    412.             Endif
    413.    
    414.         Else
    415.             Return x
    416.         Endif
    417.    
    418.         Return 0
    419.        
    420.     End
    421.  
    422.  
    423.     Method VMouseY:Float (limit:Bool)
    424.    
    425.         ' Position of mouse, in real pixels, from centre of screen (centre being 0)...
    426.  
    427.  
    428.         Local mouseoffset:Float = MouseY () - Float (DeviceHeight ()) * 0.5
    429.        
    430.         ' This calculates the scaled position on the virtual display. Somehow...
    431.  
    432.  
    433.         Local y:Float = (mouseoffset / multi) / vzoom + (VDeviceHeight () * 0.5)
    434.        
    435.         ' Check if mouse is to be limited to virtual display area...
    436.  
    437.  
    438.         If limit
    439.        
    440.             Local heightlimit:Float = vheight - 1
    441.        
    442.             If y > 0
    443.                 If y < heightlimit
    444.                     Return y
    445.                 Else
    446.                     Return heightlimit
    447.                 Endif
    448.             Else
    449.                 Return 0
    450.             Endif
    451.  
    452.  
    453.         Else
    454.             Return y
    455.         Endif
    456.        
    457.         Return 0
    458.  
    459.  
    460.     End
    461.  
    462.  
    463.     Method VTouchX:Float (index:Int, limit:Bool)
    464.        
    465.         ' Position of touch, in real pixels, from centre of screen (centre being 0)...
    466.        
    467.         Local touchoffset:Float = TouchX (index) - Float (DeviceWidth ()) * 0.5
    468.        
    469.         ' This calculates the scaled position on the virtual display. Somehow...
    470.        
    471.         Local x:Float = (touchoffset / multi) / vzoom + (VDeviceWidth () * 0.5)
    472.  
    473.  
    474.         ' Check if touches are to be limited to virtual display area...
    475.        
    476.         If limit
    477.    
    478.             Local widthlimit:Float = vwidth - 1
    479.    
    480.             If x > 0
    481.                 If x < widthlimit
    482.                     Return x
    483.                 Else
    484.                     Return widthlimit
    485.                 Endif
    486.             Else
    487.                 Return 0
    488.             Endif
    489.    
    490.         Else
    491.             Return x
    492.         Endif
    493.    
    494.         Return 0
    495.        
    496.     End
    497.  
    498.  
    499.     Method VTouchY:Float (index:Int, limit:Bool)
    500.    
    501.         ' Position of touch, in real pixels, from centre of screen (centre being 0)...
    502.  
    503.  
    504.         Local touchoffset:Float = TouchY (index) - Float (DeviceHeight ()) * 0.5
    505.        
    506.         ' This calculates the scaled position on the virtual display. Somehow...
    507.  
    508.  
    509.         Local y:Float = (touchoffset / multi) / vzoom + (VDeviceHeight () * 0.5)
    510.        
    511.         ' Check if touches are to be limited to virtual display area...
    512.  
    513.  
    514.         If limit
    515.        
    516.             Local heightlimit:Float = vheight - 1
    517.        
    518.             If y > 0
    519.                 If y < heightlimit
    520.                     Return y
    521.                 Else
    522.                     Return heightlimit
    523.                 Endif
    524.             Else
    525.                 Return 0
    526.             Endif
    527.  
    528.  
    529.         Else
    530.             Return y
    531.         Endif
    532.        
    533.         Return 0
    534.  
    535.  
    536.     End
    537.  
    538.  
    539.     Method UpdateVirtualDisplay:Int (zoomborders:Bool, keepborders:Bool)
    540.  
    541.  
    542.         ' ---------------------------------------------------------------------
    543.         ' Calculate/draw borders, if any, scale, etc...
    544.         ' ---------------------------------------------------------------------
    545.  
    546.  
    547.         ' ---------------------------------------------------------------------
    548.         ' Check for 'real' device resolution change...
    549.         ' ---------------------------------------------------------------------
    550.  
    551.  
    552.         If (DeviceWidth () <> lastdevicewidth) Or (DeviceHeight () <> lastdeviceheight)
    553.             lastdevicewidth = DeviceWidth ()
    554.             lastdeviceheight = DeviceHeight ()
    555.             device_changed = True
    556.         Endif
    557.        
    558.         ' ---------------------------------------------------------------------
    559.         ' Force re-calc if so (same for first call)...
    560.         ' ---------------------------------------------------------------------
    561.  
    562.  
    563.         If device_changed
    564.  
    565.  
    566.             ' Store device resolution as float values to avoid loads of casts. Doing it here as
    567.             ' device resolution may potentially be changed on the fly on some platforms...
    568.            
    569.             fdw = Float (DeviceWidth ())
    570.             fdh = Float (DeviceHeight ())
    571.            
    572.             ' Device ratio is calculated on the fly since it can change (eg. resizeable
    573.             ' browser window)...
    574.            
    575.             dratio = fdh / fdw
    576.  
    577.  
    578.             ' Compare to pre-calculated virtual device ratio...
    579.    
    580.             If dratio > vratio
    581.    
    582.                 ' -----------------------------------------------------------------
    583.                 ' Device aspect narrower than (or same as) game aspect ratio:
    584.                 ' will use full width, borders above and below...
    585.                 ' -----------------------------------------------------------------
    586.    
    587.                 ' Multiplier required to scale game width to device width (to be applied to height)...
    588.                
    589.                 multi = fdw / vwidth
    590.                
    591.                 ' "vheight * multi" below applies width multiplier to height...
    592.                
    593.                 heightborder = (fdh - vheight * multi) * 0.5
    594.                 widthborder = 0
    595.                
    596.             Else
    597.    
    598.                 ' -----------------------------------------------------------------
    599.                 ' Device aspect wider than game aspect ratio:
    600.                 ' will use full height, borders at sides...
    601.                 ' -----------------------------------------------------------------
    602.                
    603.                 ' Multiplier required to scale game height to device height (to be applied to width)...
    604.                
    605.                 multi = fdh / vheight
    606.                
    607.                 ' "vwidth * multi" below applies height multiplier to width...
    608.    
    609.                 widthborder = (fdw - vwidth * multi) * 0.5
    610.                 heightborder = 0
    611.    
    612.             Endif
    613.  
    614.  
    615.         Endif
    616.  
    617.  
    618.         ' ---------------------------------------------------------------------
    619.         ' Check for zoom level change...
    620.         ' ---------------------------------------------------------------------
    621.  
    622.  
    623.         If vzoom <> lastvzoom
    624.             lastvzoom = vzoom
    625.             zoom_changed = True
    626.         Endif
    627.        
    628.         ' ---------------------------------------------------------------------
    629.         ' Re-calc if so (and on first call), or if device size changed...
    630.         ' ---------------------------------------------------------------------
    631.  
    632.  
    633.         If zoom_changed Or device_changed
    634.  
    635.  
    636.             If zoomborders
    637.    
    638.                 ' Width/height of SCALED virtual display in real pixels...
    639.                
    640.                 realx = vwidth * vzoom * multi
    641.                 realy = vheight * vzoom * multi
    642.        
    643.                 ' Space in pixels between real device borders and virtual device borders...
    644.                
    645.                 offx = (fdw - realx) * 0.5
    646.                 offy = (fdh - realy) * 0.5
    647.    
    648.                 If keepborders
    649.    
    650.                     ' -----------------------------------------------------
    651.                     ' Calculate inner area...
    652.                     ' -----------------------------------------------------
    653.  
    654.  
    655.                     If offx < widthborder
    656.                         sx = widthborder
    657.                         sw = fdw - widthborder * 2.0
    658.                     Else
    659.                         sx = offx
    660.                         sw = fdw - (offx * 2.0)
    661.                     Endif
    662.    
    663.                     If offy < heightborder
    664.                         sy = heightborder
    665.                         sh = fdh - heightborder * 2.0
    666.                     Else
    667.                         sy = offy
    668.                         sh = fdh - (offy * 2.0)
    669.                     Endif
    670.    
    671.                 Else
    672.    
    673.                     sx = offx
    674.                     sw = fdw - (offx * 2.0)
    675.    
    676.                     sy = offy
    677.                     sh = fdh - (offy * 2.0)
    678.    
    679.                 Endif
    680.  
    681.  
    682.                 ' Apply limits...
    683.                
    684.                 sx = Max (0.0, sx)
    685.                 sy = Max (0.0, sy)
    686.                 sw = Min (sw, fdw)
    687.                 sh = Min (sh, fdh)
    688.  
    689.  
    690.             Else
    691.  
    692.  
    693.                 ' Apply limits...
    694.  
    695.  
    696.                 sx = Max (0.0, widthborder)
    697.                 sy = Max (0.0, heightborder)
    698.                 sw = Min (fdw - widthborder * 2.0, fdw)
    699.                 sh = Min (fdh - heightborder * 2.0, fdh)
    700.            
    701.             Endif
    702.  
    703.  
    704.             ' Width and height of *scaled* virtual display in pixels...
    705.  
    706.  
    707.             scaledw = (vwidth * multi * vzoom)
    708.             scaledh = (vheight * multi * vzoom)
    709.  
    710.  
    711.             ' Find offsets by which view needs to be shifted...
    712.            
    713.             vxoff = (fdw - scaledw) * 0.5
    714.             vyoff = (fdh - scaledh) * 0.5
    715.  
    716.  
    717.             ' Ahh, good old trial and error -- I have no idea how this works!
    718.            
    719.             vxoff = (vxoff / multi) / vzoom
    720.             vyoff = (vyoff / multi) / vzoom
    721.        
    722.             ' Reset these...
    723.            
    724.             device_changed = False
    725.             zoom_changed = False
    726.            
    727.         Endif
    728.        
    729.         ' ---------------------------------------------------------------------
    730.         ' Draw borders at full device size...
    731.         ' ---------------------------------------------------------------------
    732.  
    733.  
    734.         SetScissor 0, 0, DeviceWidth (), DeviceHeight ()
    735.         Cls 0, 0, 0
    736.  
    737.  
    738.         ' ---------------------------------------------------------------------
    739.         ' Draw inner area...
    740.         ' ---------------------------------------------------------------------
    741.  
    742.  
    743.         SetScissor sx, sy, sw, sh
    744.            
    745.         ' ---------------------------------------------------------------------
    746.         ' Scale everything...
    747.         ' ---------------------------------------------------------------------
    748.        
    749.         Scale multi * vzoom, multi * vzoom
    750.  
    751.  
    752.         ' ---------------------------------------------------------------------
    753.         ' Shift display to account for borders/zoom level...
    754.         ' ---------------------------------------------------------------------
    755.  
    756.  
    757.         If vzoom Then Translate vxoff, vyoff
    758.        
    759.         Return 0
    760.        
    761.     End
    762.  
    763.  
    764. End
    765.  
    766.  
    767.  
     

    Attached Files:

  16. HubertGendron

    HubertGendron

    Joined:
    Feb 22, 2013
    Posts:
    9

    Nachtmahr solution works for me and from all the test that I've done, I was able to keep my batching and also able to use PixelSnap with Unity Free version. . :)

    So here's what have done.

    1 - Add a script to your camera to automatically set the othographic size to get 1:1 pixel.
    Code (csharp):
    1. public void Awake()
    2. {
    3.     //
    4.     camera.orthographicSize = (Screen.height / 100f / 2.0f); // 100f is the PixelPerUnit that you have set on your sprite. Default is 100.
    5. }
    2 - Create a new material, choose from the shader list the Sprites/Default shader and check the Pixel Snap option on your material.

    $MaterialSetup.png

    3 - From now you need to add this material on the SpriteRenderer component of each sprites in your game. (Adding this material on all your sprites will keep batching.)

    $SpriteRenderer.png

    And that's it.

    P.S. As Nachtmahr said it will not work with uneven screen height like 485. But I've found that sometimes, if you uncheck PixelSnap when the screen height is uneven it will work. I've tried to uncheck PixelSnap at runtime when the screen height is uneven, but unfortunately, it looks like PixelSnap does not update the shader at runtime. :(

    Hope it will helps ! :D
    Cheers.
     
    Olgo, coah, donderper and 1 other person like this.
  17. Trebor Zaid

    Trebor Zaid

    Joined:
    Nov 21, 2013
    Posts:
    5
    Awesome, that fixed my problem with my random tile map generator. I noticed that depending on the camera's position the UV coordinates would sometimes be one pixel off. I think perhaps there should be a special camera option for 2D games that would automatically enable pixel snap for all sprites. If done at the camera level it could also be designed in such a way that it would work for both even and odd screen resolutions.
     
  18. ham

    ham

    Joined:
    Aug 28, 2012
    Posts:
    2
  19. AllegroDigital

    AllegroDigital

    Joined:
    Jan 8, 2014
    Posts:
    4
    Does it make sense to use

    Code (csharp):
    1.     public void Awake()
    2.     {
    3.         //
    4.         camera.orthographicSize = (Screen.height / 100f / 2.0f); // 100f is the PixelPerUnit that you have set on your sprite. Default is 100.
    5.     }
    ?

    The reason I ask is that the Screen.height seems to pick up whatever your final resolution is when you build the game. So in the event that you're using something like 640x480 for all your graphics, and then the user sets their resolution to 1280x960, it ends up setting your camera to display more than you would have wanted once they run the game.


    I'm only a couple weeks into learning Unity, so I'm not sure what the ideal way would be to do this...
     
  20. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    This doesn't work. None of it works.

    It gets the correct size, such as turning a 40x40 square into a 40x40 pixels displayed. However, the pixels displayed are incorrect.

    This is what I call "Pixel Imperfect"

    Here is an image as to what I'm talking about:



    edit: this seems to be an issue with the image being 40x40 and not a Power of Two.

    edit: fixed this by using TexturePacker to pack all animations of a character into a POT image, while still keeping their 40x40 size. Alternatively, one could batch resize "Canvas Size" in Photoshop from NPOT (40x40) to POT (64x64) which would also resolve Unity's butchering of the image when it is NPOT.
     

    Attached Files:

    Last edited: Jan 17, 2014
  21. imaginaryhuman

    imaginaryhuman

    Joined:
    Mar 21, 2010
    Posts:
    5,834
    When you use a non-power-of-2 texture, as far as it looks on the surface Unity presents it to you as if you are using a non-power-of-2 texture and all is good... however, in secret, internally they actually scale up the texture to a power-of-2 size, and I don' t mean that they just put the pixels onto a po2 texture with some extra space around it, they actually stretch it to fit (I think). This results in most likely an up-scaling, which means interpolation. Then when you render your texture you think you're rendering non power of 2 but actually internally it's taking a power of 2 upscaled version of the texture (that you can't access from scripts either) and using that... hence it doesn't come out right. I found this out when I was trying to get exact pixel values transferred from a texture into a shader that needed those values to be perfect. So either you have to go with power-of-2 assets up-front and manually deal with what size sprites you need/texture atlas etc, or accept the consequences.
     
  22. M1k4

    M1k4

    Joined:
    Jun 8, 2013
    Posts:
    6
    I used the same formula (screen height/100/2) to test it on a 32x32 sprite and i got bad results, here they are (game window resolution - sprite resolution):

    640x480 - 38x39
    800x600 - 32x32
    1280x720 - 38x39

    Am i doing something wrong or is the formula only working on some cases?
     
  23. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,042
    That makes sense, though there is probably no secret stretching going on behind the scenes.

    Typically for shaders and materials of the normal variety, po2 is expected and what is commonly used.

    For sprites though, it is a different story/application. Size(ratio) isn't important, because (ideally), the separate elements are going to be batched into atlases, which will be po2. That is really what sprites are about, discrete chunks of image data.

    Really the best approach is not to use one image for both a sprite and a texture. Though you can, the use case for both is different.
     
  24. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,042
    What are you trying to do, and where are you applying it?

    The idea behind pixel perfect is that one pixel on the sprite is one pixel on the display. So a 32x32 should be 32x32 everywhere, assuming your camera is setup correctly. If you change the resolution without changing the camera size, they won't be pixel perfect, but they will stay the same visual size.

    The formula you stated is to set the size of the camera, not elements, for pixel perfect resolution. So, for 800x600 your ortho camera size should be 3, 640x480 it would be 2.4. Assuming you are using a pixel to units of 100, a 32x32 sprite at a scale of 1, will be exactly 32x32 in both of those cases.
     
  25. M1k4

    M1k4

    Joined:
    Jun 8, 2013
    Posts:
    6
    I added the script to the update function on the main camera, so it should've been updating every frame, which means it would work on every resolution, right? (also, the sprite is just a red square on the screen, nothing special about it)
     
  26. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,042
    It's probably not something you want put in update, (it is unneeded overhead), but sure, that should work, I just gave it quick test and it worked as expected. You are specifying floats, right?
    Code (csharp):
    1. cam.orthographicSize = (Screen.height/100f/2f);
     
  27. M1k4

    M1k4

    Joined:
    Jun 8, 2013
    Posts:
    6
    Damn... I completely forgot that i was using an intenger, which would always give me a number without decimals, and that explains why it only worked on 800x600. Thank you for pointing that out! :D
     
  28. zombiegorilla

    zombiegorilla

    Moderator

    Joined:
    May 8, 2012
    Posts:
    9,042
    Heh... the only reason I noticed it was because when I first typed it in I used ints as well, and the sprite was all over the place in size. It's always those little things that are hardest to spot. ;)
     
  29. siddharth3322

    siddharth3322

    Joined:
    Nov 29, 2013
    Posts:
    1,049
    I can able to cover my game within bound of screen using this approach but still exist a black bars so how to come out of this?
     
  30. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    Here is a tiny script I use to make sure my Camera is always pixel perfect.

    Simply drop it on your camera.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class PixelPerfect : MonoBehaviour
    6. {
    7.     public float floatable = 100.0f; //This can be PixelsPerUnit, or you can change it during runtime to alter the camera.
    8.  
    9.     void Update ()
    10.     {
    11.         this.camera.orthographicSize = Screen.height * gameObject.camera.rect.height / floatable / 2.0f;//- 0.1f;
    12.     }
    13. }
    14.  

    I don't remember if this works only for my game, or if it would work with anyone's. I'm pretty sure it will work with anyones.
     
    BusyCat likes this.
  31. TheFuntastic

    TheFuntastic

    Joined:
    Feb 11, 2013
    Posts:
    17
    [ANOTHER SOLUTION FOUND]

    I was struggling immensely with this, but I just found something no one else mentioned:

    I had tried:
    - Texture filter mode set to point
    - Max size set to size of texture
    - Compression off, set to true color (this actually seems unnecessary)
    - Power of two texture size (using texture atlas)
    - Sprite Renderer Material with pixel snap set to on
    - Camera orthographic size set to half height / pixels to unity unit size

    And still I was getting rather savage point filtering artefacts. It wasn't until I found some hidden texture import options that I solved it. If you set the texture to sprite first, and then to advanced, you get a bunch of extra texture import options. In particular Mesh Type. By default unity tries to construct a cutout mesh that saves as much transparency overdraw as possible. But this seems to play havoc with point filtering. So I set it Full Rect and voila - pixel perfect textures!

    $MeshFilter.png

    Note: I'm not sure, but I have a feeling this only works if your viewport is set to whole numbers, as I still sometimes see artefacts in the editor window while in play mode.
     
    Last edited: Mar 13, 2014
  32. RonnyD1978

    RonnyD1978

    Joined:
    Mar 13, 2014
    Posts:
    2
    Hey all, thanks for the great information. I thought Ray Wenderlich's tutorial was very handy.

    One quick question though: is there anything wrong with setting "Pixels to units" option at import settings to value 1? I mean that makes Unity units and pixels really 1-on-1. Which means if i position an object at 50, 50 in editor window then it's really at position 50, 50 in pixels, with expected width and height (shortly saying).

    I wonder why leaving it at default 100, are there any disadvantages or pitfalls along the way?

    Thanks in advance!
     
    Last edited: Mar 13, 2014
  33. Aedous

    Aedous

    Joined:
    Jun 20, 2009
    Posts:
    244
    This is a very informative read for people trying to understand the sprites and having pixel perfect calculations.

    I'm not sure if that at all applies to the distance of the sprite from the camera ( when using perspective ). From what I've tried even 'TheFuntastic' option does not actually make a difference with trying to get a pixel perfect representation of your sprite. ( If you could provide a screenshot that would be really good to see, maybe I'm doing something wrong )

    I don't know if there are any drawbacks for the number of pixel to units, I doubt there is that much of a set back as you really are only just determining how many pixels to units you want to use.

    The thing I've come to conclude is that in order to have pixel perfect sprites each sprite must be designed to fit a particular resolution that you have decided that the game view is going to have.

    Having an orthographic camera just makes it easier for you to calculate what the camera size should be in order to get a pixel perfect representation, however if you scale a sprite regardless of if you are in perspective or orthographic you lose that fine pixel quality.

    I may be completely wrong because I've only being messing around with 2d for the last couple of months, but it seems if you are going to do anything that is 2D the higher the resolution you bring into unity the better scaling it applies to the sprite so you reduce the odd pixel stretching.

    EDIT: I'm only referring to actually having to scale pixel art, everything seems to be fine if you are not using pixel art.
     
    Last edited: Mar 16, 2014
  34. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,539
    The biggest issue with that, is you will quickly start to run into floating point number inaccuracy as you move further and further away from 0,0,0. By keeping it near 100 pixels to units, you're in that sweet zone that will give you the most range out of the float value range. Here's a nice article that covers this topic:
    http://www.davenewson.com/dev/unity-notes-on-rendering-the-big-and-the-small

    You really shouldn't use 1 Pixel Per Unit. It's not that hard to just divide in your head by 100 to get the values you want to use, all you have to do is shift your number over by 2 decimal places, super simple! Or even, use a power of 2 value, such as 64 or 128, so that your texture dimensions are always either 0.25, 0.5 units, 1 units, 2 units, 4 units, etc.... Making it even easier to keep things matched up and placed around. (setting your Snap Settings to something like 0.25, and holding CTRL to move things around)
     
  35. SiegfriedCroes

    SiegfriedCroes

    Joined:
    Oct 19, 2013
    Posts:
    569
    Oh, I didn't know about that... I'm using 1 for pixels to units and it's actually working fine ^^'
    See for yourself: http://siegfriedcroes.com/landsoftreasure/ (Game is actually 320x180, web player is 960x540 so that's scaled up 3x)
     
  36. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,539
    It's working fine because you're still near the center of the scene. But as your level gets bigger, the further you get away from 0,0,0 world position, the more inaccurate it's going to become, introducing jitter/position errors. By having your scene scale so big, the distance you can go before that happens is going to be muuuuch smaller.
     
  37. SiegfriedCroes

    SiegfriedCroes

    Joined:
    Oct 19, 2013
    Posts:
    569
    Hmmm, I'll have to test that. If I would move my scene (object, player, camera,...) very far away from 0,0 should that show the jitter you are talking about? If so I'll try doing that and see what happens.

    EDIT: Moved everything to (10000, 5000), no difference at all ;)
     
    Last edited: Mar 16, 2014
  38. RonnyD1978

    RonnyD1978

    Joined:
    Mar 13, 2014
    Posts:
    2
    Invertex: I see your point here, smaller numbers so it's possible to plot further away positions within a level.

    Project i'm working on right now will only be 1, 2 maybe 3 screens max. So it's not going to be a big problem i think, pixel perfect and easy positioning are the most important aspects of my engine on top of Unity.

    I was thinking though: maybe i'm going to maintain 1 pixel => 2 units for SD textures and 1 pixel => 1 unit for HD textures (retina?), plotting everything onto a 2048x1536 surface.

    Of course at this moment i'm guessing a little and try out things that may easily fail (or not). Thanks for the info and great advice.
     
  39. Venks

    Venks

    Joined:
    Nov 20, 2013
    Posts:
    1
    @HubertGendron I followed your instructions and now everything is working A-OK for me. Thanks a bunch!
     
  40. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    Is this PRO only? I do not have those last two options: "Mesh Type" and "Extrue Edges".



    This is still a problem, even with all other settings correct.


    Unity pixel distortion occurs unless I offset the camera to .1

    I have tried everything but Pixel Snap on.


    The developers of Unity need to fix this. It's a horrendous bug which plagues all 2D developers. A hacky workaround or adjusting options is no excuse. This is a real issue which should simply not exist in the first place.

    $Unity-pixel-distortion.gif
     
  41. SiegfriedCroes

    SiegfriedCroes

    Joined:
    Oct 19, 2013
    Posts:
    569
    I totally agree, I'm also have to use some slight offset to make my pixel art look right, I absolutely hate the distortion. Luckily the offset fix always works so for now it's fine but they should definitely fix it!
     
  42. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    It's not fine for me, because as my character moves in a 2D map, it distorts the pixels resulting in a kindof flickering of different pixels.



    Pixel Snap - ON actually makes it WORSE.
     
    Last edited: May 2, 2014
  43. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
  44. CarterG81

    CarterG81

    Joined:
    Jul 25, 2013
    Posts:
    1,773
    Hilarious.

    Just being honest, whatever developer over at Unity who is in charge of 2D rendering, sucks. They just do. I don't like saying it, but it's an irrefutable fact.

    Rendering is the #1 most important aspect of any game engine. It is what makes video games...video games. Hence the video portion of "video games".

    Unity fails us in this regard though. How or why, I have no clue. Even after compiling all possible solutions, even after updating Unity to fix some of the sub-pixel bugs, the problems remain. Unity is irrational about placing objects, as some need to be placed with random offsets that seem entirely inconsistent in logic. Asset1 needs offset of 0.5 a pixel. Asset2 needs an offset of 0.7 a pixel. Oh wait, this one wont even render correctly bc it's a NPOT texture! Pixel snap on? Off? RAWRGHGHRHGHLLL!

    The only solution I've ever found was to use Vectrosity to render from text files, which is honestly unacceptable.

    Then on the asset store, Pixelatto released "Pixel Perfect" and all the pixel perfect problems vanished. At least so far. Simply phenomenal that an asset store developer had to fix rendering flaws in Unity's 2D components. This is unacceptable, and something Unity should have resolved a long, long time ago.

    The only working solution I've found: https://www.assetstore.unity3d.com/en/#!/content/14498

    If using Pixel Perfect asset, be sure to do the following:

    2) Just to be safe. Make sure your textures are Power of Two. (256x256, 512x512, etc.) Unity itself is horrible messing up NPOT textures. Not sure if the asset with the nested gameobjects were the reason why, or if NPOT also caused bugs.
    3) Turn OFF pixel snap.
     
    Last edited: Oct 18, 2014
    GarBenjamin likes this.
  45. Rokzero

    Rokzero

    Joined:
    May 19, 2014
    Posts:
    5
    It sucks that you need to buy an asset to fix Unity 2D engine problems, I hope they will build that asset in soon.
     
    GarBenjamin and CarterG81 like this.
  46. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    At least you found a way around it. Part of the frustration I've had with switching to Unity is due to these same things. They do some impressive things making some very complex bits an afterthought yet sometimes the simple most fundamental things they seem to have messed up. It is truly very strange. Lol

    But everything I have ever used has these kinds of issues to some degree which is why I don't like to rely on anything but the most basic functionality of an API and just do the rest myself. Too many times I have had to scrap stuff and redo entire modules because of some flaw in the API / engine I was using. You end up spending more time trying to work around the bug than if you just wrote it yourself to begin with in some cases!

    Right now I am happy with my Unity dev. I am not using the Animator, Physics etc. Just using the bare minimum I need from Unity to display graphics and play sounds. The rest I am handling myself in code. Works beautifully. I do have an issue with collisions not being as tight as they should be but that is because I tried taking the easy way again of using Unity's collision system. And the polygon colliders are very loose around the sprite images. I suppose I need to write that part myself as well to get tight collisions but I can live with it for now.
     
    CarterG81 likes this.
  47. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    418
    Not exactly sure what you mean by "loose", but the physics settings in your project have a huge effect on how they feel and perform. I'd definitely experiment with [Edit > Project Settings > Physics / Physics 2D] if you haven't already. To see if you can make it feel tighter.
     
  48. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    This is not related to the physics settings. I am not using the Unity Physics although I understand what you are saying, the collision detection is handled as part of the Physics updates.

    What I mean by "loose" polygon colliders is how they map around a sprite image. I realize making them pixel perfect could be quite expensive in some cases requiring a huge number of points. However, the way they currently map is pretty loose and I think should definitely be improved in a future release.

    Here is an example of 2 frames of an animated snake enemy from my current W.I.P. platform game:


    You can see the bounding box of the sprites and then inside you can see the Polygon Collider mapping Unity generated.

    This is what I mean by "loose". When you consider any colliding objects can also have gaps the same size it means you end up with collisions happening quite often that should not be happening. This kind of defeats the point of using polygon colliders. Sure it is a better fit than a single box collider would be but still very imprecise. Especially, notice the second sprite has strange glitches of shapes around the snake's head.
     
    CarterG81 likes this.
  49. IsaiahKelly

    IsaiahKelly

    Joined:
    Nov 11, 2012
    Posts:
    418
    Looks like my suspicions were correct. The level of detail for auto-generated polygon colliders seems to be based on the pixel density of the image. In the example below, I scaled the same image in Photoshop several times, exporting each into Unity.

    ContraExample.png

    As you can see, the larger the image, the more vertices/detail. The looseness is a side effect of the algorithm using less vertices for smaller images. Interestingly enough the "pixels to units" setting on sprites has no effect. Only the actual image size.

    This issue can be "fixed" by manually modifying the polygon collider yourself, but that is kind of a pain. Perhaps Unity could add a setting to allow you to set how many vertices are used per unit/pixel. This would give you a lot more control over the level of precision for auto-generated colliders.

    However, I personally just use boxes, circles, or compound colliders for characters like these. Polygon colliders seem excessive to me.

    Update: Unity 5.6 seems to have finally added features to let you control this. Better late than never I suppose.
     
    Last edited: Mar 23, 2017
    GarBenjamin likes this.
  50. GarBenjamin

    GarBenjamin

    Joined:
    Dec 26, 2013
    Posts:
    7,441
    That was an excellent test and one I never considered! Great info. Sounds like we could simply scale up the sprite images and when imported into unity they would be wrapped with polygon colliders that are much more precise. Then simply scale the image down. I need to test that.

    But yeah you are right. When I was using XNA I made a utility to generate multiple box colliders for sprites. I may just use that approach again. Thanks for sharing your test results!