我正在按照Sam Wronski制作的教程进行操作。零世界(Tutorial by World of Zero),他为一个点云草发生器编码几何着色器。伟大的教程,但我想知道(并且经过几天的研究后没有找到合适的解决方案)如何实现阴影到阴影(投射和接收阴影)。我正在尝试深入挖掘着色器,但这对我来说还是一个很高的水平。
我的问题是:如何为这个草形着色器实现阴影投射和接收?到目前为止存在且工作正常的代码如下:
Shader "Custom/GrassGeometryShader" {
// https://www.youtube.com/watch?v=HY6qFbmbij8 und http://www.battlemaze.com/?p=153
Properties {
// --> HDR allows High Dynamic Colors
[HDR]_BackgroundColor ("Background Color", Color) = (1,0,0,1) // default to red
[HDR]_ForegroundColor ("Foreground Color", Color) = (0,1,0,1) // default to green
_MainTex ("Albedo (RGB)", 2D) = "white" {}
_Glossiness ("Smoothness", Range(0,1)) = 0.5
_Metallic ("Metallic", Range(0,1)) = 0.0
_Cutoff("Alpha Cuttoff", Range (0,1)) = 0.15 // Wieviel abgeschnitten sien soll
_GrassHeight("GrasHeight", Float) = 0.25
_GrassWidt("GrasWidth", Float) = 0.25
_WindSpeed ("WindSpeed", Float) = 100
_WindStrength("WindStrength", Float) = 0.05
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 200
Pass
{
Cull OFF
CGPROGRAM
#include "UnityCG.cginc" // like: "using" in C#
// Vertex-Shader with vert-function
#pragma vertex vert
// Fragment-Shader with frag-function
#pragma fragment frag
// Geometry-Shader with geom-function
#pragma geometry geom
// Use shader model 3.0 target, to get nicer looking lighting
#pragma target 4.0 // needs to be 4.0 !
sampler2D _MainTex;
// vertex to graphics (v2g)
struct v2g
{
float4 pos : SV_POSITION;
float3 norm : NORMAL;
float2 uv : TEXCOORD0;
float3 color : TEXCOORD1;
};
//graphics to fragments (g2f)
struct g2f
{
float4 pos : SV_POSITION;
float3 norm : NORMAL;
float2 uv : TEXCOORD0;
float3 diffuseColor : TEXCOORD1;
//float3 specularColor : TEXCOORD2;
};
half _Glossiness;
half _Metallic;
fixed4 _BackgroundColor;
fixed4 _ForegroundColor;
half _GrassHeight;
half _GrassWidth;
half _Cutoff;
half _WindStrength;
half _WindSpeed;
// Vertex-Shader from Battlemaze.com
v2g vert(appdata_full v)
{
float3 v0 = mul(unity_ObjectToWorld, v.vertex).xyz;
v2g OUT;
OUT.pos = v.vertex;
OUT.norm = v.normal;
OUT.uv = v.texcoord;
OUT.color = tex2Dlod(_MainTex, v.texcoord).rgb;
return OUT;
}
void buldQuad(inout TriangleStream<g2f> triStream, float3 points[4], float3 color) {
g2f OUT;
float3 faceNormal = cross(points[1]-points[0], points[2]-points[0]);
for(int i; i < 4; ++i) {
OUT.pos = UnityObjectToClipPos(points[i]);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(i%2, (int)i/2);
triStream.Append(OUT);
}
triStream.RestartStrip();
}
// geom-Funktion
[maxvertexcount(24)]
void geom(point v2g IN[1], inout TriangleStream<g2f> triStream)
{
float3 lightPosition = _WorldSpaceLightPos0;
float3 perpendicularAngle = float3(0,0,1);
float3 faceNormal = cross(perpendicularAngle, IN[0].norm); // normal of gras
float3 v0 = IN[0].pos.xyz; // Tip of the gras
float3 v1 = IN[0].pos.xyz + IN[0].norm * _GrassHeight; // base of the gras
float3 v2 = IN[0].pos.xyz + IN[0].norm * _GrassHeight / 2; // middle part (?)
float3 wind = float3(sin(_Time.x * _WindSpeed + v0.x) + sin(_Time.x * _WindSpeed + v0.z * 2), 0, cos(_Time.x * _WindSpeed + v0.x * 2) + cos(_Time.x * _WindSpeed + v0.z)); // Anzahl oder Stärke der Manipulation an den Eckpunkten
// (_Time.x + v0.x + v0.z looks "random", because it's using time + coordinates)
v1 += wind * _WindStrength;
v2 += (wind * _WindStrength/2)/2;
float3 color = (IN[0].color); // color of the gras
float sin30 = 0.5;
float sin60 = 0.866f;
float cos30 = sin60;
float cos60 = sin30;
g2f OUT;
// Quad 1 - the following code could fit in one function (BUT!) it did not work on MacOSX, that's why it's still calculated the long way
OUT.pos = UnityObjectToClipPos(v0 + perpendicularAngle * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(1, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1 + perpendicularAngle * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(1, 1);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v0);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 1);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1 - perpendicularAngle * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0, 1);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v0 - perpendicularAngle * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v0);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 1);
triStream.Append(OUT);
// Quad 2
OUT.pos = UnityObjectToClipPos(v0 + float3(sin60, 0, -cos60) * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(1, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1 + float3(sin60, 0, -cos60)* 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(1, 1);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v0);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 1);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v0 - float3(sin60, 0, -cos60) * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1 - float3(sin60, 0, -cos60) * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0, 1);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v0);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 1);
triStream.Append(OUT);
// Quad 3 - Positive
OUT.pos = UnityObjectToClipPos(v0 + float3(sin60, 0, cos60) * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(1, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1 + float3(sin60, 0, cos60)* 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(1, 1);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v0);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 1);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v0 - float3(sin60, 0, cos60) * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1 - float3(sin60, 0, cos60) * 0.5 * _GrassHeight);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0, 1);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v0);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 0);
triStream.Append(OUT);
OUT.pos = UnityObjectToClipPos(v1);
OUT.norm = faceNormal;
OUT.diffuseColor = color;
OUT.uv = float2(0.5, 1);
triStream.Append(OUT);
}
// Fragment-Shader by Battlemaze.com --> gets input v2g and renders it on screen
half4 frag(g2f IN) : COLOR
{
fixed4 c = tex2D(_MainTex, IN.uv);
clip(c.a - _Cutoff);
return c;
//return float4 (IN.diffuseColor.rgb, 1.0);
}
ENDCG
}
}
}
正如我所提到的,我使用运行MacOS的机器,遗憾的是它不能与计算着色器一起使用。
我将不胜感激任何帮助。
添加对阴影接收的支持
在CGPROGRAM块的顶部,添加以下内容:
#include "AutoLight.cginc"
您可能还需要添加以下内容:
#pragma multi_compile_fwdbase
在v2g结构中,添加以下行:
SHADOW_COORDS(3) // (3) means we are using TEXCOORD3
在几何着色器内部,对于每个新顶点,在分配OUT.pos后添加此行:
TRANSFER_SHADOW(OUT)
最后,在您的片段函数中,添加以下内容:
half shadow = SHADOW_ATTENUATION(IN)
现在,“shadow”变量包含您的阴影蒙版。在点亮的着色器中,您将其与浅色相乘,但在您的情况下,您可以将其与输出反照率颜色相乘。
添加对阴影投射的支持
将以下传递添加到着色器:
Pass {
Name "ShadowCaster"
Tags { "LightMode" = "ShadowCaster" }
ZWrite On ZTest LEqual
CGPROGRAM
#pragma target 2.0
#pragma multi_compile_shadowcaster
#pragma vertex vertShadowCaster
#pragma fragment fragShadowCaster
#include "UnityStandardShadow.cginc"
ENDCG
}