material.SetColor doesn't work PC/Android build - unity3d

This script works as follows: when I raycast an object, it fades out.
Script works great in the Unity Play Mode.
But objects dont wanna fade out on PC/Android build. Just nothing happen, but raycast is detecting object (problem not in raycast)
I debugged Android/PC and script is going into SetMaterialProperties method
Standard material, default new project, default scene, simple capsule gameObject, nothing specific
Because of what could this be?
private IEnumerator FadeIn()
{
Color objectColor = GetComponent<MeshRenderer>().material.color;
while (objectColor.a < 1)
{
float fadeAmount = objectColor.a + (_fadeSpeed * Time.deltaTime);
objectColor = new Color(objectColor.r, objectColor.g, objectColor.b, fadeAmount);
SetMaterialProperties(objectColor);
yield return null;
}
}
private void SetMaterialProperties(Color color)
{
foreach (var material in _materials)
{
material.SetColor("_Color", color);
material.SetFloat("_Mode", 3);
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.EnableKeyword("_ALPHABLEND_ON");
material.renderQueue = 3000;
}
}

Related

Unity - Set player position after loading scene

I am Trying to set player position after loading a scene. The program runs ok sometimes, but sometimes it places the player in the wrong position.
This is a video showing this strange behaviour: https://youtu.be/MFl9P3taV0Y
This is the code:
public class IniciaHeroi : MonoBehaviour
{
public GameObject GM;
private int startPosition;
void Awake()
{
startPosition = GM.GetComponent<StartScene>().startPosition;
if(startPosition == 1)
{
transform.position = new Vector3(119,4.67f,36);
transform.GetComponent<HeroiMovimento>().rot = -30;
Debug.Log("StartPosition1: " + transform.position);
}
if(startPosition == 2)
{
transform.position = new Vector3(49,13.8f,167);
transform.GetComponent<HeroiMovimento>().rot = 100;
Debug.Log("StartPosition2: " + transform.position);
}
}
}
Debug log shows always the correct position but, as you can see in the video, something changes the position.
Can anyone point the correct way to do this?
The problem was the Character controller attached to my player. For some strange reason Character Controller do not change its own transform.position when i change player transform.position.
So the solution is to disable Character Controller before change player position and Enable it after the change.
Thanks!! Having the same issue, and took me so long to find this. Finally I was able to solve by using disabling the Controller and then enabling it:
example:
gameObject.GetComponent<CharacterController>().enabled = false;
gameObject.transform.position = new Vector3(-31, 1, -10);
gameObject.GetComponent<CharacterController>().enabled = true;

TrailRenderer start point on click

I followed Brackeys tutorial on how to create a Fruit Ninja Replica (youtube).
When creating the blade, though, the behaviour I got wasn't exactly the same.
Expected behaviour
Actual behaviour
The difference is that in the Actual behaviour, the trail starts where it stopped the last time it was shown. The code responsible for this is exactly the same as the video:
public class BladeController : MonoBehaviour
{
bool isCutting = false;
public GameObject bladeTrailPrefab;
GameObject currentBlade;
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0)) {
StartCutting();
} else if (Input.GetMouseButtonUp(0)) {
StopCutting();
}
if (isCutting) {
UpdateCut();
}
}
void UpdateCut()
{
GetComponent<Rigidbody2D>().position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
void StartCutting()
{
isCutting = true;
this.currentBlade = Instantiate(bladeTrailPrefab, transform);
}
void StopCutting()
{
isCutting = false;
Destroy(currentBlade, 1f);
}
}
After understanding the code, I thought the problem was that I instantiated the bladeTrail before actually moving the Blade to the new position, but tried moving the Instantiate method to UpdateCut after changing the position and only if this.currentBlade == null.
I've search a lot about this, and even found some other posts with the same problem but no answer.
It seams the Instantiate is using the last mouse position to instiantiate the prefab.
Maybe use:
Instantiate(bladeTrailPrefab, Camera.main.ScreenToWorldPoint(Input.mousePosition), Quaternion.identity)
I ran into this problem following the tutorial as well.
It's a few years later but for those of you who hit this page, I found a solution for me that while isn't fantastic, it's better than having the streaks shown in the post.
Before instantiating the trail vfx, make sure to wait until fixed update is called after you set the position of the parent transform.
I did this with a Coroutine like so:
private IEnumerator StartCutting()
{
// When we begin cutting, move the blade object to the input position
m_isCutting = true;
m_previousPosition = m_camera.ScreenToWorldPoint(Input.mousePosition);
m_rigidBody.position = m_previousPosition;
// Then for positions to be updated so that the vfx doesn't get confused
yield return m_waitForFixedUpdate; // new WaitForFixedUpdate(); <-- cache this
// Instantiate the trail at this new position
m_currentTrail = Instantiate(m_trailPrefab, m_rigidBody.transform);
m_collider.enabled = false;
}

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>();

How do I change GameObject properties in scripts Unity?

I'm trying to save/load my game. In the load method, everytime I change the properties of a GameObject, those changes are applied and then get reverted shortly after. Here is my code:
public void Load()
{
SceneManager.LoadScene(sceneID);
List<GameObject> rootObjects = new List<GameObject>();
Scene scene = SceneManager.GetActiveScene();
scene.GetRootGameObjects(rootObjects);
int ncube = 0, npick = 0;
for (int i = 0; i < rootObjects.Count; ++i)
{
GameObject obj = rootObjects[i];
if (obj.CompareTag("Player"))
{
obj.transform.position = player.position;
obj.transform.rotation = player.rotation;
obj.transform.localScale = player.localScale;
}
else if (obj.CompareTag("Cube"))
{
obj.transform.position = cube[ncube].position;
obj.transform.rotation = cube[ncube].rotation;
obj.transform.localScale = cube[ncube].localScale;
++ncube;
}
else if (obj.CompareTag("Pickup"))
obj.SetActive(pickup[npick++]);
else if (obj.CompareTag("Door"))
obj.SetActive(door);
else if (obj.CompareTag("GreenWall"))
obj.SetActive(greenWall);
}
}
Those changes are applied to the GameObject, however they get aborted right away. How can I resolve this?
The script contains these lines of code is not a component of the GameObject.
Edit 1: Complete code updated.
Problem is I think that
Scene scene = SceneManager.GetActiveScene();
scene.GetRootGameObjects(rootObjects);
gets the objects from the scene before the Scene is fully loaded so they are reset.
From the Docu
When using SceneManager.LoadScene, the loading does not happen immediately, it completes in the next frame. This semi-asynchronous behavior can cause frame stuttering and can be confusing because load does not complete immediately.
I guess you rather should use SceneManager.sceneLoaded and do your stuff there like
public void Load()
{
SceneManager.LoadScene(sceneID);
}
And maybe in an extra component within the scene:
void OnEnable()
{
SceneManager.sceneLoaded += OnSceneLoaded;
}
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
// your stuff here
}
void OnDisable()
{
SceneManager.sceneLoaded -= OnSceneLoaded;
}
though we don't know/see where player, cube[ncube] etc come from ...
for transparting values between Scenes you should get into using ScriptableObjects
The problem might be that SceneManager.LoadScene completes in the next frame. See the documentation: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html
It says:
When using SceneManager.LoadScene, the loading does not happen
immediately, it completes in the next frame. This semi-asynchronous
behavior can cause frame stuttering and can be confusing because load
does not complete immediately.
You change the values within the same frame, thus they are overwritten when loading the scene finishes. Cou could use an event to prevent that behaviour: https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager-sceneLoaded.html

Unity: Applying MoveRotation to an object with an offset

In a Unity VR app I'm building, I'm trying to rotate an object that is currently 'being held'. The technique I'm using is to find the desired rotation and feed it into the target objects Rigidbody via Rigidbody.MoveRotation. This works well when I use a test quaternion exposed in the inspector, but my quaternion math is completely failing me when it comes to finding the target rotation I want. I've got the position tracking working perfectly, it's just the rotation thats killing me!
The desired outcome is that the target object in question keeps its current rotation (from the moment its picked up) and simply applies the frame-by-frame difference of the VR controller. I thought this would be pretty straight forward, but I'm getting strange results. This is what I have so far:
public Rigidbody targetRigidbody;
public Quaternion controllerRotationSnapshot;
public Quaternion targetRotationSnapshot;
public float grabRadius = 0.25f;
public Collider[] grabResults;
Quaternion deltaRotation;
void Awake() {
grabResults = new Collider[5];
}
// This is triggered externally
public void Pickup() {
Physics.OverlapSphereNonAlloc(transform.position, grabRadius, grabResults);
for (int i = 0; i < grabResults.Length; i++) {
if (grabResults[i] != null) {
if (grabResults[i].CompareTag("Grabbable")) {
targetRigidbody = grabResults[0].GetComponent<Rigidbody>();
targetRotationSnapshot = targetRigidbody.transform.rotation;
i = grabResults.Length;
}
}
}
controllerRotationSnapshot = transform.rotation;
}
public void LetGo() {
if (!targetRigidbody) {
return;
}
targetRigidbody = null;
grabResults = new Collider[5];
}
void FixedUpdate() {
if (!targetRigidbody) {
return;
}
Quaternion deltaRotationDifference = transform.rotation * Quaternion.Inverse(controllerRotationSnapshot);
targetRigidbody.MoveRotation(targetRotationSnapshot * deltaRotationDifference);
}
It works perfectly as long as the target object is at a rotation of 0,0,0 (in euler angles). But the moment the target object is picked up with a different rotation at all (i.e. [X: 20, Y: -5, Z: 325] or something), the frame-by-frame controller difference (a 'delta rotation' I've heard this called?) gets applied on a completely different axis. It's very confusing because as far as I can tell, nothing about my code is applied locally, it's all using global calculations?
I've done a lot of Googlin' and can't find an answer at all, any help is greatly appreciated.