Search Unity

Pixel3D - Turn Your Pixel Art into Voxelized 3D Shapes! [RELEASED]

Discussion in 'Assets and Asset Store' started by scarletshark, May 1, 2015.

  1. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    Free Version - Coming Soon!
    pixel3D_Free.png

    • Added proper scripting access for pixel variables (size, layer offset, scale, etc).

    What is Pixel3D?


    Pixel3D is a simple component that attaches to Unity's built-in 2D sprite object, and turns your 2D pixelart sprites into stylized 3D shapes! Just add the component to your sprite, and press play.

    Pixel3D supports frame-by-frame animation, and allows you to create awesome voxel-like effects!

    Download now in the Asset Store!
    Check out the WebGL Demo!


    Why would I use this?

    Because you want to set your Pixel Art creations apart from all others!


    I have questions/comments/feedback!

    We want to hear from you! Please contact us at info@cwinteractive.com

    LIMITATIONS

    Individual sprites should be no larger than 128x128, but packed spritesheets can be larger.


     
    Last edited: May 12, 2015
    SAOTA likes this.
  2. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    I'm excited to announce that I have tested an early prototype of a free version! The free version will be a fully-featured alternative for hobbyists who do not need access to the source code.

    pixel3D_Free.png


    I'm looking forward to posting Pixel3D Free, and getting feedback!
     
  3. SAOTA

    SAOTA

    Joined:
    Feb 9, 2015
    Posts:
    220
    Wow. what magic is this!!
     
    scarletshark likes this.
  4. Diet-Chugg

    Diet-Chugg

    Joined:
    Jul 4, 2012
    Posts:
    51
    Cool. Looks fun.
     
    scarletshark likes this.
  5. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    No magic, just a fun little project! Can't wait to get some feedback from users.
     
  6. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    Version 1.2 Released!

    In this release:

    • Fixed bug where non-center pivot point caused the 3D sprite to be offset
    • Fixed bug where sprite was offset improperly when sprite's localScale != 1

    Thanks so much to superdbop on REDDIT for finding a pivot point bug!
     
    Last edited: May 8, 2015
  7. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    Version 1.3 Released!

    With this version come some enhancements to scripting the pixel attributes!

    I have made a WebGL build to show it off. Take a look, and let me know what you think!

    Check it out here!

    For those interested, there were a specific set of requirements to get this working in WebGL:

    • WebGL is set to the lowest quality setting by default. In quality settings, texture resolution must be full-res to work.
    • Sprites must be imported non-compressed. I used Automatic Truecolor.
    • WebGL chugged pretty hard with SSAO, so I had to remove it for the demo.
     
    Last edited: May 12, 2015
  8. Duende

    Duende

    Joined:
    Oct 11, 2014
    Posts:
    200
    Hello! This asset looks really great!

    In addition to runtime, is it possible to use it in the editor to export an object?
     
  9. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    That is not a feature of my plugin, but you could theoretically do this! Here's a wiki article to get you started!

    Steps:
    • Copy that script to a new script in your Assets/Editor directory.
    • Set up your sprites to work appropriately with Pixel3D.
    • Press play.
    • In the Hierarchy panel, select the sprite you want to export.
    • Select File/Export/Wavefront OBJ (No Submeshes).
    However, this does not save the materials that were assigned to the pixels. You will probably need to manually re-assign these in your desired 3D application. This will also not save any animations (should be self-explanatory).
     
  10. Duende

    Duende

    Joined:
    Oct 11, 2014
    Posts:
    200
    Thank you very much! I bought your asset.

    I've been testing and ExportOBJ not work accurately. I mean, each pixel does not measure the same when I load the .obj file in another program for editing.
     
  11. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    Interesting. I gave it a try, and it seemed to be working, but as I said this is not a feature of my plugin... Could you upload a screenshot, and I'll see if I can help?
     
  12. Duende

    Duende

    Joined:
    Oct 11, 2014
    Posts:
    200
    Well, the first is that ExportOBJ is not compatible with Unity5 and need to upgrade. I used the automatic update of Unity.

    Then if I use Wavefront OBJ (No submeshes) exports me this:




    If I remove the objects that are invisible, leaving only the figure of the sprite, exports me this:




    As you can see, it creates something rare. Each cubes of the sprite seem to be hollow, that is, it does not have its six walls:




    If I import it into a program like MagicaVoxel, you can see it is not a sprite which each pixel is the same size:



     
    Last edited: May 19, 2015
  13. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    This isn't a big deal, a lot of scripts require this now due to major changes to Unity... shouldn't affect the outcome much.

    Ah, you know, I hadn't considered this! [I have not tested this yet] In the ObjExporter, you could do the following to keep those transparent pixels from being exported:

    Code (CSharp):
    1.     static string processTransform(Transform t, bool makeSubmeshes)
    2.     {
    3.         StringBuilder meshString = new StringBuilder();
    4.      
    5.         // Add new local variables
    6.         Transform child;
    7.         Material childMat;
    8.      
    9.         meshString.Append("#" + t.name
    10.                         + "\n#-------"
    11.                         + "\n");
    12.  
    13.         if (makeSubmeshes)
    14.         {
    15.             meshString.Append("g ").Append(t.name).Append("\n");
    16.         }
    17.  
    18.         MeshFilter mf = t.GetComponent<MeshFilter>();
    19.         if (mf)
    20.         {
    21.             meshString.Append(ObjExporterScript.MeshToString(mf, t));
    22.         }
    23.  
    24.         for(int i = 0; i < t.childCount; i++)
    25.         {
    26.             // Don't export invisible children
    27.             child = t.GetChild(i);
    28.             childMat = child.renderer.material;
    29.          
    30.             if(childMat.color.a != 0){
    31.                 meshString.Append(processTransform(child, makeSubmeshes));
    32.             }
    33.         }
    34.  
    35.         return meshString.ToString();
    36.     }
    It looks like those normals are reversed. The cubes have 6 sides, as you can see in your MagicaVoxel screenshot; however, for some reason Unity is displaying them backwards. You could try editing the .obj's import settings. Set the Normals to "Calculate", and apply. See what happens.

    This particular program I am unfamiliar with. You may want to post a question on the MagicaVoxel forums, and see what people have to say. I hope I have helped!
     
  14. Duende

    Duende

    Joined:
    Oct 11, 2014
    Posts:
    200
    I tried that and not fixed, but do not worry.

    Thank you very much for the help. :)
     
  15. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    You know, it had me stumped so bad, I couldn't resist finding the problem! :)

    I have it working now in Maya and in Unity (left and right below). The problem was that the ObjExporter in the wiki was writing the vertices in -Z direction. They were also writing normals the wrong direction too, it appears.



    Here's my full ObjExporter class:

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System.Collections;
    4. using System.IO;
    5. using System.Text;
    6.  
    7. public class ObjExporterScript
    8. {
    9.     private static int StartIndex = 0;
    10.  
    11.     public static void Start()
    12.     {
    13.         StartIndex = 0;
    14.     }
    15.     public static void End()
    16.     {
    17.         StartIndex = 0;
    18.     }
    19.  
    20.  
    21.     public static string MeshToString(MeshFilter mf, Transform t)
    22.     {  
    23.         Vector3 s         = t.localScale;
    24.         Vector3 p         = t.localPosition;
    25.         Quaternion r     = t.localRotation;
    26.      
    27.      
    28.         int numVertices = 0;
    29.         Mesh m = mf.sharedMesh;
    30.         if (!m)
    31.         {
    32.             return "####Error####";
    33.         }
    34.         Material[] mats = mf.GetComponent<Renderer>().sharedMaterials;
    35.      
    36.         StringBuilder sb = new StringBuilder();
    37.      
    38.         foreach(Vector3 vv in m.vertices)
    39.         {
    40.             Vector3 v = t.TransformPoint(vv);
    41.             numVertices++;
    42.             sb.Append(string.Format("v {0} {1} {2}\n",v.x,v.y,v.z));
    43.         }
    44.         sb.Append("\n");
    45.         foreach(Vector3 nn in m.normals)
    46.         {
    47.             Vector3 v = r * nn;
    48.             sb.Append(string.Format("vn {0} {1} {2}\n",v.x,v.y,v.z));
    49.         }
    50.         sb.Append("\n");
    51.         foreach(Vector3 v in m.uv)
    52.         {
    53.             sb.Append(string.Format("vt {0} {1}\n",v.x,v.y));
    54.         }
    55.         for (int material=0; material < m.subMeshCount; material ++)
    56.         {
    57.             sb.Append("\n");
    58.             sb.Append("usemtl ").Append(mats[material].name).Append("\n");
    59.             sb.Append("usemap ").Append(mats[material].name).Append("\n");
    60.          
    61.             int[] triangles = m.GetTriangles(material);
    62.             for (int i=0;i<triangles.Length;i+=3) {
    63.                 sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n",
    64.                                         triangles[i]+1+StartIndex, triangles[i+1]+1+StartIndex, triangles[i+2]+1+StartIndex));
    65.             }
    66.         }
    67.      
    68.         StartIndex += numVertices;
    69.         return sb.ToString();
    70.     }
    71. }
    72.  
    73. public class ObjExporter : ScriptableObject
    74. {
    75.     [MenuItem ("File/Export/Wavefront OBJ")]
    76.     static void DoExportWSubmeshes()
    77.     {
    78.         DoExport(true);
    79.     }
    80.  
    81.     [MenuItem ("File/Export/Wavefront OBJ (No Submeshes)")]
    82.     static void DoExportWOSubmeshes()
    83.     {
    84.         DoExport(false);
    85.     }
    86.  
    87.  
    88.     static void DoExport(bool makeSubmeshes)
    89.     {
    90.         if (Selection.gameObjects.Length == 0)
    91.         {
    92.             Debug.Log("Didn't Export Any Meshes; Nothing was selected!");
    93.             return;
    94.         }
    95.      
    96.         string meshName = Selection.gameObjects[0].name;
    97.         string fileName = EditorUtility.SaveFilePanel("Export .obj file", "", meshName, "obj");
    98.      
    99.         ObjExporterScript.Start();
    100.      
    101.         StringBuilder meshString = new StringBuilder();
    102.      
    103.         meshString.Append("#" + meshName + ".obj"
    104.                           + "\n#" + System.DateTime.Now.ToLongDateString()
    105.                           + "\n#" + System.DateTime.Now.ToLongTimeString()
    106.                           + "\n#-------"
    107.                           + "\n\n");
    108.      
    109.         Transform t = Selection.gameObjects[0].transform;
    110.      
    111.         Vector3 originalPosition = t.position;
    112.         t.position = Vector3.zero;
    113.      
    114.         if (!makeSubmeshes)
    115.         {
    116.             meshString.Append("g ").Append(t.name).Append("\n");
    117.         }
    118.         meshString.Append(processTransform(t, makeSubmeshes));
    119.      
    120.         WriteToFile(meshString.ToString(),fileName);
    121.      
    122.         t.position = originalPosition;
    123.      
    124.         ObjExporterScript.End();
    125.         Debug.Log("Exported Mesh: " + fileName);
    126.     }
    127.  
    128.     static string processTransform(Transform t, bool makeSubmeshes)
    129.     {
    130.         StringBuilder meshString = new StringBuilder();
    131.      
    132.         // Add new local variables
    133.         Transform child;
    134.         GameObject childGO;
    135.      
    136.         meshString.Append("#" + t.name
    137.                           + "\n#-------"
    138.                           + "\n");
    139.      
    140.         if (makeSubmeshes)
    141.         {
    142.             meshString.Append("g ").Append(t.name).Append("\n");
    143.         }
    144.      
    145.         MeshFilter mf = t.GetComponent<MeshFilter>();
    146.         if (mf)
    147.         {
    148.             meshString.Append(ObjExporterScript.MeshToString(mf, t));
    149.         }
    150.      
    151.         for(int i = 0; i < t.childCount; i++)
    152.         {
    153.             // Don't export invisible children
    154.             child = t.GetChild(i);
    155.  
    156.             if(child.gameObject.activeSelf){
    157.                 meshString.Append(processTransform(child, makeSubmeshes));
    158.             }
    159.         }
    160.      
    161.         return meshString.ToString();
    162.     }
    163.  
    164.     static void WriteToFile(string s, string filename)
    165.     {
    166.         using (StreamWriter sw = new StreamWriter(filename))
    167.         {
    168.             sw.Write(s);
    169.         }
    170.     }
    171. }
     
    nxrighthere and SAOTA like this.
  16. Duende

    Duende

    Joined:
    Oct 11, 2014
    Posts:
    200
    Oh, thank you very much. Now exports well the .obj.

    MagicaVoxel continues to import wrong the object, but that's problem of MagicaVoxel.
     
    scarletshark likes this.
  17. Exeneva

    Exeneva

    Joined:
    Dec 7, 2013
    Posts:
    432
    How well does this work with sprites that are not pixel art style?
     
  18. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    That is not the intended purpose of the plugin :)
     
  19. Hertzole

    Hertzole

    Joined:
    Jul 27, 2013
    Posts:
    422
    Hi!

    I have been checking out your asset and so far it looks really good for the project I am working on! But I have one question before I purchase it. Can it change the model of a current 3D sprite art to a new one without needing to create another game object? An example:

    I have this equipment system. So for example, I equip a sword. Would your asset be able to generate that model then on the fly? But there's more. I then equip a bow instead of the sword. Would your asset be able to switch the model from the sword model to the bow model without lag and without creating a new game object of each model?
    (When I switch weapon, I switch the sprite basically)

    If it can handle my question I will buy this without looking back! :)
     
  20. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    Theoretically, if I understand correctly, all you would need to do is change the sprite property to a new sprite!
     
  21. Ortath

    Ortath

    Joined:
    May 22, 2014
    Posts:
    7
    I recently purchased this and when I import it into Unity3d 5.1.2f1, I get the following errors.
    Broken YAML file(Assets/Pixel3D/Base/Animations/PlayerAnimator.controller). Local file identifier (110204312) doesn't exist!
    Broken YAML file(Assets/Pixel3D/Base/Animations/PlayerAnimator.controller). Local file identifier (110220632) doesn't exist!
     
  22. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    Thank you for the report. I'm in the middle of adding support for "static" sprites at the moment, and will make sure to fix this issue as well for this release.
     
  23. scarletshark

    scarletshark

    Joined:
    Jun 6, 2013
    Posts:
    33
    Just an update: That error is not fatal, and appears to be a Unity issue. If you clear the error, it will not come back. Everything should work correctly!
     
  24. ZJP

    ZJP

    Joined:
    Jan 22, 2010
    Posts:
    2,649
    Nice asset. Bookmarked. :cool:
     
  25. anuj

    anuj

    Joined:
    Jun 15, 2015
    Posts:
    28
    is it possible to optimize the final mesh .
    for example if i generate pixels for necromancer image (single sprite non animated), is it possible to get rid of inner faces of the generated pixel art

    the obj exporter you provided above , will it be included in future updates by default . it will be easy to get it from asset package itself rather then coming here to copy the code from forum.

    also , is the mesh exported by obj exporter is it optimized ( the inner faces removed).

    and lastly is code optimized for mobile applications for runtime.
     
  26. magarcan

    magarcan

    Joined:
    Sep 25, 2012
    Posts:
    34
    Has anybody been able to use it in Unity 5.6?

    Those are my settings, as accurate as the ones in Readme I can. And the error.

    Can anybody help?