Color submeshes in unity3d - unity3d

I have a main_mesh that has 10 submeshes, I wonder how I can change the color of of these submeshes to a different color (e.g submesh1 will have a red color, submesh2 will have a blue color,...etc). Any advise please?
UPDATE:
This is how I'm getting my mesh which has 10 submeshes:
SkinnedMeshRenderer smr = gameobject1.GetComponent<SkinnedMeshRenderer>();
Mesh main_mesh = smr.sharedMesh;

SkinnedMeshRenderer smr = gameobject1.GetComponent<SkinnedMeshRenderer>();
Mesh main_mesh = smr.sharedMesh;
smr.materials[0].color = Color.red; // Change submesh1 to red color
smr.materials[1].color = Color.blue; // Change submesh2 to blue color
...
smr.materials[n].color = ... // Change submesh n to whatever color

Since you've added the tag Unityscript i'll assume that you want to be able to change submeshes inside a script.
Assignation as parameter
The first solution would be to have add a public parameter to you script that would be an array of Mesh. Then assign manually each submesh to the array through the inspector. Now you can access the material of each mesh and change it's color.
public class MyScript : MonoBehaviour {
public Mesh[] submeshes;
// Update is called once per frame
void Update () {
for (int i = 0; submeshes[i]; i++) {
// Return the first material of the mesh renderer, use .materials if multiple Material are applied
submeshes[i].renderer.material.color = Color.red;
}
}
}
Note that I used Mesh as type for my array, but you could directly use Material if you only want to change the color.
Also, if submeshes have the exact same material, It'll change the color for all submeshes, not just one. You need to have one material per mesh.
While this solution is not viable if your number of submeshes change dynamically, this solution is pretty simple and straighforwarded.
Use children
Instead of assigning every submeshes manually, you can dynamically change the color by accessing children
public class MyScript : MonoBehaviour {
public Mesh myObject;
// Update is called once per frame
void Update () {
Material[] array = myObject.GetComponentsInChildren<Material>();
for (int i = 0; array[i]; i++) {
array[i].color = Color.red;
}
}
}
This solution allows you to have N material assigned to your submeshes.
Here is the documentation for GetComponentsInChildren
Edit
Short answer If you want a specific answer to your case, it depends on the materials and shaders assigned to your skinned Mesh Renderer because they can override or alter your childrens' materials. If not, the below code should work.
SkinnedMeshRenderer smr = gameobject1.GetComponent<SkinnedMeshRenderer>();
Mesh main_mesh = smr.sharedMesh;
Mesh[] submeshes = main_mesh.GetComponentsInChildren<Mesh>();
for (int i = 0; submeshes[i]; i++) {
// If your submesh already have a material, remove the first line below !
submeshes[i].renderer.material = new Material(Shader.Find("Diffuse"));
submeshes[i].renderer.material.color = Color.red;
}
This solution create a new material for each submesh, which is quite brutal.
In the inspector, you should assign one material to each submeshes and then use always the same material with different colors.
In case it doesn't work
When you want to change the color of one specific mesh, this mesh needs to have his own material. The color of the mesh will depends on this materials and it's properties (shaders, textures, colors).
With a Skinned Mesh Renderer, you generally use Diffuse Material with textures to apply colors to one complex mesh. In some case, this mesh apply the color to it's childrens.
When using a Skinned Mesh Renderer, you usually use a UV texture. This particular texture is created based on your 3D object and is used to apply multiple color on it (sometimes also it's childrens). Here is a simple example of UV texture and here is a more complex example.
Note that, as a mesh Renderer, a skinned mesh renderer can have multiple materials which make the situation more complex but the principle remains the same.
SkinnedMeshRenderer smr = gameobject1.GetComponent<SkinnedMeshRenderer>();
Mesh main_mesh = smr.sharedMesh;
With your code if main_mesh use a UV texture, you have two solutions
Remove the texture then apply a color to it's children
Create a specific UV texture which apply colors as you want.

Related

Lightning and display issues with Unity CanvasRenderer

My goal is to draw simple, colored meshes on a Canvas in Unity. I set up a Canvas and chose Render Mode World Space. I then added a GameObject, set its RectTransform, added a CanvasRenderer (later also a MeshFilter and MeshRenderer) and a script to create my mesh. Creating the mesh works fine but i have to major problems. The first is that the lightning does not work correctly when using CanvasRenderer instead of MeshRenderer:
My second problem is that no matter the order in the hierarchy as soon as i add a second object to my canvas (e.g. an image with the color white) my custom mesh and its color are no longer visible. Only the white image.
Here is the script i used. The last few lines are comments or not based on what Renderer i tried.
using UnityEngine;
public class MeshCanvas : MonoBehaviour
{
public Material material;
Mesh mesh;
Vector3[] vertices;
int[] triangles;
float canvasHeigt;
float canvasWidth;
private void Update()
{
canvasHeigt = FindObjectOfType<Canvas>().GetComponent<RectTransform>().rect.height;
canvasWidth = FindObjectOfType<Canvas>().GetComponent<RectTransform>().rect.width;
vertices = new Vector3[]
{
new Vector3(0, 0),
new Vector3(0, canvasHeigt),
new Vector3(canvasWidth, canvasHeigt),
new Vector3(canvasWidth, 0)
};
triangles = new int[]
{
0, 1, 2,
2, 3, 0
};
mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
/*
this.GetComponent<MeshFilter>().mesh = mesh;
this.GetComponent<MeshRenderer>().material = material;
*/
CanvasRenderer cr = this.GetComponent<CanvasRenderer>();
cr.SetColor(Color.black);
cr.materialCount = 1;
cr.SetMaterial(material, 0);
cr.SetMesh(mesh);
}
}
For problem 1: If you just want a normal unlit UI element, you should be using the UI/Default material, not a Standard material.
If you do want lighting, In your Canvas properties, set 'Additional Shader Channels' to 'Everything'. Otherwise lighting will not be calculated correctly. You can use a Standard material in this case, or one of the UI/Lit materials.
As for problem 2, I'm not sure. Unity batches all UI elements together for performance reasons, so maybe setting the mesh directly on the CanvasRenderer is breaking the batching, or maybe it's to do with the material you're using.
If you just want to be able to add your own custom 2D shapes to a Canvas, the better way is to make a class that derives from Graphic or MaskableGraphic and override the OnPopulateMesh method to provide your custom mesh vertices.
The advantages here are that it will behave like any other UI element with all the same parameters etc. and you can add it to the Create GameObject menus to easily add it to your scene.

How to know coloring is complete on the sprite?

I am trying to make color game in that there are three object border, 3d cube, and a pointer(tube), here i'm painting a 3d cube with a pointer by changing its texture and put a sprite on the cube so i want to detect the condition while i almost complete the coloring inside the sprite border how can i do that in unity?
Like in this image
I want to know how to detect almost complete coloring within the boundry sprite.
To detect if the coloring inside the sprite border is almost complete, you can use a combination of Unity's built-in collision detection and image processing techniques. Something like this:
First create a sprite mask on the sprite border to mask the cube image. This will allow you to apply an effect to only the area inside the border.
Then sample the color of each pixel inside the border using the GetPixels method of the Texture2D class. Store these values in an array.
Calculate the average color of all the pixels in the array.
Compare the average color to a pre-defined threshold color to determine if the coloring is complete. If the average color is close enough to the threshold color, you can assume that the coloring is complete.
Repeat steps 2-4 in a loop while the player is painting the cube to continuously check if the coloring is complete.
Once the coloring is complete, you can trigger an event or perform some other action in your game.
using UnityEngine;
public class ColorDetection : MonoBehaviour
{
public SpriteRenderer spriteRenderer;
public Texture2D maskTexture;
public Color thresholdColor;
private void Update()
{
Color averageColor = GetAverageColor();
if (IsColorSimilar(averageColor, thresholdColor))
{
Debug.Log("Coloring is complete");
}
}
private Color GetAverageColor()
{
Texture2D texture = spriteRenderer.sprite.texture;
Rect spriteRect = spriteRenderer.sprite.rect;
Color[] maskPixels = maskTexture.GetPixels();
Color[] spritePixels = texture.GetPixels((int)spriteRect.x, (int)spriteRect.y, (int)spriteRect.width, (int)spriteRect.height);
int count = 0;
Color sum = Color.clear;
for (int i = 0; i < maskPixels.Length; i++)
{
if (maskPixels[i].a > 0)
{
count++;
sum += spritePixels[i];
}
}
return sum / count;
}
private bool IsColorSimilar(Color a, Color b)
{
float delta = 0.05f;
return Mathf.Abs(a.r - b.r) < delta && Mathf.Abs(a.g - b.g) < delta && Mathf.Abs(a.b - b.b) < delta;
}
}

How to draw a 2D plot on a plane in Unity 3D?

I have a plane game object on the 3D scene and I want to plot 2D graph z=f(x)=sin kx (btw, MathJaX does not work in this site), for example, on it. I am very new to Unity, could you tell me what should I do?
There are three ways to show a plot.
you create a bunch of small gameobjects and piece together lines,
you create a Texture2D, and draw into it.
When leaving Unity a litte, call Texture.GetNativeTexturePtr() and use D3D calls for this.
I think the 2 is what you might use best.
3. is leaving Unity a little and will not port across target platforms.
It leaves up to you how to do graphics on it. Using only SetPixel is not a really big graphics API.
Here's an example how to load a texture with graphics drawn at runtime.
To use it, create an object, don't forget to assign a material, and attach this script.
using UnityEngine;
public class DrawTex : MonoBehaviour
{
Material mat;
Texture2D tx;
void Start()
{
MeshRenderer rend;
rend = GetComponent<MeshRenderer>();
UnityEngine.Assertions.Assert.IsNotNull(rend);
mat = rend.material;
UnityEngine.Assertions.Assert.IsNotNull(mat);
tx = new Texture2D(128,128,TextureFormat.ARGB32,true);
// draw stuff.
for(int y=0;y<128;y++)
{
for(int x=0;x<128;x++)
{
float a,r,g,b;
r=g=b=a=0f;
if( x<20 || y<20 || x>108 || y>108 )
{a=1.0f;r=g=b=0.75f;}
else
{a=0.5f;r=b=0.25f+(x/256.0f);g=0.25f+(y/256.0f);}
tx.SetPixel(x,y,new Color(r,g,b,a));
}
tx.Apply(true); // now really load all those pixels.
}
mat.mainTexture = tx;
}
}
Hope this helps.

paint polygon collider during gameplay

I'm working on a 2D game in which some objects have a triangular vision, done with a polygon collider
Is it possible to paint this collider so that it is visible during the gameplay?
Assuming your mean PolygonCollider2D and that it always has 3 points in the correct order I guess you could do something like
using System.Linq;
...
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter), typeof(PolygonCollider2D))]
public class MeshCreator : MonoBehaviour
{
void Awake ()
{
var points = GetComponent<PolygonCollider2D>().points;
var meshFilter = GetComponent<MeshFilter>();
var mesh = new Mesh();
// Just a shorthand for something like
//var list = new List<Vector3>();
//foreach(var p in points)
//{
// list.Add(p);
//}
//mesh.vertices = list.ToArray();
mesh.vertices = points.Select(p -> (Vector3) p).ToArray();
// Here create two triangles (each 3 vertices)
// just because I don't know if you have the points in the correct order
mesh.triangles = new int[]{0,1,2,0,2,1};
meshFilter.mesh = mesh;
}
}
and put this component next to the PolygonCollider2D. It will then replace this Object's mesh with the triangle.
The material you can already set beforehand in the MeshRenderer.
For getting this overlap area the simplest solution would be Semi-Transparent materials. Otherwise you might need a special shader.

How to set correct color to lines?

I'm working on my first game in Unity.
I'm trying to draw lines on my game field.
Code:
private void DrawLine(Vector3 start, Vector3 stop, GameObject template)
{
GameObject toInstiateGridLine = template;
GameObject gridLineInstance = Instantiate(toInstiateGridLine, start, Quaternion.identity) as GameObject;
LineRenderer gridLineRenderer = gridLineInstance.GetComponent<LineRenderer>();
gridLineRenderer.SetVertexCount(2);
gridLineRenderer.SetWidth(0.01f, 0.01f);
gridLineRenderer.SetColors(Color.black, Color.black);
gridLineRenderer.SetPosition(0, start);
gridLineRenderer.SetPosition(1, stop);
}
It works with one problem. I get pink lines instead of black that I expect.
Settings of LineRenderer component that has been created in runtime:
You are missing material. Pink is the standard color when material is missing.
LineRenderer gridLineRenderer = gridLineInstance.GetComponent<LineRenderer>();
Material mat = new Material(Shader.Find("Unlit/Texture"));
gridLineRenderer.material = mat;
Or, you can change material color directly. As I consider, calling directly will cause to create standard default material
gridLineRenderer.material.color = Color.white;