After adding an implementation of a PostProcessEffectRenderer to the Unity post-processing stack the effect works perfectly in the Unity Editor, but does not show in the built game.
Changes to build quality have no effect, effect does not show using maximum quality settings, building for Windows x86_64.
Grayscale.cs
using System;
using UnityEngine;
using UnityEngine.Rendering.PostProcessing;
[Serializable]
[PostProcess(typeof(GrayscaleRenderer), PostProcessEvent.AfterStack, "Custom/Grayscale")]
public sealed class Grayscale : PostProcessEffectSettings
{
[Range(0f, 1f), Tooltip("Grayscale effect intensity.")]
public FloatParameter blend = new FloatParameter { value = 0.5f };
}
public sealed class GrayscaleRenderer : PostProcessEffectRenderer<Grayscale>
{
public override void Render(PostProcessRenderContext context)
{
var sheet = context.propertySheets.Get(Shader.Find("Hidden/Custom/Grayscale"));
sheet.properties.SetFloat("_Blend", settings.blend);
context.command.BlitFullscreenTriangle(context.source, context.destination, sheet, 0);
}
}
Grayscale.shader
Shader "Hidden/Custom/Grayscale"
{
HLSLINCLUDE
#include "Packages/com.unity.postprocessing/PostProcessing/Shaders/StdLib.hlsl"
TEXTURE2D_SAMPLER2D(_MainTex, sampler_MainTex);
float _Blend;
float4 Frag(VaryingsDefault i) : SV_Target
{
float4 color = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, i.texcoord);
float luminance = dot(color.rgb, float3(0.2126729, 0.7151522, 0.0721750));
color.rgb = lerp(color.rgb, luminance.xxx, _Blend.xxx);
return color;
}
ENDHLSL
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
HLSLPROGRAM
#pragma vertex VertDefault
#pragma fragment Frag
ENDHLSL
}
}
}
After much trial and error I realised that this was caused by Unity excluding the hidden shader as it lacked a reference to anything in the game at build time. On build Unity will only include shaders either attached to a material in use in a scene or those added in project settings in the 'Always Included Shaders' array.
I tried both and it solved my problem, it has been suggested that creating a dummy object within your game referencing the hidden shader will work better as it leaves Unity to decide if it's needed in a scene or not. Either way this fixed it for me.
Related
TextMesh Pro shaders have two unusual facilities for adjusting the Textures used for both the Face and the Outline: Tiling and Offset.
They're not accessible via the normal ways of using keywords to access shader properties in Unity.
Is it possible to access these properties from Monobehaviours? How?
If you're wanting to see sample code... there's little point... as I've tried all the normal ways of accessing shader properties in Unity and found none of them work, all throwing errors relating to symbols not existing. Or returning nulls.
These properties are somewhat nested, somehow.
If you've ever successfully edited these values with a Script in Unity, you'll likely know that they're a bit different.
Within the Shader files for TextMesh Pro, these values are known as:
float4 _FaceTex_ST;
float4 _OutlineTex_ST;
Note, the .x and .y of these float4 are the scaling/tiling along their respective axis, whilst .z and .w are used for their offsets.
Depending a bit on which shader exactly you use - for now assuming one of the built-in ones like e.g. TextMeshPro/Distance Field (Surface) you can search for the shader e.g. in Assets/TextMeshPro/Shaders, select the Shader and now see which properties are exposed in the Inspector.
In that case it would be the _FaceTex texture.
Now the Tiling and Offset are indeed quite tricky since they store those directly along with the Texture property itself! You can see his when setting the Inspector to Debug mode with the TextMeshPro selected
=> You want to use Material.SetTextureOffset and Material.SetTextureScale (= Tiling) with the property name of the texture itself
yourTextMeshPro.fontMaterial.SetTextureScale("_FaceTex", new Vector2(42, 42));
yourTextMeshPro.fontMaterial.SetTextureOffset("_FaceTex", new Vector2(123, 456));
The Tiling and Offset have no effect for the Outline apparently. See e.g. Distance Field (Surface) Shader.
Outline
...
Tiling: ????
Offset: ????
You could still try though and do the same just with _OutlineTex
Thanks to the incomparable derHugo, the resultant code works perfectly, in both directions:
using TMPro;
using UnityEngine;
public class testMaterailProps : MonoBehaviour {
public Vector2 FaceTiling;
public Vector2 FaceOffset;
public Vector2 OutLineTiling;
public Vector2 OutlineOffset;
public Material myFontMaterial;
TextMeshPro myTexmMeshPro;
static readonly int FaceTex = Shader.PropertyToID( "_FaceTex" );
static readonly int OutlineTex = Shader.PropertyToID( "_OutlineTex" );
void Start ( ) {
myTexmMeshPro = GetComponent<TextMeshPro>( );
myFontMaterial = myTexmMeshPro.fontSharedMaterial;
FaceTiling = myFontMaterial.GetTextureScale( FaceTex );
FaceOffset = myFontMaterial.GetTextureOffset( FaceTex );
OutLineTiling = myFontMaterial.GetTextureScale( OutlineTex );
OutlineOffset = myFontMaterial.GetTextureOffset( OutlineTex );
}
void OnValidate ( ) {
myFontMaterial.SetTextureScale( FaceTex, FaceTiling );
myFontMaterial.SetTextureOffset( FaceTex, FaceOffset );
myFontMaterial.SetTextureScale( OutlineTex, OutLineTiling );
myFontMaterial.SetTextureOffset( OutlineTex, OutlineOffset );
}
}
Making it possible to copy text styles accurately from one text object to another, since a bug in the copy/paste of Unity properties prevents these values being copy-able through the Editor UI...
I'm making a simple game, and i have an idea about one of the items for player. If player picks the item, the screen starts to wave (distort), but i can't do that. I found a shader which distorts the image, but it distorts it permanently and works only on one picture, not the whole scene. Also i tried to use Camera.SetReplacementShader, but everything becomes just light blue and that's all.
Any ideas appreciated!
The code of the shader is down below:
Shader "Custom/NewShader" {
Properties {
_MainTex ("Base (RGB)", 2D) = "transparent" {}
_SpeedX("SpeedX", float)=3.0
_SpeedY("SpeedY", float)=3.0
_Scale("Scale", range(0.005, 0.2))=0.03
_TileX("TileX", float)=5
_TileY("TileY", float)=5
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Lambert
sampler2D _MainTex;
float4 uv_MainTex_ST;
float _SpeedX;
float _SpeedY;
float _Scale;
float _TileX;
float _TileY;
struct Input {
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o)
{
float2 uv = IN.uv_MainTex;
uv.x += sin ((uv.x+uv.y)*_TileX+_Time.g *_SpeedX)*_Scale;
uv.x += cos (uv.y*_TileY+_Time.g *_SpeedY)*_Scale;
half4 c = tex2D (_MainTex, uv);
o.Albedo = c.rgb * 4;
o.Alpha = c.a * 4;
}
ENDCG
}
FallBack "Diffuse"
}
You can use Post Processing Effects to solve this. It is Unity's "visual enchancement" package, basically an instagram filter for your game camera. You can change the visuals of your game completely using this package.
Setup:
Go to Unity > Window > Package Manager
Select Unity Registry on the top and type in the search bar "Post Porcessing"
Download and Import the package
Go to a gameObject and add the component post-process Volume
And then go to your Main Camera and add the component post-process Layer
On post-process Volume create a New Profile and give the gameObject a new Layer ("PostProcessing" perhaps)
On the post-process layer (in your camera) again select the Layer you assigned
You are all set. You can now go back to the post-process Volume component and press "Add Effect" and play around with the various effects to create the one you want.
This works for both 2D/3D, if there is a camera this will work.
I need to set a variable of a shader without a material that wraps around it.
I'll explain the problem and why it's not like the question "How can I access shader variables from script?".
Problem
My shader is similar to this (99% of irrelevant boilerplate code removed):
Shader "Hidden/XShader"
{
Properties
{
_x ("", float) = 0
}
SubShader
{
Pass
{
float _x;
half4 frag(v2f i) : SV_Target
{
// "col" and "wpos" have been correctly defined
if (wpos.x >= _x)
{
col.r = 1;
} else {
col.r = 0;
}
return col;
}
}
}
}
This shader is set through the Edit->Project Settings->Graphics->Deferred option. It is the default shader that the main camera uses.
Now I need to set the _x value from code attached to the camera:
public class XCameraController : MonoBehaviour
{
public float x;
void Update()
{
<something>.SetFloat("_x", x);
}
}
The <something> placeholder would normally be a material, as SetFloat() is defined there. But the camera and shader do not have a material. The concept of material doesn't even apply to the default shader.
I've searched online and in the documentation for hours. I admit I failed and am at a loss here. I guess it must be simple but I can't find any documentation.
I don't expect an implemented solution, a pointer where I can find help will suffice!
But the camera and shader do not have a material. The concept of
material doesn't even apply to the default shader.
True but materials simply exposes all properties from a shader so it is relevant here since you want to change the shader properties.
You have a custom shader but that's not used to render a GameObject but the camera. A material is still needed to change the shader. If you don't want to use a material then you can use the Shader.SetGlobalXXX functions such as Shader.SetGlobalFloat("_x", 3) but it will change all the shader properties. This is unrealistic.
The proper way to do this is to create a temporary material you will use to modify the shader, change the shader properties, then update the shader the camera is using. To do this, you have to:
Find the shader or get a reference of the shader with a public variable:
Shader camShader = Shader.Find("Hidden/XShader");
Create material from the shader
Material camMat = new Material(camShader);
Modify the property as you wish
camMat.SetFloat("_x", 3);
Apply to the modified shader property to the camera
Camera.main.SetReplacementShader(camShader, "RenderType");
If you're manually rendering the camera then use Camera.main.RenderWithShader(camShader, "RenderType") instead of Camera.main.SetReplacementShader(camShader, "RenderType").
I am trying to create particles emission for my objects which are actually pawns in a chess game. I changed particles material using Inspector for particle system and it works fine, however, when I try to change it with a script, nothing happens (particles stay pink for the black pawn).
I am not sure what is wrong with the script, whether it's a change of material problem or maybe I need to set the path for material. I would be glad if someone suggested a solution!
Here is the script:
public class BlackPawnParticleSystem : MonoBehaviour
{
private Material m_Material;
private ParticleSystemRenderer psr;
private void Start()
{
var ps = GetComponent<ParticleSystem>();
m_Material = GetComponent<Renderer>).material;
psr = GetComponent<ParticleSystemRenderer>);
psr.material = Resources.GetBuiltinResource<Material>("BlackBishop.mat");
}
This is how it looks like:
EDIT:
Changes in code:
public class BlackPawnParticleSystem : MonoBehaviour
{
private Material m_Material;
private ParticleSystemRenderer psr;
private void Start()
{
var ps = GetComponent<ParticleSystem>();
m_Material = GetComponent<Renderer>().material;
psr = GetComponent<ParticleSystemRenderer>();
psr.material = Resources.Load<Material>("BlackBishop");
}
Location of my materials:
Inspector for the material:
Script attached to the object:
The problem is this line: Resources.GetBuiltinResource<Material>("BlackBishop.mat")
It is returning null. The Resources.GetBuiltinResource function is used to load resources that are built-in into Unity not ones created by you. For example, "Sprites-Default.mat". There is no build-in material named "BlackBishop.mat" so it returns null.
To load material you created, use rhe Resources.Load function.
First, create a folder called "Resources" then put your "BlackBishop.mat" material there. You can now load it as below:
Resources.Load<Material>("BlackBishop");
Notice how I did not include ".mat" in the name. You don't include the extension name when using the Resources.Load function. If you do, it will not find it.
EDIT:
But still nothing happens on my game scene
Please carefully:
1.Like I said in my original answer, you must create a folder named "Resources" and must put the "Black Bishop" material inside that folder. You have not done this and it should not work. The spellings of thisfolder must be correct so copy it directly from this answer. Again, it should be named "Resources".
2.Your material is named "Black Bishop" not "BlackBishop" . See the space. Please fix this in the code. That should be Resources.Load<Material>("Black Bishop"); not Resources.Load<Material>("BlackBishop");.
3.Your material is currently using the "Standard" shader. Change that to Particle shader. You can do that by selecting the Material and changing the shader from "Standard" to "Particles/Alpha Blended Premultiply". That's it. Your problem should now be solved.
Extra:
I noticed you are using folders to organize your resources. Your "Black Bishop.mat" is inside Arcane Cyber --> Chess --> Materials --> Pieces --> Plastic. I suggest you move the "Materials" folder to the "Resources" folder created in #1 above.
Now, your "Black Bishop.mat" should be inside Assets --> Resources --> Materials --> Pieces --> Plastic.
You can now load it as:
Resources.Load<Material>("Materials/Pieces/Plastic/Black Bishop");
If you still have problems, please update your code and new Inspector images again. Remember that spellings count.
Why not just make a SerializedField with the Materials you need? If you don't want materials and trails to be random, set them to the exact spot in the array you need for the situation.
I did it like this:
using UnityEngine;
public class CorrectParticles : MonoBehaviour
{
private static ParticleSystem correctPart;
private static ParticleSystemRenderer correctRend;
public static CorrectParticles Instace;
[SerializeField] Material[] mainMaterials;
[SerializeField] Material[] trailMaterials;
private void Awake()
{
Instace = this;
}
void Start()
{
correctPart = GetComponent<ParticleSystem>();
correctRend = GetComponent<ParticleSystemRenderer>();
correctPart.Stop();
}
public void StartParticles()
{
int mainMaterial = Random.Range(0, mainMaterials.Length);
correctRend.material = mainMaterials[mainMaterial];
int trailMaterial = Random.Range(0, trailMaterials.Length);
correctRend.trailMaterial = trailMaterials[trailMaterial];
correctPart.Play();
}
public void StopParticles()
{
correctPart.Stop(withChildren: true, stopBehavior: ParticleSystemStopBehavior.StopEmittingAndClear);
}
}
Then I can start and stop the particle system as needed on other scripts.
CorrectParticles.Instace.StartParticles();
or
CorrectParticles.Instace.StopParticles();
So my professor gave our class code to look over to help us learn about Vector3D drawing, positioning, and movement. The code was originally written in XNA 3.1, and our lab here at school is still in XNA 3.1, however, I do everything on my laptop. My laptop has Visual Studio 2012 (I have 2013 but haven't moved XNA over yet). I have figured out and fixed all but one of the errors. I keep getting this error whenever I debug and run the game:
Error 1 Errors compiling C:\Users\Nicholas\Documents\Visual Studio 2013\Projects\MGH05_PrimitiveObjects\MGH05_PrimitiveObjects\Content\Shaders\PositionColor.fx:
C:\Users\Nicholas\Documents\Visual Studio 2013\Projects\MGH05_PrimitiveObjects\MGH05_PrimitiveObjects\Content\Shaders\PositionColor.fx(27,6): error X3000: syntax error: unexpected token 'VertexShader' C:\Users\Nicholas\Documents\Visual Studio 2013\Projects\MGH05_PrimitiveObjects\MGH05_PrimitiveObjects\Content\Content\Shaders\PositionColor.fx 27 6 MGH05_Win_PrimitiveObjects
My professor has been of no help, and neither has google. Anyone have any idea how to fix this? Here is the shader (PositionColor.fx) code:
float4x4 wvpMatrix : WORLDVIEWPROJ;
struct VSinput
{
float4 position : POSITION0;
float4 color : COLOR0;
};
struct VStoPS
{
float4 position : POSITION0;
float4 color : COLOR0;
};
struct PSoutput
{
float4 color : COLOR0;
};
// alter vertex inputs
void VertexShader(in VSinput IN, out VStoPS OUT)
{
// transform vertex
OUT.position = mul(IN.position, wvpMatrix);
OUT.color = IN.color;
}
// alter vs color output
void PixelShader(in VStoPS IN, out PSoutput OUT)
{
float4 color = IN.color;
OUT.color = clamp(color, 0, 1); // range between 0 and 1
}
// the shader starts here
technique BasicShader
{
pass p0
{
// declare & initialize ps & vs
vertexshader = compile vs_1_1 VertexShader();
pixelshader = compile ps_1_1 PixelShader();
}
}
When I rename VertexShader I still get the error, but now with PixelShader. When I rename them both it still gives me the VertexShader error.
If anyone has any thoughts let me know! Also, I apologize if this was asked on the wrong stack website. I'd think this one would be the proper place. If you need any extra info, let me know!
Thanks in advance!
As Romoku suggested, it would appear that XNA 4 uses a newer/different shader version, in which some new keywords have been added. This includes PixelShader and VertexShader, so those may no longer be used as identifiers.
The solution would be to give them some other name (any will do). Also remember to update the names in the technique.
void FancyVertexShader(in VSinput IN, out VStoPS OUT)
{
// transform vertex
OUT.position = mul(IN.position, wvpMatrix);
OUT.color = IN.color;
}
// alter vs color output
void AwesomePixelShader(in VStoPS IN, out PSoutput OUT)
{
float4 color = IN.color;
OUT.color = clamp(color, 0, 1); // range between 0 and 1
}
// the shader starts here
technique BasicShader
{
pass p0
{
// declare & initialize ps & vs
vertexshader = compile vs_2_0 FancyVertexShader();
pixelshader = compile ps_2_0 AwesomePixelShader();
}
}
Edit: and as you pointed out yourself, XNA 4 uses version 2.0 for both the vertex and the pixel shader.