Unity3D: Change skybox color via script? - c#

I am working on a game in the engine Unity, and am trying to make the skybox change color based on the time of day, but I can't seem to find out how to get it working.. What I want to do, I think, is to change the color of the material I use for the skybox in render settings, and be able to set it using one variable for red, one for green and one for blue.
I am using C#.
Thanks in advance for all answers :)

From the code you displayed in the comment:
RenderSettings.skybox.SetColor("_Tint", 0, 0, blue)
I think you mean
RenderSettings.skybox.SetColor("_Tint", Color.blue)
no need for extra zeros and remember that the color "blue" is a member variable of the Color class.
Next you would have to develop a time system and based on the time var you pass to the script controlling the skybox renderer you would then use a Lerp function to smoothly transition from one color to the next... like this
using UnityEngine;
using System.Collections;
public class example : MonoBehaviour {
public Color colorStart = Color.blue;
public Color colorEnd = Color.green;
public float duration = 1.0F;
void Update() {
float lerp = Mathf.PingPong(Time.time, duration) / duration;
RenderSettings.skybox.SetColor("_Tint", Color.Lerp(colorStart, colorEnd, lerp));
}
}
Then you could write a function to change the colorStart and colorEnd...
Hope this helps...

We can change Skybox color using the _Tint property. RenderSettings is the base class used to change the render properties at run time. For ensuring the attribute is existing in the skybox is done by the HasProperty(). SetColor() is used to set the color of the skybox.
if (RenderSettings.skybox.HasProperty("_Tint"))
RenderSettings.skybox.SetColor("_Tint", Color.red);
else if (RenderSettings.skybox.HasProperty("_SkyTint"))
RenderSettings.skybox.SetColor("_SkyTint", Color.red);

you can make your own skybox too in unity by changing texture shape into a cube one then apply for those changes it will create a cube mesh which you can simply drop it into your unity editor scree.
and if you want to load multiple skybox materials on run time by click on button
I have that code for that i hope it will help you for building a project in which you want to change skybox by some time or by using other input method.
enter code here
public class skybox : MonoBehaviour {
enter code here
public Material[] secondSkybox;
public static int i = 0;
public void skyboxOn()
{
if (i == 0) {
RenderSettings.skybox = secondSkybox[0];
i++;
}
else if(i==1)
{
RenderSettings.skybox = secondSkybox[1];
i++;
}else if(i==2)
{
RenderSettings.skybox = secondSkybox[2];
i=0;
}
}
}

and if you want too change the color of skybox which can be done by using this line of code
RenderSettings.skybox.SetFloat ("_Exposure", Mathf.Sin (Time.time * Mathf.Deg2Rad * 100) + 2);

Related

Unity color wont assign to ball or what it should be painting

private Color solveColor;
void Start()
{
Color[] colors = { Color.cyan, Color.red, Color.green, new Color(245, 195, 29), Color.yellow, Color.magenta };
int lengthOfColors = colors.Length;
int solveColor = UnityEngine.Random.Range(0, lengthOfColors);
}
private void start()
{
GetComponent<MeshRenderer>().material.color = solveColor;
}
private void FixedUpdate()
{
// Set the balls speed when it should travel
if (isTraveling) {
rb.velocity = travelDirection * speed;
}
// Paint the ground
Collider[] hitColliders = Physics.OverlapSphere(transform.position - (Vector3.up/2), .05f);
int i = 0;
while (i < hitColliders.Length)
{
GroundPiece ground = hitColliders[i].transform.GetComponent<GroundPiece>();
if (ground && !ground.isColored)
{
ground.Colored(solveColor);
}
The above code is supposed to pick one color from the colors array and assign it to both the ball and balls painting ability (whenever the ball collides with the ground it changes its color) however the paint the ball leaves is always black and the ball itself is always orange (pretty sure the ball color is coming from its default). I can't figure out why this is happening any help is very appreciated.
Thank you for your time
In the code you provided, nowhere do you set the material color of the ball again aside from Start. If you want to have the particles behind the ball leave different colors, you will need to instantiate a new instance of the material. The reason for this is because materials in Unity are default shared between all instances of that particular material.
All of this info and a bit more can be found on the Material docs page.
As you have a fixed size of colors you are using, I would instead create 6 new materials and make an array of materials instead. Now, instead of randomly picking a color, pick a material and assign it to the ball or your new instanced painting ability. I am also confused as to why you are placing your array of colors inside of your Start function. It would be localized to that function only then. You also appear to have two Start functions, which is odd. One being the Monobehaviour Start and another start. Unless that is intended, your second start will not be run unless you call it.
Now to get to the solution I was talking about.
// assign these in the inspector to your new materials
[SerializeField] private List<Material> materials = new List<Material>();
private MeshRenderer meshRender;
private void Start()
{
meshRenderer = GetComponent<MeshRenderer>();
// set our first random Material
SetNewMaterialColor();
}
private void SetNewMaterialColor()
{
meshRenderer.material = GrabNewMaterial();
}
private void FixedUpdate()
{
// Set the balls speed when it should travel
if (isTraveling) {
rb.velocity = travelDirection * speed;
}
// Paint the ground
Collider[] hitColliders = Physics.OverlapSphere(transform.position - (Vector3.up/2), .05f);
int i = 0;
while (i < hitColliders.Length)
{
GroundPiece ground = hitColliders[i].transform.GetComponent<GroundPiece>();
if (ground && !ground.isColored)
{
// change this from a color to a material instead
ground.Colored(meshRenderer.material);
// set a new material to your main object
SetNewMaterialColor();
}
}
}
private Material GrabNewMaterial()
{
return materials[UnityEngine.Random.Range(0, materials.Count)];
}
You will need to change your Colored function to take in a Material instead of a Color. If you want the implementation to be more dynamic, you can instead create an instance of your material and set the color dynamically, but as you have a fixed size of colors I do not think you need to do that.
Edit: The one other option which involves creating a new shader would be to utilize [PerRendererData] meaning each object for a property field is rendered individually. I would go with the previous option as either option using shaders or instanced materials is a bit more complex.
You would need to use a MaterialPropertyBlock and can then assign the color when you want. It would look something like
public void SetNewColor()
{
// create a new material property block
MaterialPropertyBlock tmpBlock = new MaterialPropertyBlock();
// grab the current block from our renderer
meshRender.GetPropertyBlock(tmpBlock);
// set our changes to the block
tmpBlock.SetColor("_Color", YourColorHere);
// now apply our changes
tmpRend.SetPropertyBlock(tmpBlock);
}
And you would need to create a new shader that laters the Main Color property by using the PerRendererData attribute.
Properties
{
[PerRendererData]_Color("Main Color", Color) = (1,1,1,1)
...
Also, one other question I have is why you are using Physics.OverlapSphere instead of just an OnCollisionEnter? Or if your game is 2D, then OnCollisionEnter2D and let the physics engine handle how collisions work, then just change the colors when the collision occurs?
Edit: Here are the answer to your questions - let me know if you have more.
In the line "[SerializeField] private List materials = new
List();" which section do I need to replace with the
materials and how?
The line as is is fine. By using [SerializeField] it exposes this list to the editor. You will want to create several new duplicate materials that use your 6 different colors. Instead of setting the colors, you will be setting materials now. What I mean by inspector and editor is you can find the object that has this script on it in Unity, select it (it must be a Prefab or in the scene), then a tab of the Unity editor will populate with information about this object. Find the script portion and find the field materials. There should be a drop-down arrow, click it and set the number to 6 (or however many material swaps you want). Now create 6 new materials with your colors and drag them into the boxes that appeared.
Would it be something like writing "./Materials/Ball 1" in the () for
example?
Nope! You would be assigning this data in the inspector, so the data would be stored in the list without referencing them in code.
And I'm not sure how to assign this to my ball using "[SerializeField]
private GameObject paintObject = null;"
Similarly, this would appear in the inspector. However, remove this line as I misunderstood your original question and accidentally left this in. I assumed that your paint object was a Prefab that you were spawning after the ball bounced, not the ground that you were changing the color of.
I get the error "Argument 1: cannot convert from
'UnityEngine.Material' to 'UnityEngine.Color'"
Yep! So as I mentioned in the comments, your function call to your paint object is most likely currently taking a Color parameter. As I changed your implementation to instead directly set Material, you will need to change how that function signature. Specifically the line:
ground.Colored(meshRenderer.material);
You have some object ground that is of type GroundPiece and has a function called Colored. I assume it currently look something like:
public void Colored(Color color){...}
You want to change this instead to:
public void Colored(Material mat{...}
After changing it, instead of changing the ground's color in this script, you would change its material directly. Let me know if you have more questions.

How do I get the texture to scroll on my sprite?

I have a large sprite on my screen but I want the image it displays to scroll infinitely horizontally.
I have the current code which does not have any effect at all.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjLayer : MonoBehaviour
{
public float Speed = 0;
public int layer = 0;
protected Material _material;
protected float currentscroll = 0f;
// Start is called before the first frame update
void Start()
{
_material = GetComponent<SpriteRenderer>().material;
}
// Update is called once per frame
void Update()
{
currentscroll += Speed * Time.deltaTime;
var currentOffset=_material.GetTextureOffset("Layer3");
_material.SetTextureOffset("Layer3", new Vector2(currentscroll, 0));
_material.mainTextureOffset = new Vector2(currentscroll, 0);
}
}
Just to note that I am setting both SetTextureOffset and mainTextureOffset as neither seem to be working.
Also currentOffset is changing as expected but the texture is not moving on the screen.
You are most likely using a Material that doesn't support texture offsetting, unless the property is HiddenInInspector you can check in the inspector if your material supports it by checking if it has the Offset x,y input fields underneath "Texture"
The standard Unlit/Texture shader has this property, so do any newly created UnlitShaders (as seen in my example screenshot).
If you are using a custom shader then your Texture isn't named "_MainTex", which is the property that Unity looks for when using mainTextureOffset, as cited from the docs:
By default, Unity considers a texture with the property name name "_MainTex" to be the main texture.
Using material.mainTextureOffset works fine for me when using a shader where the Texture is called _MainTex:
public Vector2 offset;
private Material material;
private void Start()
{
material = GetComponent<MeshRenderer>().material;
}
private void Update()
{
material.mainTextureOffset = offset;
}
Result (Gyazo gif)
In your example
_material.SetTextureOffset("Layer3", new Vector2(currentscroll, 0));
You are looking for a property named "Layer3" in your shader, this is not a name that is standard in use by Unity (in my knowledge), if you are using a custom shader then make sure your Texture property has the name Layer3 inside your shader.
Update after OP's comment:
Tiling and Offsetting is not available to Materials on a SpriteRenderer, Sprites are assumed to not be offset. As indicted by the warning given by Unity when you try to add a material that has Tiling/Ofsetting in its texture
Material texture property _MainTex has offset/scale set. it is incompatible with spriterenderer
Instead use a Quad, Plane, Image or raw Image component which does have support for materials with tiling/offsetting in combination with the above code.
I think technically it is still possible to use offsetting with sprites by throwing on a shader that support it and ignoring the warning, but I can not guarantee this won't break down the line or what the performance implications are

Change the Color for One of Many of the Same GameObject

I have a space shooter where players can select a color for their ships, and this applies to the bullets the ships shoot as well. The ships use the same bullet prefab, so I would like to change the color of the bullet once it's created in the game. I originally used the following code to change the color.
Material bulletMat = this.GetComponent<MeshRenderer>().sharedMaterial;
if (bulletMat != null)
{
bulletMat.SetColor("_TintColor", color);
}
However, I found out that this will change the color of the material and the bullets would switch in between colors with each bullet created. After doing some more research, I came accross the MaterialPropertyBlock variable and the following tutorial http://thomasmountainborn.com/2016/05/25/materialpropertyblocks/. So I followed this tutorial and setup the following code.
public Renderer renderer;
public MaterialPropertyBlock matBlock;
public Color color;
public bool colorSet = false;
void Awake()
{
renderer = this.GetComponent<Renderer>();
matBlock = new MaterialPropertyBlock();
}
public void ColorSet(Color color)
{
this.color = color;
this.colorSet = true;
}
void Update()
{
if (this.colorSet)
{
renderer.GetPropertyBlock(matBlock);
matBlock.SetColor("_Color", this.color);
renderer.SetPropertyBlock(matBlock);
}
}
However, the same issue as the previous solution happened....
Can someone help me figure out how to set the color for each individual bullet?
You use sharedMaterial only wherever you really want to change the material for every Object using this material. That's exactly what you don't want to do. Instead you ahve to use material so you only change a "clone" instance of the material.
Unity actually automatically instantiates a local copy of the current material only for that object if you do:
public class ColorChanger : MonoBehavior
{
private MeshRenderer meshRenderer;
private void OnEnable()
{
meshRenderer = GetComponent<MeshRenderer>();
}
public void SetColor(Color newColor)
{
renderer.material.color = newColor;
}
}
or using SetColor as you had it should do the same I guess
public void SetColor(Color newColor)
{
renderer.material.SetColor("_TintColor", newColor);
}
I personally find the before metnioned one easier. But the second one gives you more control since you can e.g. also change the emitColor which is not possible on another way.
Now when you instantiate your bullets make sure you first instantiate the prefab and than change the color using the component above:
public GameObject bulletPrefab;
public Color myColor;
public GameObject Hand;
private void Shoot()
{
// There are various ways for Instantiate e.g. providing start position and rotation or also the parent object
// Since it shall be fired from the player I'll assume here there is a "Hand" object from which you want to fire
// and that you want to add the bullet directly to the hierarchy without a parrent
GameObject newBullet = Instantiate(bulletPrefab, Hand.position, Hand.rotation);
// Now we get the color change component
ColorChanger colorChanger = newBullet.GetComponent<ColorChanger>();
// And set the color
colorChanger.SetColor(myColor);
}
Note:
In case this is a multiplayer game the bullets should be Instantiated only on the Server so you'ld have to first let the server know which color the bullet shall be and than also provide this information back to all players after you Network.Spawn them.
You don't need to keep updating the property block. Once is enough. You've also got to make sure that the material allows instancing, and that the shader supports instancing of "_Color". On the standard and sprite materials, you'll find that at the bottom of the inspector window for the material.
So, you can remove the test in Update, and modify the ColorSet method. In fact, on a Bullet type object, I'd be inclined to make it as lean as possible (ideally move all functionality to a central bullet manager, but that's off topic).
public void ColorSet(Color color)
{
renderer.GetPropertyBlock(matBlock);
matBlock.SetColor("_Color", color);
renderer.SetPropertyBlock(matBlock);
}
If this isn't helping, are you grabbing a bullet from a pool, which already has colours set on the objects? Is it simply a case that you're not setting the correct colour on already instantiated objects?
I'm also questioning why renderer.material didn't work (or if you ever tried it?). But, it's my understanding/guess that setting a new material actually breaks instancing. So you might actually get better performance from setting the property block anyway.

Fading Alpha Values In Unity?

I am making a game for Android using Unity 5.4.0f3 and am having trouble fading out a sprite's color.a value. I have tried animations, but they don't seem to work for me. I have tried using the code from here and here, but those didn't work either. I want the sprite to fade out over about 1 second when it is tapped. I think I need to use a for loop and Mathf.Lerp. Please help.
Edit: Here is an image of the Inspector view of the object I want to fade out.
Sure change sprRender.color, not color.a. Simple code for you, Fadeout worked. Add your advanced.
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(SpriteRenderer))]
public class FadeOut : MonoBehaviour {
SpriteRenderer sprRender;
void Start()
{
sprRender = GetComponent<SpriteRenderer>();
}
void Update()
{
sprRender.color -= new Color(0, 0, 0, Time.deltaTime);
}
}
Because Sprite-Default material is NOT modifiable.
Try this instead:
Easiest way:
/* Modify SpriteRenderer.color instead of Material.color */
//Get the renderer via GetComponent or have it cached previously
var renderer = GetComponent<SpriteRenderer>();
renderer.color = new Color(0f, 0f, 0f, 0f); // Do your lerping stuff with this property
If you still want to modify Material
Create a new material in Project tab and name it whatever you
want. Project tab -> Create -> Material.
Assign it a shader like in the below image.
Assign the newly created material to your Sprite Renderer
Material slot. Notice that now you can modify material color from
the inspector. It has not been grayed out any more. You should run
you code again and it should work.

How can I decrease opacity in unity?

I see this subject in stack over flow but I think it is false
Making an object 'transparent' so it cannot be seen is not the most efficient way to do things. What you rather want to do is make the renderer inactive when you don't want to see it, and active when you do.
If you click on your gameObject in the editor, there should be a Mesh Renderer as one of the components.
To set it to inactive from a script attached to this same gameObject, you can do this...
gameObject.GetComponent<Renderer> ().enabled = false;
If you really want to use transparency, you can do this...
gameObject.GetComponent<Renderer> ().material.color.a = 0;
Although if you are setting transparency, you need to make sure the shader the material is using supports transparency. I would suggest using the Legacy Shaders/Transparent Diffuse shader.
How I can use:
gameObject.GetComponent<Renderer> ().material.color.a = 0;
For those who might still come across this question, gameObject.GetComponent<Renderer> ().material.color is not a variable. Create a variable as such:
var trans = 0.5f;
var col = gameObject.GetComponent<Renderer> ().material.color;
Then assign your value:
col.a = trans;
Also be aware that not all shaders have a _Color property. In my case, I had to use:
var col = gameObject.GetComponent<Renderer> ().material.GetColor("_TintColor");
How I can use:
gameObject.GetComponent<Renderer> ().material.color.a = 0;
As you already stated in your own question, the object you call this on must have a shader which supports transparency. In Unity5, when using the standard shader, you must explicitly set it to "Transparent" to be able to manipulate the alpha value.
It should also be clear to you that the alpha value is a float which goes from 0.0f to 1.0f, so e.g. setting
gameObject.GetComponent<Renderer> ().material.color.a = 0.5f;
will make the object 50% transparent.
Select your material and change its Rendering Mode to Transparent.
Then, add the below script.
using UnityEngine;
public class MakeTransparent : MonoBehaviour
{
public GameObject currentGameObject;
public float alpha = 0.5f;//half transparency
void Start()
{
currentGameObject = gameObject;
}
void Update()
{
ChangeAlpha(currentGameObject.GetComponent<Renderer>().material, alpha);
}
void ChangeAlpha(Material mat, float alphaVal)
{
Color oldColor = mat.color;
Color newColor = new Color(oldColor.r, oldColor.g, oldColor.b, alphaVal);
mat.SetColor("_Color", newColor);
}
}
Change the alpha value in the inspector on runtime.
Here is the video explanation.
Try in this way
var other : GameObject;
other.renderer.material.color.a = 0.5f; // 50 % transparent
other.renderer.material.color.a = 1.0f; // 100% visible

Categories