Writing a shader that allows both opaque and transparent blending
Hey! So I am trying to write a custom shader that will allow for both regular opaque rendering and transparency. This will be controlled in the editor, much like the standard shader. My problem now though is that it doesn't seem to take into account anything from the alpha channels for color(neither from albedo map or just color picker). When I turn on the transparency mode, it just because vaguely transparent, and does not respond to changes in the alpha channels. This is my shader code:
Shader "Custom/ArcheryEmissive" {
Properties {
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", 2D) = "black" {}
_NormalMap ("Normals", 2D) = "bump"{}
_AOMap("Ambient Occlusion",2D) = "white"{}
_Cutoff ("Alpha Cutoff", Range (0.0, 1.0)) = 0.5
//Adding the Emissive maps
_Emissive1 ("Primary Emissive", 2D) = "black"{}
_EmissionIntensity ("Intensity", Range(0,3)) = 1.0
_Emissive2 ("Secondary Emissive", 2D) = "black"{}
_Tween ("Transition", Range(0,1)) = 0.0
// Blending state
[HideInInspector] _Mode ("__mode", Float) = 0.0
[HideInInspector] _SrcBlend ("__src", Float) = 1.0
[HideInInspector] _DstBlend ("__dst", Float) = 0.0
[HideInInspector] _ZWrite ("__zw", Float) = 1.0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 300
Blend [_SrcBlend] [_DstBlend]
ZWrite [_ZWrite]
CGPROGRAM
// Physically based Standard lighting model, and enable shadows on all light types
#pragma surface surf Standard fullforwardshadows
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTPIY_ON
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 3.0
sampler2D _MainTex;
sampler2D _Metallic;
sampler2D _NormalMap;
sampler2D _AOMap;
sampler2D _Emissive1;
sampler2D _Emissive2;
struct Input {
float2 uv_MainTex;
float2 uv_Metallic;
float2 uv_NormalMap;
float2 uv_AOMap;
float2 uv_Emissive1;
float2 uv_Emissive2;
};
half _Glossiness;
fixed4 _Color;
fixed _Cutoff;
float _EmissionIntensity;
float _Tween;
void surf (Input IN, inout SurfaceOutputStandard o) {
// Albedo comes from a texture tinted by color
fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
o.Albedo = c.rgb;
// Metallic and smoothness come from slider variables
o.Metallic = tex2D (_Metallic, IN.uv_Metallic);
fixed smooth = _Glossiness * tex2D(_Metallic, IN.uv_Metallic).a;
o.Smoothness = smooth;
//Adding normal maps
o.Normal = UnpackNormal (tex2D(_NormalMap, IN.uv_NormalMap));
//Ambient Occlusion
o.Occlusion = tex2D(_AOMap, IN.uv_AOMap);
//emission mapping and the transition between two maps
float3 Em1 = tex2D(_Emissive1, IN.uv_Emissive1).rgb;
float3 Em2 = tex2D(_Emissive2, IN.uv_Emissive2).rgb;
o.Emission = c.rgb * lerp(Em1, Em2, _Tween) * _EmissionIntensity;
o.Alpha = c.a;
}
ENDCG
}
FallBack "VertexLit"
CustomEditor "CustomShaderGUI"
}
so for this to work I have also made a custom shader GUI:
using System;
using UnityEngine;
using UnityEditor;
public class CustomShaderGUI : ShaderGUI {
private enum WorkflowMode {
Metallic
}
//Setting up the different Blend modes for the shader
public enum BlendMode {
Opaque,
Transparent
}
//Setting up the tooltip texts
private static class Styles {
public static GUIStyle optionsButton = "PaneOptions";
public static GUIContent uvSetLabel = new GUIContent ("UV Set");
public static GUIContent[] uvSetOptions = new GUIContent[]{new GUIContent("UV Channel 0"), new GUIContent ("UV Channel 1")};
public static string emptyTooTip = "";
public static GUIContent albedoText = new GUIContent("Albedo", "Albedo (RGB) and Transparency (A)");
public static GUIContent alphaCutoffText = new GUIContent ("Alpha Cutoff", "threshold for Alpha cutoff)");
public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map");
public static GUIContent metallicMapText = new GUIContent ("Metallic Map", "Metallic (RGB) and Smoothness (A)");
public static GUIContent metallicGlossText = new GUIContent ("Smoothness", "Smooth intensity as defined by Metallic Alpha");
public static GUIContent occlusionMapText = new GUIContent ("AO Map", "Ambient Occlusion Map");
public static GUIContent emissiveMapText = new GUIContent ("Primary Emission Map", "Primary Emission Map");
public static GUIContent emissionStrengthText = new GUIContent ("Intensity", "Intensity of the emission map");
public static GUIContent emissiveMapSecondaryText = new GUIContent ("Secondary Emission Map", "Secondary Emission Map");
public static GUIContent emissionTweeningText = new GUIContent ("Emission map transition", "Transition between the two emission maps");
//FIXME
public static string whiteSpaceString = " ";
public static string primaryMapsText = "Main Maps";
public static string renderingMode = "Rendering Mode";
public static readonly string[] blendNames = Enum.GetNames(typeof (BlendMode));
}
MaterialProperty blendMode = null;
MaterialProperty albedoMap = null;
MaterialProperty albedoColor = null;
MaterialProperty alphaCutoff = null;
MaterialProperty metallicGloss = null;
MaterialProperty metallicMap = null;
MaterialProperty normalMap = null;
MaterialProperty occlusionMap = null;
MaterialProperty emissiveMap = null;
MaterialProperty emissiveMapSecondary = null;
MaterialProperty emissionStrength = null;
MaterialProperty emissionTween = null;
MaterialEditor m_MaterialEditor;
WorkflowMode m_WorkflowMode = WorkflowMode.Metallic;
ColorPickerHDRConfig m_ColorPickerHDRConfig = new ColorPickerHDRConfig(0f, 99f, 1/99f, 3f);
bool m_FirstTimeApply = true;
public void FindProperties (MaterialProperty[] props) {
blendMode = FindProperty ("_Mode", props);
albedoMap = FindProperty ("_MainTex", props);
albedoColor = FindProperty ("_Color", props);
alphaCutoff = FindProperty ("_Cutoff", props);
normalMap = FindProperty ("_NormalMap", props);
occlusionMap = FindProperty ("_AOMap", props);
metallicGloss = FindProperty ("_Glossiness", props);
metallicMap = FindProperty ("_Metallic", props);
emissiveMap = FindProperty ("_Emissive1", props, false);
emissionStrength = FindProperty ("_EmissionIntensity", props, false);
emissiveMapSecondary = FindProperty ("_Emissive2", props, false);
emissionTween = FindProperty ("_Tween", props, false);
}
public override void OnGUI (MaterialEditor materialEditor, MaterialProperty[] props) {
FindProperties (props);
m_MaterialEditor = materialEditor;
Material material = materialEditor.target as Material;
if (m_FirstTimeApply) {
MaterialChanged (material, m_WorkflowMode);
m_FirstTimeApply = false;
}
ShaderPropertiesGUI (material);
}
//Setting up the workspace for the different maps, except those with more advanced setup
public void ShaderPropertiesGUI (Material material) {
EditorGUIUtility.labelWidth = 0f;
EditorGUI.BeginChangeCheck (); {
BlendModePopup ();
//Maps
GUILayout.Label (Styles.primaryMapsText, EditorStyles.boldLabel);
DoAlbedoArea (material);
m_MaterialEditor.TexturePropertySingleLine (Styles.occlusionMapText, occlusionMap);
m_MaterialEditor.TexturePropertySingleLine (Styles.normalMapText, normalMap);
DoMetallicArea (material);
DoEmissionArea (material);
}
if (EditorGUI.EndChangeCheck()) {
foreach (var obj in blendMode.targets)
MaterialChanged ((Material)obj, m_WorkflowMode);
}
}
//Dropdown menu for the blendmodes
void BlendModePopup () {
EditorGUI.showMixedValue = blendMode.hasMixedValue;
var mode = (BlendMode)blendMode.floatValue;
EditorGUI.BeginChangeCheck ();
mode = (BlendMode)EditorGUILayout.Popup (Styles.renderingMode, (int)mode, Styles.blendNames);
if (EditorGUI.EndChangeCheck()) {
m_MaterialEditor.RegisterPropertyChangeUndo ("Rendering Mode");
blendMode.floatValue = (float)mode;
}
EditorGUI.showMixedValue = false;
}
// Setting up the Albedo workspace
void DoAlbedoArea (Material material){
m_MaterialEditor.TexturePropertySingleLine (Styles.albedoText, albedoMap, albedoColor);
}
//Setting up the Metallic workspace
void DoMetallicArea (Material material) {
int indenation = 2;
m_MaterialEditor.TexturePropertySingleLine (Styles.metallicMapText, metallicMap);
m_MaterialEditor.ShaderProperty (metallicGloss, Styles.metallicGlossText, indenation);
}
//Setting up the Emissive workspace with both intensity and transition slider
void DoEmissionArea (Material material){
int indenation = 2;
bool hasPrimaryMap = false;
bool hasSecondaryMap = false;
m_MaterialEditor.TexturePropertySingleLine (Styles.emissiveMapText, emissiveMap);
if (emissiveMap != null) {
hasPrimaryMap = true;
}
if (emissiveMapSecondary != null) {
hasSecondaryMap = true;
}
if (hasPrimaryMap) {
m_MaterialEditor.ShaderProperty (emissionStrength, Styles.emissionStrengthText, indenation);
m_MaterialEditor.TexturePropertySingleLine (Styles.emissiveMapSecondaryText, emissiveMapSecondary);
}
if (hasSecondaryMap) {
m_MaterialEditor.ShaderProperty (emissionTween, Styles.emissionTweeningText, indenation);
}
}
//Switching between the Opaque and Transparent mode in the shader
public static void SetupMaterialWithBlendMode (Material material, BlendMode blendMode) {
switch (blendMode) {
case BlendMode.Opaque:
material.SetOverrideTag ("RenderType", "Opaque");
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;
break;
case BlendMode.Transparent:
material.SetOverrideTag ("Queue", "Transparent");
material.SetOverrideTag ("RenderType", "Transparent");
material.SetOverrideTag ("IgnoreProjector", "True");
material.SetInt ("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt ("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt ("_ZWrite", 0);
material.DisableKeyword ("_ALPHATEST_ON");
material.DisableKeyword ("_ALPHABLEND_ON");
material.EnableKeyword ("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
break;
}
}
//Keeping the maps in place when changing material or mode
static void MaterialChanged (Material material, WorkflowMode workFlowMode) {
SetupMaterialWithBlendMode (material, (BlendMode)material.GetFloat ("_Mode"));
//SetMaterialKeyWords(material, workFlowMode);
}
}
Know this is a long post, so sorry gor that >.> but anyone got any idea of what could be the issue here? Thanks in advance!
Answer by correia55 · Apr 20, 2017 at 04:08 PM
@Moeren588 Not sure if you still need this but, since I finally came out with a solution, I decided to post it anyway.
The solution I found was very simple, even though it took me a very long time. You just need to add "keepalpha" to the pragma in the shader, in your case, resulting in:
#pragma surface surf Standard fullforwardshadows keepalpha
This works but not sure if it is the right way to do it.
Since changing the alpha value while using the transparent version would result in a change of color, I decided to add the other two versions of the standard shader ("Cutout" and "Fade"). And "Fade" was just the thing I was looking for, maybe its also what you want.
Your answer
Follow this Question
Related Questions
Transparency using Scene Color node not layering multiple transparent objects over each other 0 Answers
Custom opaque shader looks transparent 0 Answers
How can I add alpha channel to this shader and how can I make the object to be transparent ? 1 Answer
A problem with a shader to make a window transparent 0 Answers
Make albedo transparent and keep the glossiness and reflection visible - standard shader 0 Answers