Changing the color of a gameobject shows as white not the colour requested - unity3d

I have a set of gameobjects (simple cubes). I can set their initial colour when instantiating them. However when I try and change the colour by code, the object in the game view and inspector show as white, but in the colour picker show the correct colour!
There is a single directional light (the default one).
IEnumerator ColourChange()
{
Color targetColour = new Color(Random.Range(0, 255), Random.Range(0, 255), Random.Range(0, 255));
Debug.Log("color = " + targetColour);
for (int x = 0; x < CreateCubeGrid.GRIDSIZE; x++) {
for (int z = 0; z < CreateCubeGrid.GRIDSIZE; z++) {
CreateCubeGrid.cubeGrid[x,z].GetComponent<Renderer>().material.color = targetColour;
}
yield return new WaitForSeconds (0.05f);
}
}

Colours are 0 to 1 not 0 to 255.
Use Color32 if you want to use 0-255 values.
Color32 Documentation

In order to change the material's color, you must tell it exactly what color you're trying to change, by using Shader.Find("_YourColor") (Emission, Albedo, etc).
An approach that should work for materials using Standard Shader can be seen below:
private void ChangeColor(Color color)
{
//Fetch the Renderer from the GameObject.
Renderer rend = GetComponent<Renderer>();
//Find and set the main Color ("_Color") of the Material to the new one
rend.material.shader = Shader.Find("_Color");
rend.material.SetColor("_Color", color);
}
You can read more about changing a Material's color at Unity's Documentation.

Related

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;
}
}

Unity material.color.a code is not working

void OnTriggerStay(Collider other)
{
if (other.gameObject.CompareTag("tree"))
{
Color color = other.gameObject.GetComponent<Renderer>().material.color;
color.a = 0.5f;
}
}
If an object with a "tree" tag enters the camera's trigger, I want the opacity of that object to be 0.5. But didn't worked. How can i fix this? Thanks.
While the other two answers are technically correct, you are most likely missing a very important step to allow for the changing of the alpha of a Material. I'll take a guess and assume you generated a new Material in the Editor by using the Asset Creation Menu. By default, the Material RenderMode is set to Opaque.
To allow for changes of the Material color's alpha, you will need to set the RenderMode either to Transparent or Fade. If you are working with a custom shader, you will need to alter the code to format to one of the mentioned RenderTypes. If you need help modifying your shader, that would best be answered in a new question.
For clarity, here is a gif of what the confusion might be:
Edit: For completeness, here is a full script that will toggle the RenderMode of your material at runtime if you do not wish to change it at compile time.
using UnityEngine;
public static class MaterialUtils
{
public enum BlendMode
{
Opaque,
Cutout,
Fade,
Transparent
}
public static void SetupBlendMode(Material material, BlendMode blendMode)
{
switch (blendMode)
{
case BlendMode.Transparent:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
material.SetFloat("_Mode", 3.0f);
break;
case BlendMode.Opaque:
material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
material.SetFloat("_Mode", 0.0f);
break;
default:
Debug.LogWarning("Warning: BlendMode: " + blendMode + " is not yet implemented!");
break;
}
}
}
[RequireComponent(typeof(MeshRenderer))]
public class TestScript : MonoBehaviour
{
[SerializeField] private MeshRenderer mr = null;
[SerializeField] private float alphaChange = 0.5f;
private bool isOpaque = true;
private void Awake()
{
if (mr == null)
mr = GetComponent<MeshRenderer>();
}
private void OnMouseDown()
{
// store our color struct and change the alpha channel
Color clr = mr.material.color;
clr.a = alphaChange;
// instance our material to alter the rendermode
Material mat = mr.material;
// update our render mode to transparent and our color to the new alpha
MaterialUtils.SetupBlendMode(mat, isOpaque ? MaterialUtils.BlendMode.Transparent : MaterialUtils.BlendMode.Opaque);
mat.color = clr;
// apply our material change
mr.material = mat;
// toggle our bool
isOpaque = !isOpaque;
}
}
Your original question does not state whether or not you need to toggle the material back to opaque, but I included it. You can keep the RenderMode as Transparent and simply change the alpha back to 1.0f to make it fully opaque again. Again, here's a gif example of the above script in action:
To show that the snippet is working, I place 2 spheres behind the cubes. The snippet is probably a bit overkill for what you need, but if someone else stumbles on the question and needs a more versatile answer here it is!
Color is just a struct and basically just a container of values without further functionality. It is not linked to the Material it was taken from.
By assigning only
color.a = XY;
you do nothing yet.
You have to assign it back to the material!
void OnTriggerStay(Collider other)
{
if (!other.CompareTag("tree")) return;
var material = other.GetComponent<Renderer>().material;
var color = material.color;
color.a = 0.5f;
material.color = color;
}
You're not really setting the color with the code you wrote.
Color color = other.gameObject.GetComponent<Renderer>().material.color;
color.a = 0.5f;
With the first line you take the color from the object and with the second you set the opacity. But you don't assign it back to the object. You can assign the color back to the object and it should work:
other.gameObject.GetComponent<Renderer>().material.color = color;

TextMeshPro Text colors reset when moved

I've been struggling with this issue for a while now-
Essentially I have a TMP_Text object. Then (like in TMP example 23), I am setting the character's vertices colors to a specified color. However, when I move the TMP_Text object, all of the character's colors get reset.
Here is the relevant code that sets character color as well as a video displaying this behavior:
private void ChangeColor(int i, Color32 c)
//changes color of the letter that is # specific index to a color32
//this is getting called elsewhere in the script
{
int materialIndex = tf_.characterInfo[i].materialReferenceIndex;//get characters material index
cols = tf_.meshInfo[materialIndex].colors32;//get its colors
int vertexIndex = tf_.characterInfo[i].vertexIndex;//get its vertex index
cols[vertexIndex + 0] = c;//set vertex color to C
cols[vertexIndex + 1] = c;// ^
cols[vertexIndex + 2] = c;// ^
cols[vertexIndex + 3] = c;// ^
ms_.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
//update the vertex data to render the new colors
}
public void scrollContent()//this moves the TMP_Text object
{
sr.verticalNormalizedPosition = 0;//scroll the rect to the bottom
//performing this^ movement changes the objects position, thus resetting all the colors.
}
}

Name of this selectable scroll in unity editor?

As you can see in the picture, "Layout0" is selected with dark blue color.
I want to make this box too in my custom editor, but what I actually found is that this is not EditorGUILayout.BeginScrollView and other whatever stuffs.
could someone please tell me the keyword of this selectable box?
I am not entirely sure how the highlighting works but here's how I think it's implemented.
Make a scrollable view using GUILayout.BeginScrollView
Make a vertical view, but with help box style GUILayout.BeginVertical(EditorStyles.helpBox)
For the highlighting, create a blue texture and assign it to a GUIStyle, which you then use for the button. Do this on Awake so you only do this once.
Texture2D texture = new Texture2D(1, 1);
for(int x = 0; x < 1; x++)
{
for(int y = 0; y < 1; y++)
{
texture.SetPixel(x, y, Color.blue);
}
}
texture.Apply();
this.selectedStyle = new GUIStyle();
this.selectedStyle.normal.textColor = Color.white;
this.selectedStyle.normal.background = texture;
Change the buttons to label buttons GUILayout.Button("name", currentSelected ? this.selectedStyle : GUIStyle.label)

Is there any way to make some rectangular areas of a mask to be transparent?

I am using UGUI to make a Novice guide to guide people to play my game.
And need the whole UI be mask, but some rectangular areas to be lighted.
How to do?
Create a new gameobject and add a image component to it. Create a image with transparent areas where you want your ui to be visible. Assign that image to the image component. Then add a mask component
Put your other gui elements inside this gameobject so that is could overlap and hide everything except transparent areas. Here is the picture of demo setup.
IMHO, what you want to achieve is not easy to be done perfectly in Unity. Here is my personal solution:
I put a black panel below every other GUI, so that it darkens my entire screen.
I put an empty game object called BrightRoot below the panel, so that everything under BrightRoot will float over and "brightened".
In my tutorial script, I add function to look for a UI game object by name and change its parent to the BrightRoot. In example:
// To brighten the object
GameObject button = GameObject.Find("PlayButton");
Tansform oldParent = button.transform.parent;
button.transform.SetParent(BrightRoot, true);
// To darken it again
button.transform.SetParent(oldParent, true);
The perfect solution would be to write a UI shader that darken any pixel outside some rectangles and brighten the inside. Then set that shader to all UI objects.
Editted:
This just another easy method, using UI Vertex effect. Just need to implement IsPointInsideClipRect, put this component to your UI objects, and set the rectangles list:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
[AddComponentMenu("UI/Effects/Clip")]
public class Clip : BaseVertexEffect
{
// We need list of rectangles here - can be an array of RectTransform
public RectTransform[] ClipRects;
public override void ModifyVertices(List<UIVertex> vertexList)
{
if (!IsActive())
{
return;
}
bool isClipped = true;
for (int i = 0; i < count; i++)
{
UIVertex uiVertex = vertexList[i];
foreach (RectTransform rect in ClipRects)
{
if (IsPointInsideClipRect(rect, uiVertex.position))
{
isClipped = false;
break;
}
}
}
Color32 color = isClipped ? new Color32(0.5f, 0.5f, 0.5f, 0.5f) : new Color(1.0f, 1.0f, 1.0f, 1.0f);
for (int i = 0; i < count; i++)
{
UIVertex uiVertex = vertexList[i];
uiVertex.color = color;
}
}
private static bool IsPointInsideClipRect(RectTransform rect, Vector3 position)
{
// ...
}
}