【ShaderToy中图形效果转译到UnityShaderlab案例分享,代码实现渐变火焰扰动_Flame】

文章详细介绍了如何使用ShaderToy的源码在Unity中创建火焰效果。通过浮点噪声函数、球体函数和自定义的raymarch算法,结合CG编程语言,实现了从顶点着色到片段着色的过程,最终在Unity内展示了动态的火焰渲染效果。
摘要由CSDN通过智能技术生成

ShaderToy内的源码与效果图如下:

请添加图片描述

float noise(vec3 p) //Thx to Las^Mercury
{
	vec3 i = floor(p);
	vec4 a = dot(i, vec3(1., 57., 21.)) + vec4(0., 57., 21., 78.);
	vec3 f = cos((p-i)*acos(-1.))*(-.5)+.5;
	a = mix(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x);
	a.xy = mix(a.xz, a.yw, f.y);
	return mix(a.x, a.y, f.z);
}

float sphere(vec3 p, vec4 spr)
{
	return length(spr.xyz-p) - spr.w;
}

float flame(vec3 p)
{
	float d = sphere(p*vec3(1.,.5,1.), vec4(.0,-1.,.0,1.));
	return d + (noise(p+vec3(.0,iTime*2.,.0)) + noise(p*3.)*.5)*.25*(p.y) ;
}

float scene(vec3 p)
{
	return min(100.-length(p) , abs(flame(p)) );
}

vec4 raymarch(vec3 org, vec3 dir)
{
	float d = 0.0, glow = 0.0, eps = 0.02;
	vec3  p = org;
	bool glowed = false;
	
	for(int i=0; i<64; i++)
	{
		d = scene(p) + eps;
		p += d * dir;
		if( d>eps )
		{
			if(flame(p) < .0)
				glowed=true;
			if(glowed)
       			glow = float(i)/64.;
		}
	}
	return vec4(p,glow);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	vec2 v = -1.0 + 2.0 * fragCoord.xy / iResolution.xy;
	v.x *= iResolution.x/iResolution.y;
	
	vec3 org = vec3(0., -2., 4.);
	vec3 dir = normalize(vec3(v.x*1.6, -v.y, -1.5));
	
	vec4 p = raymarch(org, dir);
	float glow = p.w;
	
	vec4 col = mix(vec4(1.,.5,.1,1.), vec4(0.1,.5,1.,1.), p.y*.02+.4);
	
	fragColor = mix(vec4(0.), col, pow(glow*2.,4.));
	//fragColor = mix(vec4(1.), mix(vec4(1.,.5,.1,1.),vec4(0.1,.5,1.,1.),p.y*.02+.4), pow(glow*2.,4.));

}


下面是在Unity内的效果展示:

请添加图片描述

Shader"Flame"{
    Properties
    {

    }
    SubShader
    {
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma fragmentoption ARB_precision_hint_fastest
            #include "UnityCG.cginc"
            // 定义顶点输入结构
            struct appdata{
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };
            // 定义顶点到片段的输出结构
            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float4 screenCoord : TEXCOORD1;
            };

            // 顶点着色器
            v2f vert(appdata v)
            {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.screenCoord.xy = ComputeScreenPos(o.vertex);
                return o;
            }
			// 噪声函数
			fixed noise(fixed3 p) //感谢Las^Mercury
			{
			    fixed3 i = floor(p); // 计算p的向下取整
			    fixed4 a = dot(i, fixed3(1., 57., 21.)) + fixed4(0., 57., 21., 78.); // 计算点积并加上一个向量
			    fixed3 f = cos((p-i)*acos(-1.))*(-.5)+.5; // 计算余弦插值系数
			    a = lerp(sin(cos(a)*a),sin(cos(1.+a)*(1.+a)), f.x); // 根据插值系数在两个值之间插值
			    a.xy = lerp(a.xz, a.yw, f.y); // 根据插值系数在两个值之间插值
			    return lerp(a.x, a.y, f.z); // 根据插值系数在两个值之间插值并返回结果
			}
			
			// 球体函数
			fixed sphere(fixed3 p, fixed4 spr)
			{
			    return length(spr.xyz-p) - spr.w; // 计算点到球心的距离减去球半径
			}
			
			// 火焰函数
			fixed flame(fixed3 p)
			{
			    fixed d = sphere(p*fixed3(1.,.5,1.), fixed4(.0,-1.,.0,1.)); // 计算变换后的点到球体的距离
			    return d + (noise(p+fixed3(.0,_Time.y*2.,.0)) + noise(p*3.)*.5)*.25*(p.y) ; // 计算火焰函数的值
			}
            // 场景函数
            fixed scene(fixed3 p)
            {
                return min(100.-length(p) , abs(flame(p)) );
            }
            // 定义 raymarch 函数,输入参数为光线的起点 org 和方向 dir
            fixed4 raymarch(fixed3 org, fixed3 dir)
            {
                // 初始化距离 d,发光强度 glow,以及误差值 eps
                fixed d = 0.0, glow = 0.0, eps = 0.02;
                // 初始化点 p 为光线起点 org
                fixed3  p = org;
                // 初始化 glowed 标志为 false
                bool glowed = false;
                
                // 循环 64 次,每次更新光线位置和发光强度
                [unroll(100)]
                for(int i=0; i<64; i++)
                {
                    // 计算点 p 在场景中的距离 d
                    d = scene(p) + eps;
                    // 更新点 p 的位置
                    p += d * dir;
                    // 如果距离大于误差值,更新发光强度
                    if( d>eps )
                    {
                        // 如果点 p 的 flame 值小于 0,设置 glowed 为 true
                        if(flame(p) < .0)
                        glowed=true;
                        // 如果 glowed 为 true,计算 glow 值
                        if(glowed)
                        glow = fixed(i)/64.;
                    }
                }
                // 返回点 p 的位置和发光强度
                return fixed4(p,glow);
            }

            // 定义 frag 函数,输入参数为顶点结构体 i
            fixed4 frag(v2f i) : SV_Target
            {
                // 计算屏幕坐标 v
                fixed2 v = -1.0 + 2.0 * i.uv.xy / 1;
                // 更新 v 的 x 坐标
                v.x  = mul(	v.x ,1/1);
                
                // 初始化光线起点 org 和方向 dir
                fixed3 org = fixed3(0., -2., 4.);
                fixed3 dir = normalize(fixed3(v.x*1.6, -v.y, -1.5));
                
                // 调用 raymarch 函数,计算光线与场景的交点 p 和发光强度 glow
                fixed4 p = raymarch(org, dir);
                fixed glow = p.w;
                
                // 计算颜色 col,根据 p.y 的值在两种颜色之间插值
                fixed4 col = lerp(fixed4(1.,.5,.1,1.), fixed4(0.1,.5,1.,1.), p.y*.02+.4);
                // 返回黑色背景下的颜色值
                return lerp(fixed4(0.,0.,0.,0.), col, pow(glow*2.,4.));
                // 白色背景下的颜色值
                //return lerp(fixed4(1.,1.,1.,1.), lerp(fixed4(1.,.5,.1,1.),fixed4(0.1,.5,1.,1.),p.y*.02+.4), pow(glow*2.,4.));
            }
            ENDCG
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暴走约伯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值