基于光线投射算法(累加密度和最大密度投影)的三维CT图像(X光)效果

思路:利用平面的顶点和法线模拟一束平行光线,计算光线与物体(AABB)相交部分,以一定的步长采样相交部分,并且累加每一步采样得到的值,最后乘以相同的系数取平均值输出颜色。Texture3D大小512x512x415。

Shader "Custom/XAddShader"
{Properties{_Volume("Texture3D", 3D) = "" {}lightScale("LightScale",Range(0,5)) = 1LightColor("LightColor",color) = (0,0,0,1)Zvalue("value",Range(0,1)) = 0}SubShader{Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" }LOD 100Pass{CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"sampler3D _Volume;float lightScale;float4x4 Direction;fixed4 LightColor;float Zvalue;bool cubeIntersection(float3 origin, float3 direction, float3 aabbMax, float3 aabbMin, out float tNear, out float tFar){float3 t1 = direction * (aabbMax - origin);float3 t2 = direction * (aabbMin - origin);float3 tMin = min(t1, t2);float3 tMax = max(t1, t2);tNear = min(max(tMin.x, tMin.y), tMin.z);tFar = max(min(tMax.x, tMax.y), tMax.z);return tNear <= tFar;}struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 vertex : SV_POSITION;float3 Pos : TEXCOORD0;float3 Normal : TEXCOORD1;};v2f vert(appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.Pos = v.vertex;o.Normal =normalize(v.normal);return o;}fixed4 frag(v2f i) : SV_Target{float4 col = float4(0, 0, 0, 0);float3 lpos = i.Pos;float3 ldir = i.Normal;float3 origin = lpos - ldir;//投影算法需要的参数float tNear, tFar;cubeIntersection(origin, ldir, float3(0.5, 0.5, 0.5), float3(-0.5, 0.5, -0.5), tNear, tFar);//AABB投影算法float CurrentRayLength = tNear;float maxSamples = 512;//我的Texture3d是512*512*176的float CurrentSample = 0;float Steplength = 1.732 / maxSamples; //box两点间最大距离/maxint CurrentStep = 0;while (CurrentRayLength0-1                                   float4 pcol = tex3Dlod(_Volume, float4(pos, 0));//3D采样if (pcol.a >= Zvalue){CurrentStep += 1;float single = (pcol.a - Zvalue) / (1 - Zvalue) * (maxSamples - CurrentSample) / maxSamples;//关于pcol.a直线方程乘以采样衰减系数col.a += single;                //叠加}CurrentRayLength += Steplength;CurrentSample += 1;}if (CurrentStep>0) {col.a = col.a *0.08;//以相同的标准取平均值,毕竟加了那么多次}return float4(col.aaa,1)*LightColor*lightScale;//加上光的强度和颜色}ENDCG}}
}


最大密度投影,对每一步采样得到的值取最大值就可以,不用累加了

Shader "Custom/MipXShader"
{Properties{_Volume("Texture3D", 3D) = "" {}lightScale("LightScale",Range(0,10)) = 1LightColor("LightColor",color) = (0,0,0,1)Zvalue("value",Range(0,1)) = 0}SubShader{Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" }LOD 100Pass{CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"sampler3D _Volume;float lightScale;float4x4 Direction;fixed4 LightColor;float Zvalue;bool cubeIntersection(float3 origin, float3 direction, float3 aabbMax, float3 aabbMin, out float tNear, out float tFar){float3 t1 = direction * (aabbMax - origin);float3 t2 = direction * (aabbMin - origin);float3 tMin = min(t1, t2);float3 tMax = max(t1, t2);tNear = min(max(tMin.x, tMin.y), tMin.z);tFar = max(min(tMax.x, tMax.y), tMax.z);return tNear <= tFar;}struct appdata{float4 vertex : POSITION;float3 normal : NORMAL;};struct v2f{float4 vertex : SV_POSITION;float3 Pos : TEXCOORD0;float3 Normal : TEXCOORD1;};v2f vert(appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.Pos = v.vertex;o.Normal =normalize(v.normal);return o;}fixed4 frag(v2f i) : SV_Target{float4 col = float4(0, 0, 0, 0);float3 lpos = i.Pos;float3 ldir = i.Normal;float3 origin = lpos - ldir;//投影算法需要的参数float tNear, tFar;cubeIntersection(origin, ldir, float3(0.5, 0.5, 0.5), float3(-0.5, 0.5, -0.5), tNear, tFar);//AABB投影算法float step = tNear;float maxvalue=0;while(step0-1                                   float4 pcol = tex3Dlod(_Volume, float4(pos, 0));//3D采样if (pcol.a >= Zvalue){if (pcol.a > maxvalue) {maxvalue = pcol.a;//取最大值}col.a =maxvalue;}step += 0.002;}col.a =saturate(col.a);return float4(col.aaa,1)*LightColor*lightScale;//加上光的强度和颜色}ENDCG}}
}



 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部