如何在着色器代码中创建一圈圆圈?

问题描述 投票:0回答:1

我正在使用带有着色器代码的Unity游戏引擎(我是初学者)。

目标
我正在尝试创建一个圆圈,类似于下图(我现在不关心颜色)。

问题
每个圆圈似乎都被压向中心,我不知道如何解决这个问题(见下文)。

我的设置
该着色器的材质应用于画布内的面板,我使用的是 uv 的材质(见下文)。

v2f vert (appdata v)
{
     v2f o;
     o.vertex = UnityObjectToClipPos(v.vertex);
     o.uv = v.uv;
     return o;
}        

问题代码
我认为问题在于我在 frag 函数中计算纵横比、角度或距离的方式(见下文)。

fixed4 frag(v2f i) : SV_Target
{
     float aspectRatio = _ScreenParams.x / _ScreenParams.y;

     float2 center = (0.5 * aspectRatio, 0.5);

     float2 uv = i.uv - center;

     uv.x *= aspectRatio;

     float angle = atan2(uv.y, uv.x);

     angle = (angle < 0) ? (angle + UNITY_TWO_PI) : angle;

     float circleX = _DistanceFromCenter * cos(angle * _CircleNumber);
     float circleY = _DistanceFromCenter * sin(angle * _CircleNumber);

     float distance = length(uv - float2(circleX, circleY) * aspectRatio);

     float circlePattern = smoothstep(_CircleRadius, _CircleRadius + 0.01, distance);

     fixed4 smallCircleColor = _CircleColor;

     fixed4 result = lerp(_BackgroundColor, smallCircleColor, circlePattern);

     return result;
}

我试图改变计算纵横比的方式,但是我所做的任何事情都会使其远离中心,所以我只是坚持使用我能得到的最接近的东西。

完整代码
请参阅下面的完整脚本。

Shader "Magnality/Loading/LoadingCircle"
{
    Properties
    {
        _BackgroundColor("Background Color", Color) = (0, 0, 0, 0)
        _CircleColor("Circle Color", Color) = (1, 1, 1, 1)
        _CircleRadius("Circle Radius", Float) = 0.1
        _CircleNumber("Circle Number", Int) = 10
        _DistanceFromCenter("Distance from Center", Float) = 0.2

        [HideInInspector] _MainTex("Dummy Texture", 2D) = "white" { }
    }
    SubShader
    {
    Tags { "RenderType"="Opaque" }
    LOD 100

    Pass
    {
        CGPROGRAM
        #pragma vertex vert
        #pragma fragment frag          

        #include "UnityCG.cginc"

        struct appdata
        {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
        };

        struct v2f
        {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
        };

        fixed4 _BackgroundColor;
        fixed4 _CircleColor;
        float _CircleRadius;
        int _CircleNumber;
        float _DistanceFromCenter;


        v2f vert (appdata v)
        {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.uv = v.uv;
            return o;
        }

        fixed4 frag(v2f i) : SV_Target
        {
             float aspectRatio = _ScreenParams.x / _ScreenParams.y;

             float2 center = (0.5 * aspectRatio, 0.5);

             float2 uv = i.uv - center;

             uv.x *= aspectRatio;

             float angle = atan2(uv.y, uv.x);

             angle = (angle < 0) ? (angle + UNITY_TWO_PI) : angle;

             float circleX = _DistanceFromCenter * cos(angle * _CircleNumber);
             float circleY = _DistanceFromCenter * sin(angle * _CircleNumber);

             float distance = length(uv - float2(circleX, circleY) * aspectRatio);

             float circlePattern = smoothstep(_CircleRadius, _CircleRadius + 0.01, distance);

             fixed4 smallCircleColor = _CircleColor;

             fixed4 result = lerp(_BackgroundColor, smallCircleColor, circlePattern);

             return result;
        }
        ENDCG
    }
  } 
}

非常感谢任何建议。

unity-game-engine shader hlsl
1个回答
0
投票

看起来您的问题来自于您对变量

angle
的使用 - 它的计算方式是屏幕中心和正在渲染的像素之间的角度 - 但它的使用方式就好像它是屏幕中心之间的角度一样和圆的中心。圆心只能位于设定的角度(例如 0、45、90 等度),而不是代码中
angle
变量指定的角度。

一种更简单的方法是将问题简化为一个象限并旋转角度变量,使其始终位于该象限中,然后为该象限内的圆设定一个固定位置。您可以获取相对于中心的 UV 变量,然后旋转它,就好像它是第一个“象限”的一部分一样,然后针对这种情况求解它。

这是该方法的一个工作示例:

        fixed4 frag(v2f i) : SV_Target
        {
             float aspectRatio = _ScreenParams.x / _ScreenParams.y;

             float2 center = (0.5 * aspectRatio, 0.5);

             float2 uv = i.uv - center;

             uv.x *= aspectRatio;

             float angle = atan2(uv.y, uv.x);
             angle = (angle < 0) ? (angle + UNITY_TWO_PI) : angle;

             float quadrantSize = UNITY_TWO_PI / _CircleNumber;
             float quadrantAngle = (angle) % (quadrantSize) - quadrantSize/2;
             
             float uvLength = length(uv);
             float qX = uvLength * cos(quadrantAngle);
             float qY = uvLength * sin(quadrantAngle);

             float circleX = _DistanceFromCenter;
             float circleY = 0;

             float dist = distance(float2(qX, qY), float2(circleX, circleY) * aspectRatio);

             float circlePattern = smoothstep(_CircleRadius, _CircleRadius + 0.01, dist);

             fixed4 smallCircleColor = _CircleColor;

             fixed4 result = lerp(_BackgroundColor, smallCircleColor, circlePattern);

             return result;
        }

它与您的代码基本相同,但它将圆位置硬编码为

(_DistanceFromCenter, 0)
,并通过仅对其进行取模将
angle
转换为
quadrantAngle
,以便角度始终在
-0.5*(2PI/_CircleNumber)
0.5*(2PI/_CircleNumber)
之间,创建旋转对称,然后重新创建相对于象限的 UV 位置(
qX
qY
)。

© www.soinside.com 2019 - 2024. All rights reserved.