C# 在Shaderlab中初始化全局变量时出现问题
我刚刚意识到Unity中的全局变量必须在函数中初始化。作为着色器的新手,我不知道我是否用了错误的方法 例如,当我定义常量变量时:C# 在Shaderlab中初始化全局变量时出现问题,c#,unity3d,shader,shaderlab,C#,Unity3d,Shader,Shaderlab,我刚刚意识到Unity中的全局变量必须在函数中初始化。作为着色器的新手,我不知道我是否用了错误的方法 例如,当我定义常量变量时: const float PI = 3.14159265359; 然后尝试编写在frag函数中使用的代码: fixed4 frag(v2f i) : SV_Target { float result = PI * otherVariable; ///Use the result value... } 它不起作用。我得到一个黑屏作为结果或预期结果不会显
const float PI = 3.14159265359;
然后尝试编写在frag函数中使用的代码:
fixed4 frag(v2f i) : SV_Target
{
float result = PI * otherVariable;
///Use the result value...
}
它不起作用。我得到一个黑屏作为结果或预期结果不会显示
令人困惑的是,当我在frag函数中重新初始化全局变量PI时,我得到了预期的结果
例如,这就是有效的方法:
float PI = 3.14159265359;
然后尝试编写在frag函数中使用的代码:
fixed4 frag(v2f i) : SV_Target
{
//re-initialize
PI = 3.14159265359;
float result = PI * otherVariable;
}
我有太多恒定的全局变量,我无法保持它们
这个问题的一个完整例子是我移植的Shadertoy代码
Shader "Unlit/Atmospheric Scattering 2"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//https://www.shadertoy.com/view/lslXDr
// math const
float PI = 3.14159265359;
float DEG_TO_RAD = (3.14159265359 / 180.0);
float MAX = 10000.0;
// scatter const
float K_R = 0.166;
float K_M = 0.0025;
float E = 14.3;
float C_R = float3(0.3, 0.7, 1.0); // 1 / wavelength ^ 4
float G_M = -0.85; // Mie g
float R = 1.0;
float R_INNER = 0.7;
float SCALE_H = 4.0 / (1.0 - 0.7);
float SCALE_L = 1.0 / (1.0 - 0.7);
int NUM_OUT_SCATTER = 10;
float FNUM_OUT_SCATTER = 10.0;
int NUM_IN_SCATTER = 10;
float FNUM_IN_SCATTER = 10.0;
// angle : pitch, yaw
float3x3 rot3xy(float2 angle) {
float2 c = cos(angle);
float2 s = sin(angle);
return float3x3(
c.y, 0.0, -s.y,
s.y * s.x, c.x, c.y * s.x,
s.y * c.x, -s.x, c.y * c.x
);
}
// ray direction
float3 ray_dir(float fov, float2 size, float2 pos) {
float2 xy = pos - size * 0.5;
float cot_half_fov = tan((90.0 - fov * 0.5) * DEG_TO_RAD);
float z = size.y * 0.5 * cot_half_fov;
return normalize(float3(xy, -z));
}
// ray intersects sphere
// e = -b +/- sqrt( b^2 - c )
float2 ray_vs_sphere(float3 p, float3 dir, float r) {
float b = dot(p, dir);
float c = dot(p, p) - r * r;
float d = b * b - c;
if (d < 0.0) {
return float2(MAX, -MAX);
}
d = sqrt(d);
return float2(-b - d, -b + d);
}
// Mie
// g : ( -0.75, -0.999 )
// 3 * ( 1 - g^2 ) 1 + c^2
// F = ----------------- * -------------------------------
// 2 * ( 2 + g^2 ) ( 1 + g^2 - 2 * g * c )^(3/2)
float phase_mie(float g, float c, float cc) {
float gg = g * g;
float a = (1.0 - gg) * (1.0 + cc);
float b = 1.0 + gg - 2.0 * g * c;
b *= sqrt(b);
b *= 2.0 + gg;
//b = mul(b,sqrt(b));
//b = mul(b,2.0 + gg);
return 1.5 * a / b;
}
// Reyleigh
// g : 0
// F = 3/4 * ( 1 + c^2 )
float phase_reyleigh(float cc) {
return 0.75 * (1.0 + cc);
}
float density(float3 p) {
return exp(-(length(p) - R_INNER) * SCALE_H);
}
float optic(float3 p, float3 q) {
float3 step = (q - p) / FNUM_OUT_SCATTER;
float3 v = p + step * 0.5;
float sum = 0.0;
for (int i = 0; i < NUM_OUT_SCATTER; i++) {
sum += density(v);
v += step;
}
sum *= length(step) * SCALE_L;
//sum = mul(sum,length(step) * SCALE_L);
return sum;
}
float3 in_scatter(float3 o, float3 dir, float2 e, float3 l) {
float len = (e.y - e.x) / FNUM_IN_SCATTER;
float3 step = dir * len;
float3 p = o + dir * e.x;
float3 v = p + dir * (len * 0.5);
float3 sum = float3(0.,0.,0.);
for (int i = 0; i < NUM_IN_SCATTER; i++) {
float2 f = ray_vs_sphere(v, l, R);
float3 u = v + l * f.y;
float n = (optic(p, v) + optic(v, u)) * (PI * 4.0);
sum += density(v) * exp(-n * (K_R * C_R + K_M));
v += step;
}
sum *= len * SCALE_L;
//sum = mul(sum,len * SCALE_L);
float c = dot(dir, -l);
float cc = c * c;
return sum * (K_R * C_R * phase_reyleigh(cc) + K_M * phase_mie(G_M, c, cc)) * E;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
fixed4 frag(v2f i) : SV_Target
{
//Re-initialize BEGIN
// math const
PI = 3.14159265359;
DEG_TO_RAD = (3.14159265359 / 180.0);
MAX = 10000.0;
// scatter const
K_R = 0.166;
K_M = 0.0025;
E = 14.3;
C_R = float3(0.3, 0.7, 1.0); // 1 / wavelength ^ 4
G_M = -0.85; // Mie g
R = 1.0;
R_INNER = 0.7;
SCALE_H = 4.0 / (1.0 - 0.7);
SCALE_L = 1.0 / (1.0 - 0.7);
NUM_OUT_SCATTER = 10;
FNUM_OUT_SCATTER = 10.0;
NUM_IN_SCATTER = 10;
FNUM_IN_SCATTER = 10.0;
//Re-initialize END
float4 fragColor = 0;
float2 fragCoord = i.vertex.xy;
// default ray dir
float3 dir = ray_dir(45.0, _ScreenParams.xy, fragCoord.xy);
// default ray origin
float3 eye = float3(0.0, 0.0, 2.4);
// rotate camera
float3x3 rot = rot3xy(float2(0.0, _Time.y * 0.5));
/* dir = rot * dir;
eye = rot * eye;*/
dir = mul(rot,dir);
eye = mul(rot,eye);
// sun light dir
float3 l = float3(0, 0, 1);
float2 e = ray_vs_sphere(eye, dir, R);
if (e.x > e.y) {
discard;
}
float2 f = ray_vs_sphere(eye, dir, R_INNER);
e.y = min(e.y, f.x);
float3 I = in_scatter(eye, dir, e, l);
fragColor = float4(I, 1.0);
return fragColor;
}
ENDCG
}
}
}
它工作得很好,但请注意我如何重新初始化PI、DEG_to_RAD、MAX和其他全局变量…如果不这样做,它将无法工作。屏幕只是黑色的,这不是第一个导致相同问题的着色器
为什么会这样
我用错误的方式声明变量了吗?嗨
可以这样编写的任何常量:
//float my_constant = 104.3;
#define my_constant 104.3f
可以为着色器创建自定义库,并根据需要使用变量和函数。例如,创建名为MyConstants.cginc的文件并放入项目中。代码:
#ifndef MY_CONSTANTS_INCLUDED
#define MY_CONSTANTS_INCLUDED
#define DEG_TO_RAD 0.01745329251994f
#define MAX 10000.0f
#define PI 3.14159265359f
//scatter const
// .....
// .....
float3 ray_dir(float fov, float2 size, float2 pos) {
float2 xy = pos - size * 0.5;
float cot_half_fov = tan((90.0 - fov * 0.5) * DEG_TO_RAD);
float z = size.y * 0.5 * cot_half_fov;
return normalize(float3(xy, -z));
}
//.... and other methods
#endif
并在着色器中使用库
//.....
#include "UnityCG.cginc"
#include "MyConstants.cginc"
//.....
这是一个输入错误:float=PI*otherVariable?是的,这是一个输入错误,并假设otherVariable也被声明。主要的完整问题示例在frag函数中我的问题中的完整着色器代码中。请参阅“重新初始化开始”和“重新初始化结束”注释之间的内容。我想知道为什么我从未收到有关此答案的通知。你的意思是使用预处理器/定义是唯一的解决方案?@Programmer我不擅长着色器,我只知道用这种方法来实现你想要的。要了解更多信息,我们需要了解更多有关着色器的信息。如果您发现其他内容,请注意,这很好。我也是一个新的着色器,并试图避免处理器。如果我发现任何新的东西,我会发表评论。谢谢
//.....
#include "UnityCG.cginc"
#include "MyConstants.cginc"
//.....