Unity material.color.a code is not working - unity3d

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;

Related

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

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.

Take Screenshot Before any ARCore model is rendered

I'm using Screenshot code to take a screenshot of the screen which is working fine but its also taking the arcore models with it. Is there a way to take a screenshot before models are rendered?
I tried to SetActive(false) then take a screenshot then SetActive(true), it does work but there's a noticeable difference i.e. model disappears than reappears.
Update: This is a script applied on ScreenShotCamera and it is updated after removing all the bugs (thanks to #Shingo), feel free to use it it's working properly
using GoogleARCore;
using OpenCVForUnitySample;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
[RequireComponent(typeof(Camera))]
public class SnapshotCamera : MonoBehaviour
{
Camera snapCam;
public UnityEngine.UI.Text text;
public RenderTexture mRenderTexture;
int resWidth=480;
int resHeight=800;
// Start is called before the first frame update
public void initialize(ARBackgroundRenderer background, Material material)
{
background = new ARBackgroundRenderer();
snapCam = GetComponent<Camera>();
background.backgroundMaterial = material;
background.camera = snapCam;
background.mode = ARRenderMode.MaterialAsBackground;
if (snapCam.targetTexture == null)
{
snapCam.targetTexture = new RenderTexture(resWidth, resHeight, 24);
}
else
{
snapCam.targetTexture.height = resHeight;
snapCam.targetTexture.width = resWidth;
//resHeight = snapCam.targetTexture.height;
//resWidth = snapCam.targetTexture.width;
}
background.camera.cullingMask = LayerMask.NameToLayer("Default");
//snapCam.CopyFrom(background.camera);
snapCam.gameObject.SetActive(false);
}
public void TakeSnapShot()
{
snapCam.gameObject.SetActive(true);
}
void LateUpdate()
{
if (snapCam.gameObject.activeInHierarchy)
{
snapCam.cullingMask = LayerMask.NameToLayer("Default");
if (ARCoreBackgroundRenderer.screenShot == null)
ARCoreBackgroundRenderer.screenShot = new Texture2D(resWidth, resHeight, TextureFormat.RGB24, false);
snapCam.Render();
RenderTexture.active = snapCam.targetTexture;
ARCoreBackgroundRenderer.screenShot.ReadPixels(new Rect(0, 0, resWidth, resHeight), 0, 0);
ARCoreBackgroundRenderer.screenShot.Apply();
snapCam.gameObject.SetActive(false);
HandPoseRecognition.captureTexture = false;
//string name = string.Format("{0}_Capture{1}_{2}.png", Application.productName, "{0}", System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
//UnityEngine.Debug.Log("Permission result: " + NativeGallery.SaveImageToGallery(ARCoreBackgroundRenderer.screenShot, Application.productName + " Captures", name));
}
}
}
Perhaps I was a little ambiguous, what u mentioned in the comment has already been resolved thanks to you but the problem now is.
I'll show you the images:
These are the 2 cameras I have:
This is what my Main (ARCore Camera) shows
And this is what the (ScreenShot Camera) Shows
You can use layer, put every arcore models in one layer (eg. ARLAYER), then set camera's culling mask to avoid these models.
Pseudo code:
// Set models' layer
foreach (GameObject arcoreModel in arcoreModels)
arcoreModel.layer = ARLAYER;
// Set camera's culling mask
camera.cullingMask = ~(1 << ARLAYER);
camera.Render();
Create screenshot camera from another camera
var go = new GameObject("screenshotcamera");
// Copy transform
go.transform.position = mainCamera.transform.position.
...
// Copy camera
var screenshotcamera= go.AddComopnent<Camera>();
screenshotcamera.CopyFrom(mainCamera);
Update with your script
snapCam = GetComponent<Camera>();

Using CoRoutine Unity 3D Buttons

I'm currently making a quiz game that has three buttons, from an object pool, and I want them to turn green or red depending on whether or not they are the correct answer. This works perfectly.
When I add the coRoutine to change the button back to clear so the next question can be answered, the button almost never changes color after clicking and essentially nothing happens. Would really appreciate any help!! Thank you.
public void HandelClick()
{
var colors = GetComponent<Button> ().colors;
if( ! answerData.isCorrect)
{
colors.normalColor = Color.red;
GetComponent<Button>().colors = colors;
}
else
{
colors.normalColor = Color.green;
GetComponent<Button> ().colors = colors;
playerMovement.dodge();
}
StartCoroutine("Revert");
//gameController.AnswerButtonClicked(answerData.isCorrect);
}
IEnumerator Revert()
{
Debug.Log(" we are reverting " + Time.time);
yield return new WaitForSeconds(1.8f);
Debug.Log(" we are reverting again " + Time.time);
var colors = GetComponent<Button> ().colors;
colors.normalColor = Color.clear;
GetComponent<Button> ().colors = colors;
gameController.AnswerButtonClicked(answerData.isCorrect);
}
Changing the colors works as you said (you can see that in the Inspector of the Button)
The problem is that the Image component's color doesn't get updated automatically since the Button isn't receiving any pointer event like PointerDown, PointerExit etc => the new color is not applied to the Image (only in the cases where you do a new pointer event like enter, exit, up or down).
You could solve this by doing
GetComponent<Image>().color = colors.normalColor;
additional everywhere you change it.
Note: In general you should use GetComponent only once in Awake
private Button _button;
private Image _image;
private void Awake()
{
_button = GetComponent<Button>();
_image = GetComponent<Image>();
}
and than reuse the references _image and _button

Cannot modify a value type return value of `UnityEngine.Material.color' for changing alpha of gameobject

I'm having trouble with this, although this is just for improvement for my code I can make the gameobject change it's alpha I just want it simpler.
here is my code:
SpriteRenderer go;
Color colora;
float x = 0f;
void Start () {
go = GetComponent<SpriteRenderer> ();
}
// Update is called once per frame
void Update () {
colora = new Color(255f,255f,255f,.5f);
go.material.color.a = colora.a;
}
this is the error one. just to make this code simpler.
Color is a struct and it is valueType.
go.material.color // it will return a copy of Color
You have to make another instance of Color then assign back to go.material.color
go.material.color = new Color(255f,255f,255f,.5f);

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)
{
// ...
}
}