问题描述
我一直在尝试制作一个着色器,它允许光线行进在没有重型显卡的设备上发生。我正在使用 unity3d,但已经被一个问题困住了大约 2 周。
我现在拥有的着色器非常简单,并且可以在不同平台上提供良好的 fps。它甚至在 WebGL 中工作得非常快(这是一场噩梦),但最后一块拼图是允许用户选择不同的光线行进形状。
我终生无法弄清楚为什么,第 94 行的简单开关在 WebGL 中不起作用。
我试过了:
- 将其重写为 if/else 语句
- 三元运算符
- 尝试通过线性逻辑运算符决定正确的有符号距离
- 基于比较的数学,以避免使用条件分支。
我现在很想使用 step 或 lerp 等函数的数学版本,但它们的实现有时也涉及似乎分支着色器的条件或逻辑运算符。 WebGL 只是忽略我尝试的所有内容,并且只在 Web 控制台中打印(错误:制服太多)。
就好像它总是知道我在做什么(◕︵◕)
我也在尝试安装其他 Webgl 调试控制台,如 spector.js,但我没有从中找到任何重要的线索。
我是着色器编程的新手,所以我真的不知道调试它的最佳方法,想知道社区中是否有人知道出路。
Properties
{
_MainTex ("Texture",2D) = "white" { }
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "SigneddistanceFunctions.cginc"
sampler2D _MainTex;
float4x4 _FrustrumCornersES;
float4 _TexelSize;
float4x4 _CameraInvViewMatrix;
float _Scale;
float _Size;
float4 _LightDir;
sampler2D _CameraDepthTexture;
float _SphereScale;
float _SmoothUnion;
//Shape Arrays
int _ShapeCount;
float4 shapePosition[256];
float4x4 shapetoLocal[256];
float4 shapeExtent[256];
float shapeType[256];
float4 shapeColor[256];
struct appdata
{
float4 vertex: POSITION;
float2 uv: TEXCOORD0;
};
struct v2f
{
float2 uv: TEXCOORD0;
float4 vertex: SV_POSITION;
float3 ray: TEXCOORD1;
};
// How many times each ray is marched
// Higher values give higher resolution
// (and potentially longer draw distances)
// but lower performance
static const int maxSteps = 60;
//How close does a ray have to get to be consider a hit
//Higher values give a sharper deFinition of shape
// but lower performance
static const float epsilon = 0.03;
// The maximum distance we want a ray to be from
// the nearest surface before giving up
//Higher values give a longer draw distance but
// lower performance
static const float maxdist = 10;
// Utility function to find out
// when two values are equal
// Return 1 if equal,0 if not.
float when_eq(float x,float y) {
return 1.0 - abs(sign(x - y));
}
//Get the specific shape of a raymarch object
float4 GetShape(float3 p,int index)
{
float3 position = mul(shapetoLocal[index],float4((p),1.0));
float3 col = float3(shapeColor[index].x,shapeColor[index].y,shapeColor[index].z);
float dst = 0;
switch (shapeType[index])
{
case 0:
dst = sdSphere(shapePosition[index] - p,length(float3(shapeExtent[index].x,shapeExtent[index].y,shapeExtent[index].z)));
break;
case 1:
dst = sdBox(position,float3(shapeExtent[index].x,shapeExtent[index].z));
break;
case 2:
dst = sdTorus(position,length(shapeExtent[index].x),length(shapeExtent[index].z));
break;
case 3:
dst = sdCone(position,float2(shapeExtent[index].x,shapeExtent[index].z),shapeExtent[index].y);
break;
case 4:
dst = sdCylinder(position,length(float2(shapeExtent[index].x,shapeExtent[index].z)),shapeExtent[index].y);
break;
}
return float4(col,dst);
}
// Map out Signed distances by looping
// over all shapes we Feed the shader
float4 map(float3 p)
{
float4 dist = GetShape(p,0);
[unroll(4)]
for (int i = 0; i < _ShapeCount; i++){
dist = opSmoothUnion(dist,GetShape(p,i),_SmoothUnion);
}
return dist;
}
//Get normals given a point
float3 calcnormal(float3 p)
{
float x = map(float3(p.x + epsilon,p.y,p.z)).w
- map(float3(p.x - epsilon,p.z)).w;
float y = map(float3(p.x,p.y + epsilon,p.z)).w
- map(float3(p.x,p.y - epsilon,p.z)).w;
float z = map(float3(p.x,p.z + epsilon)).w
- map(float3(p.x,p.z - epsilon)).w;
return normalize(float3(x,y,z));
}
// Actual Raymarching function,// returns a color for different points
// where our rays hit objects.
fixed4 raymarch(float3 rayOrigin,float3 rayDirection,float s)
{
fixed4 col = fixed4(0,0);
const int timestep = 100;
float travelled = 0;
for (int i = 0; i < timestep; i ++)
{
float3 position = rayOrigin + rayDirection * travelled;
float4 surf = map(position);
if (travelled > maxdist || travelled >= s)
// if (travelled >= s)
{
col = fixed4(0,0);
break;
}
if(surf.w < 0.03)
{
float3 n = calcnormal(position);
col = fixed4(surf.rgb * dot(-_LightDir.xyz,n).rrr,1);
break;
}
travelled += surf.w;
}
return col;
}
//Vertex
v2f vert(appdata v)
{
v2f o;
half index = v.vertex.z;
v.vertex.z = 0;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv.xy;
// #if UNITY_UV_STARTS_AT_TOP
// if(_TexelSize.y < 0)
// o.uv.y = 1 - o.uv.y;
// #endif
o.ray = _FrustrumCornersES[(int)index].xyz;
//normalize on the Z axis - viewspace position
o.ray /= abs(o.ray.z);
o.ray = mul(_CameraInvViewMatrix,o.ray);
return o;
}
//Fragment
fixed4 frag(v2f i): SV_Target
{
float3 rayDir = normalize(i.ray.xyz);
float3 rayOrigin = _WorldspaceCameraPos;
float2 duv = i.uv;
if (_TexelSize.y < 0)
duv.y = 1 - duv.y;
float depth = LinearEyeDepth(tex2D(_CameraDepthTexture,duv).r);
depth *= length(i.ray.xyz);
fixed3 col = tex2D(_MainTex,i.uv);
fixed4 add = raymarch(rayOrigin,rayDir,depth);
return (fixed4(col * (1.0 - add.w) + add.xyz * add.w,1.0) + 0.2);
}
ENDCG
}
}
}
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)