I am working on a cel shader for a uni project that I would like to only be affected by scene lights over x intensity. I am struggling in figuring out how to implement this within the code. The code I have been working with I found online, and have been using it to test and understand how shaders work. I am unsure if I need to implement some kind of conditional statement? Some of the information I have read has said that using conditional statements within shaders makes for poor performance.
I am new to shaders and any help would be greatly appreciated.
Thank you in advance :)
ps. I am limited to using Unity 2018.3.8
Properties {
[Header(Base Parameters)]
_Color ("Tint", Color) = (0, 0, 0, 1)
_MainTex ("Texture", 2D) = "white" {}
[HDR] _Emission ("Emission", color) = (0, 0, 0, 1)
[HDR]
_SpecularColor("Specular Color", Color) = (0.9, 0.9, 0.9, 1)
// Controls the size of the specular reflection.
_Glossiness("Glossiness", Float) = 32
[HDR]
_RimColor("Rim Color", Color) = (1,1,1,1)
_RimAmount("Rim Amount", Range(0, 1)) = 0.716
// Control how smoothly the rim blends when approaching unlit
// parts of the surface.
_RimThreshold("Rim Threshold", Range(0, 1)) = 0.1
}
SubShader {
Tags{ "RenderType"="Opaque" "Queue"="Geometry"}
CGPROGRAM
#pragma surface surf Stepped fullforwardshadows
#pragma target 3.0
sampler2D _MainTex;
fixed4 _Color;
half3 _Emission;
float4 _SpecularColor;
float _Glossiness;
float4 _RimColor;
float _RimAmount;
float _RimThreshold;
float3 worldPos;
float4 LightingStepped(SurfaceOutput s, float3 lightDir, half3 viewDir, float shadowAttenuation){
float shadow = shadowAttenuation;
s.Normal=normalize(s.Normal);
float diff = dot(s.Normal, lightDir);
float towardsLightChange = fwidth(diff);
float lightIntensity = smoothstep(0, towardsLightChange, diff);
float3 diffuse = _LightColor0.rgb * lightIntensity * s.Albedo;
float diffussAvg = (diffuse.r + diffuse.g + diffuse.b) / 3;
float3 halfVector = normalize(viewDir + lightDir);
float NdotH = dot(s.Normal, halfVector);
float specularIntensity = pow(NdotH * lightIntensity, _Glossiness * _Glossiness);
float specularIntensitySmooth = smoothstep(0.005, 0.01, specularIntensity);
float3 specular = specularIntensitySmooth * _SpecularColor.rgb * diffussAvg;
float rimDot = 1 - dot(viewDir, s.Normal);
float rimIntensity = rimDot * pow(dot(lightDir, s.Normal), _RimThreshold);
rimIntensity = smoothstep(_RimAmount - 0.01, _RimAmount + 0.01, rimIntensity);
float3 rim = rimIntensity * _RimColor.rgb * diffussAvg;
float4 color;
color.rgb = (diffuse + specular + rim) * shadow;
color.a = s.Alpha;
return color;
}
struct Input {
float2 uv_MainTex;
float3 worldPos;
};
void surf (Input i, inout SurfaceOutput o) {
worldPos = i.worldPos;
fixed4 col = tex2D(_MainTex, i.uv_MainTex);
col *= _Color;
o.Albedo = col.rgb;
o.Alpha = col.a;
o.Emission = _Emission;
}
ENDCG
}
FallBack "Standard"
}
Related
I have a shader for voxel rendering which do not support transparency.
Shader code:
Shader "Custom/Voxel"
{
Properties
{
_Color ("Color", Color) = (1,1,1,1)
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_AOColor ("AO Color", Color) = (0,0,0,1)
_AOIntensity ("AO Intensity", Range(0, 1)) = 1.0
_AOPower ("AO Power", Range(1, 10)) = 1.0
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 200
CGPROGRAM
#pragma surface surf Standard fullforwardshadows
#pragma vertex vert
#pragma target 3.0
sampler2D _MainTex;
struct Input
{
float3 position;
float4 custom_uv;
float4 color : COLOR;
};
half _Glossiness;
half _Metallic;
fixed4 _Color;
int _AtlasX;
int _AtlasY;
fixed4 _AtlasRec;
half4 _AOColor;
float _AOIntensity;
float _AOPower;
UNITY_INSTANCING_BUFFER_START(Props)
UNITY_INSTANCING_BUFFER_END(Props)
void vert (inout appdata_full v, out Input o)
{
UNITY_INITIALIZE_OUTPUT(Input, o);
o.custom_uv = v.texcoord;
o.position = v.vertex;
v.color.rgb = _AOColor;
v.color.a = pow((1-v.color.a) * _AOIntensity, _AOPower );
}
void surf (Input IN, inout SurfaceOutputStandard o)
{
fixed2 atlasOffset = IN.custom_uv.zw;
fixed2 scaledUV = IN.custom_uv.xy;
fixed2 atlasUV = scaledUV;
atlasUV.x = (atlasOffset.x * _AtlasRec.x) + frac(atlasUV.x) * _AtlasRec.x;
atlasUV.y = (((_AtlasY - 1) - atlasOffset.y) * _AtlasRec.y) + frac(atlasUV.y) * _AtlasRec.y;
// Albedo comes from a texture tinted by color
fixed4 c = tex2Dgrad(_MainTex, atlasUV, ddx(atlasUV * _AtlasRec), ddy(atlasUV * _AtlasRec)) * _Color;
//fixed4 c = tex2D(_MainTex, atlasUV) * _Color;
o.Albedo = lerp(c.rgb, IN.color.rgb, IN.color.a);
o.Alpha = c.a;
// Metallic and smoothness come from slider variables
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
}
ENDCG
}
FallBack "Diffuse"
}
What I have changed/added by googling attempts:
Tags { "Queue"="Transparent" "RenderType" = "Transparent" }
Blend SrcAlpha OneMinusSrcAlpha
This did nothing.
Then I have tried to change:
#pragma surface surf Standard fullforwardshadows
with
#pragma surface surf Standard alpha
or
#pragma surface surf Standard fullforwardshadows alpha:fade
So in result those block that should are transparent, but the rest are kinda too (non transparent tiles works good in original version):
https://i.imgur.com/EwMIQnq.png
So what I'm trying to do is load satellite images from an SQL table and wrap them around a sphere to create a globe. I know I've got loading the images covered, I'm just not sure how to make my shader display the images in the correct orientation.
I've gone to the Unity Forums as well as checked out this code from the Unity Docs.
Using the linked shader code and the help I received on the forums, here's the code I've ended up with:
Properties
{
_MainTexArray("Tex", 2DArray) = "" {}
_SliceRange("Slices", Range(0,32)) = 6
_UVScale("UVScale", Float) = 1
_COLUMNS("Columns", Range(0, 5)) = 1
_ROWS("Rows", Range(0, 5)) = 1
_CELLS("Cells", Range(0, 32)) = 16
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// texture arrays are not available everywhere,
// only compile shader on platforms where they are
#pragma require 2darray
#include "UnityCG.cginc"
struct v2f
{
float3 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
float _SliceRange;
float _UVScale;
v2f vert(float4 vertex : POSITION)
{
v2f o;
o.vertex = UnityObjectToClipPos(vertex);
o.uv.xy = (vertex.xy + 0.5) * _UVScale;
o.uv.z = (vertex.z + 0.5) * _SliceRange;
return o;
}
float _COLUMNS; //Columns and rows only go between 0 and 1
float _ROWS;
float _CELLS;
UNITY_DECLARE_TEX2DARRAY(_MainTexArray);
half4 frag(v2f i) : SV_Target
{
float3 uv = float3(i.uv.x * _CELLS, i.uv.y * _CELLS, 0);
uv.z = floor(i.uv.x / _COLUMNS) * floor(i.uv.y / _ROWS);
return UNITY_SAMPLE_TEX2DARRAY(_MainTexArray, uv / _CELLS);
}
ENDCG
}
}
Using that I've gotten my materials to look like this:
Here's the code that I'm using to load the SQL images:
textures = new Texture2D[size];
for (int x = 0; x <= 7; x++)
{
for (int y = 0; y <= 3; y++)
{
textures[count] = tiler.Read(x, y, 2); //The z determines the zoom level, so I wouldn't want them all loaded at once
if (textures[count] != null) TextureScale.Bilinear(textures[count], 256, 256);
count++;
}
}
texArr = new Texture2DArray(256, 256, textures.Length, TextureFormat.RGBA32, true, true);
texArr.filterMode = FilterMode.Bilinear;
texArr.wrapMode = TextureWrapMode.Repeat;
for (int i = 0; i < textures.Length; i++)
{
if (textures[i] == null) continue;
texArr.SetPixels(textures[i].GetPixels(0), i, 0);
}
texArr.Apply();
mat.SetTexture("_MainTexArray", texArr);
In the SQL Table, the x and y determines the position of the tile and the z determines the zoom level. I'm just working with one zoom level for now.
Sorry for linking the whole shader class, but I'm not very experienced with shaders so I don't quite know where the problem lies.
If you can index into the array of photos such that you effectively have an equirectangular projection of the globe, you could try using a modified form of the shader code by Farfarer from the Unity forums copied and modified slightly below:
Shader "Custom/Equirectangular" {
Properties{
_MainTexArray("Tex", 2DArray) = "" {}
_COLUMNS("Columns", Int) = 2
_ROWS("Rows", Int) = 2
}
SubShader{
Pass {
Tags {"LightMode" = "Always"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma require 2darray
#include "UnityCG.cginc"
struct appdata {
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
};
v2f vert(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
o.normal = v.normal;
return o;
}
UNITY_DECLARE_TEX2DARRAY(_MainTexArray);
int _ROWS;
int _COLUMNS;
#define PI 3.141592653589793
inline float2 RadialCoords(float3 a_coords)
{
float3 a_coords_n = normalize(a_coords);
float lon = atan2(a_coords_n.z, a_coords_n.x);
float lat = acos(a_coords_n.y);
float2 sphereCoords = float2(lon, lat) * (1.0 / PI);
return float2(sphereCoords.x * 0.5 + 0.5, 1 - sphereCoords.y);
}
float4 frag(v2f IN) : COLOR
{
float2 equiUV = RadialCoords(IN.normal);
float2 texIndex;
float2 uvInTex = modf(equiUV * float2(_COLUMNS,_ROWS), texIndex);
int flatTexIndex = texIndex.x * _ROWS + texIndex.y;
return UNITY_SAMPLE_TEX2DARRAY(_MainTexArray,
float3(uvInTex, flatTexIndex));
}
ENDCG
}
}
FallBack "VertexLit"
}
You also need to use
texArr = new Texture2DArray(256, 256, textures.Length, TextureFormat.RGBA32, false, true);
instead of
texArr = new Texture2DArray(256, 256, textures.Length, TextureFormat.RGBA32, true, false);
It works for me if I attach this script to a sphere:
Material myMat;
public List<Texture2D> texes;
IEnumerator Start()
{
yield return null;
myMat = GetComponent<Renderer>().material;
Texture2DArray texArr = new Texture2DArray(256, 256, 9,
TextureFormat.RGBA32, false, true);
texArr.filterMode = FilterMode.Bilinear;
texArr.wrapMode = TextureWrapMode.Clamp;
for (int i = 0 ; i < texes.Count ; i++)
{
texArr.SetPixels(texes[i].GetPixels(), i, 0);
}
texArr.Apply();
myMat.SetTexture("_MainTexArray", texArr);
}
and in texes I add these textures in order:
0:
1:
2:
3:
4:
5:
6:
7:
8:
and set 3 for Rows and Columns, it produces decent results:
If bilinear filtering is enabled, there are still some artifacts at the borders of the textures. But these artifacts have to be zoomed in quite close to see. Due to the lack of adjacent pixels for bilinear filtering they mostly appear as improperly blended or missing pixels:
Of course this example doesn't properly tile so there is an obvious seam along one longitude line:
Since this setup expects normals from a sphere, this only works on things with normals that approximate those of a sphere. So it would not render properly on a plane, for instance.
I have the following shader,
I'm trying to add an alpha to the white, however all attempts have proven to be difficult.
This is the project from which I obtained the shader for reference - github
I think it has to do with one of the passes overwriting.
Shader "Suibokuga/Suibokuga" {
Properties {
_MainTex ("Water Texture", 2D) = "white" {}
_Alpha ("Transfer/Diffusion coefficient for water particles", Range(0.01, 1.5)) = 1.0
_Evaporation ("a unit quantity of water for evaporation", Range(0.0001, 0.005)) = 0.00015
_PaperTex ("Paper Texture", 2D) = "white" {}
_Brush ("brush", Vector) = (-1, -1, -1, -1)
_Prev ("previous brush position", Vector) = (-1, -1, -1, -1)
}
CGINCLUDE
#include "UnityCG.cginc"
#pragma target 3.0
/*
* r : water particles
* b : capacities of water
* a : the heights of the bottoms
*/
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float _Alpha;
float _Evaporation;
sampler2D _PaperTex;
float2 _Prev;
float3 _Brush; // x,y : position, z : size
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
v2f vert (appdata IN) {
v2f OUT;
OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
OUT.uv = IN.uv;
return OUT;
}
void sample (float2 uv, out float4 o, out float4 l, out float4 t, out float4 r, out float4 b) {
float2 texel = _MainTex_TexelSize.xy;
o = tex2D(_MainTex, uv);
l = tex2D(_MainTex, uv + float2(-texel.x, 0));
t = tex2D(_MainTex, uv + float2( 0, -texel.y));
r = tex2D(_MainTex, uv + float2( texel.x, 0));
b = tex2D(_MainTex, uv + float2( 0, texel.y));
}
float waterDelta (float4 k, float4 o) {
float ld = (k.w + k.x) - (o.w + o.x); // level difference
float transfer = (k.w + k.x) - max(o.w, k.w + k.z); // transferable water particles
return max(
0.0,
0.25 * _Alpha * min(ld, transfer)
);
}
float waterFlow (float2 uv) {
float4 o, l, t, r, b;
sample(uv, o, l, t, r, b);
float nw = o.r;
nw += (waterDelta(l, o) - waterDelta(o, l));
nw += (waterDelta(t, o) - waterDelta(o, t));
nw += (waterDelta(r, o) - waterDelta(o, r));
nw += (waterDelta(b, o) - waterDelta(o, b));
return max(nw, 0);
}
float evaporation (float wo) {
return max(wo - _Evaporation, 0.0);
}
float brush (float2 uv) {
const int count = 10;
float2 dir = _Brush.xy - _Prev.xy;
float l = length(dir);
if(l <= 0) {
float d = length(uv - _Brush.xy);
return smoothstep(0.0, _Brush.z, _Brush.z - d);
}
float ld = l / count;
float2 norm = normalize(dir);
float md = 100;
for(int i = 0; i < count; i++) {
float2 p = _Prev.xy + norm * ld * i;
float d = length(uv - p);
if(d < md) {
md = d;
}
}
return smoothstep(0.0, _Brush.z, _Brush.z - md);
// float d = length(uv - _Brush.xy);
// return smoothstep(0.0, _Brush.z, _Brush.z - d);
}
ENDCG
SubShader {
Cull Off ZWrite Off ZTest Always
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment init
float4 init (v2f IN) : SV_Target {
float4 paper = tex2D(_PaperTex, IN.uv);
return float4(
0,
0,
paper.r,
paper.r
);
}
ENDCG
}
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment waterUpdate
float4 waterUpdate (v2f IN) : SV_Target {
float4 col = tex2D(_MainTex, IN.uv);
col.x = evaporation(waterFlow(IN.uv));
float dw = brush(IN.uv);
// if(dw > 0) {
col.x = min(col.x + brush(IN.uv), 1.0);
// }
return col;
}
ENDCG
}
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment visualize
float4 visualize (v2f IN) : SV_Target {
float4 col = tex2D(_MainTex, IN.uv);
return float4(1.0 - col.xxx, 1.0);
}
ENDCG
}
}
}
You seem to miss a blending step.
Try adding this line to the end of the last pass
Blend SrcAlpha OneMinusSrcAlpha
Check this page to learn about alpha blending for Unity shaders.
The line I attached is for standard transparency, you might want to try different blending options.
I'd like to create a tiled shader that wraps back onto itself as it offsets a transparent texture over time. The result will make a "moving walkway/travellator" across a mesh using a texture representing a single step.
This is what I have so far. But it doesn't wrap around (without using external dependencies as setting the texture's wrap mode to repeat)
Shader "Custom/ScrollingTextureUnlitShader"
{
Properties
{
_FadeValue ("Fade Value", Range(0, 1)) = 1
_ColorTint ("Color Tint", Color) = (1,1,1,1)
_MainTex ("Base (RGB)", 2D) = "white" {}
_ScrollXSpeed ("X Scroll Speed", Range(-10, 10)) = -5
_ScrollYSpeed ("Y Scroll Speed", Range(-10, 10)) = 0
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 200
CGPROGRAM
#pragma surface surf Unlit alpha
float _FadeValue;
float4 _ColorTint;
sampler2D _MainTex;
fixed _ScrollXSpeed;
fixed _ScrollYSpeed;
struct Input
{
float2 uv_MainTex;
};
void surf (Input IN, inout SurfaceOutput o)
{
fixed2 scrolledUV = IN.uv_MainTex;
fixed xScrollValue = _ScrollXSpeed * _Time;
fixed yScrollValue = _ScrollYSpeed * _Time;
scrolledUV += fixed2 (xScrollValue, yScrollValue);
half4 c = tex2D (_MainTex, scrolledUV);
o.Albedo = c.rgb * _ColorTint;
o.Alpha = c.a * _FadeValue;
}
inline fixed4 LightingUnlit (SurfaceOutput s, fixed3 lightDir, fixed3 viewDir, fixed atten)
{
fixed4 c;
c.rgb = s.Albedo;
c.a = s.Alpha;
return c;
}
ENDCG
}
FallBack "Transparent/Diffuse"
}
How could I implement a bleach bypass shader effect for WPF?
I'm also interested in the possibility of implementing the first two Tehnicolor Film Processes, or any variety that would result in an old film look.
Check out: http://developer.download.nvidia.com/shaderlibrary/packages/post_bleach_bypass.fx.zip
The important part is:
float4 bypassPS(QuadVertexOutput IN, uniform sampler2D SceneSampler) : COLOR
{
float4 base = tex2D(SceneSampler, IN.UV);
float3 lumCoeff = float3(0.25,0.65,0.1);
float lum = dot(lumCoeff,base.rgb);
float3 blend = lum.rrr;
float L = min(1,max(0,10*(lum- 0.45)));
float3 result1 = 2.0f * base.rgb * blend;
float3 result2 = 1.0f - 2.0f*(1.0f-blend)*(1.0f-base.rgb);
float3 newColor = lerp(result1,result2,L);
float A2 = Opacity * base.a;
float3 mixRGB = A2 * newColor.rgb;
mixRGB += ((1.0f-A2) * base.rgb);
return float4(mixRGB,base.a);
}