How to compare two sprite textures in unity - unity3d

I have a requirement of comparing two sprite textures for knowing those two sprites belongs to same image or not. Here those textures are loaded from urls. Thanks in advance.
Here is the sample code for getting sprite texture:
WWW imageLink = new WWW(imageUrl);
var spriteTexture = imageLink.texture;
In on of my case same image with two different urls. Once url is loaded, have a requirement of identifying those textures have belongs to same image. Please suggest any idea.

There is no easy util to compare the two textures, but luckily it's easy to write one. The method of Texture2D.GetPixels() will give you a Color[] array which represents a flattened 2d array of pixel colors. Each row of pixels will be placed one after the other, starting from the bottom to the top. Comparing the two arrays should prove the two textures are identical. I tried this code:
private bool CompareTexture (Texture2D first, Texture2D second)
{
Color[] firstPix = first.GetPixels();
Color[] secondPix = second.GetPixels();
if (firstPix.Length!= secondPix.Length)
{
return false;
}
for (int i= 0;i < firstPix.Length;i++)
{
if (firstPix[i] != secondPix[i])
{
return false;
}
}
return true;
}
With you code, you will simply need to call:
WWW imageLink = new WWW(imageUrl1); //first image URL
WWW imageLink2 = new WWW(ImageUrl2); //second image URL
if (CompareTexture(imageLink.texture, imageLink2.texture) {
....
}
To compare both textures.

Related

Unity GUIEditor - how can I access the sprites within my texture from code

I want to access the sprites under the png I've got selected. (Which has already been sliced in the sprite editor)
Example: Here I know how I can make my GUIEditor see I have Druid_jump selected, now I want to grab hold of the Sprite type objects Druid_Jump_0_00 until Druid_Jump_3_03 by code (without interaction of my user) so that I can set up the 4 animations for them
I was trying with the following code sample:
List<Texture2D> textures = new List<Texture2D>(Selection.GetFiltered<Texture2D>(SelectionMode.Unfiltered));
foreach (Texture texture in textures)
{
if (texture != null)
{
string path = AssetDatabase.GetAssetPath(texture);
string containingFolder = null;
if (string.IsNullOrEmpty(containingFolder))
{
containingFolder = path.Remove(path.LastIndexOf('/'));
}
var importer = AssetImporter.GetAtPath(path) as TextureImporter;
List<Sprite> currentFrames = new List<Sprite>();
int index = 0;
foreach (SpriteMetaData spriteMetaData in importer.spritesheet)
{
string[] slice = spriteMetaData.name.Split('_');
if (slice[2] != index.ToString())
{
//CreateAnimation(currentFrames.Count, currentFrames);
currentFrames = new List<Sprite>();
index++;
}
// The Code works fine until here, I need the "Sprite" type object to set up the animation
Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>($"{containingFolder}/{spriteMetaData.name}");
//currentFrames.Add(sprite);
Debug.Log(sprite.name);
}
}
}
I was hoping Sprite sprite = AssetDatabase.LoadAssetAtPath<Sprite>($"{containingFolder}/{spriteMetaData.name}"); would get the individual Sprite, but it currently finds null, while the spriteMetaData is actually returning the correct spritenames.
Sprite sprite = Sprite.Create(Texture2D texture, Rect rect, Vector2 pivot);
Your rect will be probably (0,0,resultionX,resulutionY), and pivot (0.5f, 0.5f)
Considering the image was already sliced into sprites, the correct answer was using AssetDatabase.LoadAllAssetsAtPath instead, which returns an Object array and includes the sprites under the png image. The AssetDatabase.GetAssetPath function does not include those.
Once we have the object array, we loop through the objects and cast the object to the sprite type and then we are good to go.
Object[] data = AssetDatabase.LoadAllAssetsAtPath(AssetDatabase.GetAssetPath(texture));
if(data != null)
{
foreach (Object obj in data)
{
if (obj.GetType() == typeof(Sprite))
{
Sprite sprite = obj as Sprite;

Best way to create a 2d top down race track procedurally

I am attempting to create a 2d top-down car racing game. This game will have a random road map each time the player plays the game. I have thought about doing this in two different ways: A tilemap, or just generate the roads by placing different prefabs (straight roads, turns, etc). I have decided to go with the prefab route.
The way I believe it should work is to have prefab square "tiles" which have their own colliders set on the edges so I can tell if a player goes off the track in which case they blow up. I would have a MapGenerator Script which will generate an initial random map by keeping track of the last tile placed (including its location and road type: left turn, straight, right, etc). This script will then keep adding onto the road randomly as the player gets closer and closer to the end which makes it an infinite road.
I just want to know if this is just not efficient or if I am thinking of this completely wrong.
Here are a couple of images showing my road tiles which I made in photoshop and then one prefab for a straight road (take note of the colliders on its edges).
A similar game to one I want to make is Sling Drift which I can provide the link if you want. I don't know the policy on adding links to forum chat.
Also, here is my code for the map generator:
//Type of tyle, types are normal (straight road or horizontal road) and turns
public enum MapTileType
{
NORMAL,
N_E,
N_W,
S_E,
S_W
}
//structure for holding the last tile location and its type.
public struct TypedTileLocation
{
public TypedTileLocation(Vector2 pos, MapTileType tyleType)
{
m_tileType = tyleType;
m_position = pos;
}
public Vector2 m_position;
public MapTileType m_tileType;
}
public class MapGenerator : MonoBehaviour
{
//Map Tiles
public GameObject m_roadTile;
public GameObject m_turnNorthWestTile;
//holds all the tiles made in the game
private List<GameObject> m_allTiles;
//Map Tile Widths and Height
private float m_roadTileWidth, m_roadTileHeight;
//Used for generating next tile
TypedTileLocation m_lastTilePlaced;
private void Awake()
{
//store the initial beginning tile location (0,0)
m_lastTilePlaced = new TypedTileLocation(new Vector2(0,0), MapTileType.NORMAL);
//set height and width of tiles
m_roadTileWidth = m_roadTile.GetComponent<Renderer>().bounds.size.x;
m_roadTileHeight = m_roadTile.GetComponent<Renderer>().bounds.size.y;
m_allTiles = new List<GameObject>();
}
// Start is called before the first frame update
void Start()
{
SetupMap();
}
void SetupMap()
{
//starting at the beginning, just put a few tiles in straight before any turns occur
for (int i = 0; i < 6; ++i)
{
GameObject newTempTile = Instantiate(m_roadTile, new Vector2(0, m_roadTileHeight * i), Quaternion.identity);
m_lastTilePlaced.m_tileType = MapTileType.NORMAL;
m_lastTilePlaced.m_position.x = newTempTile.transform.position.x;
m_lastTilePlaced.m_position.y = newTempTile.transform.position.y;
m_allTiles.Add(newTempTile);
}
//now lets create a starter map of 100 road tiles (including turns and straigt-aways)
for (int i = 0; i < 100; ++i)
{
//first check if its time to create a turn. Maybe I'll randomly choose to either create a turn or not here
//draw either turn or straight road, if the tile was a turn decide which direction we are now going (N, W, E, S).
//this helps us determine which turns we can take next
//repeat this process.
}
}
void GenerateMoreMap()
{
//this will generate more map onto the already existing road and then will delete some of the others
}
// Update is called once per frame
void Update()
{
}
private void OnDrawGizmos()
{
}
}
Thanks!
Have you tried splines? They let you make curvy paths like race tracks easily. If not, here is a video that might help: https://www.youtube.com/watch?v=7j_BNf9s0jM.

How to change texture format from Alpha8 to RGBA in Unity3d?

I have been trying to change the format from a camera that give a texture in Alpha8 to RGBA and have been unsuccessful so far.
This is the code I've tried:
public static class TextureHelperClass
{
public static Texture2D ChangeFormat(this Texture2D oldTexture, TextureFormat newFormat)
{
//Create new empty Texture
Texture2D newTex = new Texture2D(2, 2, newFormat, false);
//Copy old texture pixels into new one
newTex.SetPixels(oldTexture.GetPixels());
//Apply
newTex.Apply();
return newTex;
}
}
And I'm calling the code like this:
Texture imgTexture = Aplpha8Texture.ChangeFormat(TextureFormat.RGBA32);
But the image gets corrupted and isn't visible.
Does anyone know how to change this Alpha8 to RGBA so I can process it like any other image in OpenCV?
A friend provided me with the answer:
Color[] cs =oldTexture.GetPixels();
for(int i = 0; i < cs.Length; i++){//we want to set the r g b values to a
cs[i].r = cs[i].a;
cs[i].g = cs[i].a;
cs[i].b = cs[i].a;
cs[i].a = 1.0f;
}
//set the pixels in the new texture
newTex.SetPixels(cs);
//Apply
newTex.Apply();
This will take alot of resources but it will work for sure.
If you know a better way to make this change please add an answer to this thread.

Placing randomly sized objects side by side unity 2D

I am attempting to instantiate differently shaped prefabs next to eachother. I have a folder full of differently sized objects that allow for me to string them together randomly to create a 2D endless runner. My issue is that all the answers online about placing objects beside eachother don't work when different sized objects are used. Here is the code I am using to instantiate the sections. It works when it only randomly selects similar sized objects. When the selected prefab is a different length it leaves either a gap between, or overlaps, the previous object.
for(int i = 0; i < activeSectionsAtOnce; i++)
{
int index = Random.Range(0, sectionPrefabs.Length);
GameObject currentOb = sectionPrefabs[index];
Vector2 position = new Vector2();
if(activeSections.Count == 0)
{
//set a (0, 0) position for first object
position = Vector2.zero;
}
else
{
//get most recently placed object from list
GameObject lastOb = activeSections[activeSections.Count - 1];
//my attempt at getting bounds for the last object and for the next prefab that will be used
Bounds lasObbounds = new Bounds(lastOb.transform.position, Vector2.zero);
Bounds currentBounds = new Bounds(currentOb.transform.position, Vector2.zero);
//Include child objects(all have sprite renderers)
foreach (Renderer r in lastOb.GetComponentsInChildren<Renderer>())
{
lasObbounds.Encapsulate(r.bounds);
}
foreach (Renderer rend in currentOb.GetComponentsInChildren<Renderer>())
{
currentBounds.Encapsulate(rend.bounds);
}
//position object will be instantiated at
position.x = lastOb.transform.position.x + (lasObbounds.size.x / 2) + (currentBounds.size.x/2);
}
//instantiate at selected position
activeSections.Add(
Instantiate(currentOb, position, Quaternion.identity)
);
}
This is in the start method. I'm not sure if the problem is how I'm creating the bounds, or how im mathematicaly creating the x coordinate. This is the expected result that happens when I use same sized prefabs. This is what happens with different prefabs
The shorter protrusion from the first object should be cleanly between the other two without a gap.
Here's an image of one prefab
Thanks for any advice

Add remote image as texture during loop

I am very new to Unity3d.
I have a JSON array that contains the parameters of the prefabs I want to create at runtime.
I want to display images that are stored on my server in the scene.
I have a prefab "iAsset" that has a plane (mesh filter) and I want to load the image files as the texture of the plane.
I am able to Instatiate the prefabs however the prefab is showing up as a white square. This is my code:
for(var i = 0; i < bookData.Assets.Count; i++){
GameObject newAsset = null;
newAsset = (GameObject)Instantiate(iasset, new Vector3(2*i, 0, 0), Quaternion.identity);
if(!imageAssetRequested )
{
remoteImageAsset = new WWW(((BookAssets)bookData.Assets[i]).AssetContent);
imageAssetRequested = true;
}
if(remoteImageAsset.progress >=1)
{
if(remoteImageAsset.error == null)
{
loadingRemoteAsset = false;
newAsset.renderer.material.mainTexture = remoteImageAsset.texture;
}
}
}
the urls to the images on my server is retrieved from the JSON array:
((BookAssets)bookData.Assets[i]).AssetContent);
The code builds without any errors, I would very much appreciate any help to display the remote images.
You are not waiting for your downloads to complete.
The WWW class is asynchronous, and will commence the download. However, you need to either poll it (using the code you do have above) at a later time, or use a yield WWW in a CoRoutine that will block your execution (within that CoRoutine) until the download finishes (either successfully or due to failure).
Refer to Unity Documentation for WWW
Note however, that page sample code is wrong, and Start is not a CoRoutine / IEnumarator. Your code would look something like :
void Start()
{
... your code above ...
StartCoroutine(DownloadImage(bookData.Assets[i]).AssetContent, newAsset.renderer.material.mainTexture));
}
IEnumerator DownloadImage(string url, Texture tex)
{
WWW www = new WWW(url);
yield return www;
tex.LoadImage(www.bytes)
}