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

5vf7fwbs  于 2023-11-22  发布在  其他
关注(0)|答案(1)|浏览(248)
  • 我使用Unity游戏引擎和着色器代码(我是初学者)。*
    目标

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


的数据

  • 问题 *

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


我的设置

这个着色器的材质被应用到画布中的一个面板上,我使用的是uv(见下图)。

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

字符串

问题代码

我认为问题在于我在frag函数中计算长宽比、Angular 或距离的方式(见下文)。

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
    }
  } 
}


任何建议都非常感谢。

imzjd6km

imzjd6km1#

看起来你的问题是来自你使用的变量angle-它被计算为屏幕中心和正在渲染的像素之间的Angular -但它被使用,好像它是屏幕中心和圆心之间的Angular 。圆心应该只在设定的Angular (例如,8个圆的0,45,90度等),而不是在代码中angle变量指定的Angular 。
一个更简单的方法是将问题缩小到一个象限,旋转Angular 变量,使其始终位于该象限内,然后在该象限内设置圆的位置。您可以将相对于中心的UV变量,然后旋转它,就像它是第一个“象限”的一部分一样,然后仅针对该情况求解。
例如,如果你想渲染8个圆,Angular 为3度,48度,93度等的像素都应该渲染出来-因为你试图创建的旋转对称,每45度应该是相同的,所以这些情况是相同的。所以你可以只将这些Angular 转换为一个最简单的情况,然后就像只有一个圆一样-你得到了旋转对称,它渲染了所有8个圆。
下面是该方法的一个粗略的工作示例:

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,只需要对它做一个模运算,这样Angular 总是在-0.5*(2PI/_CircleNumber)0.5*(2PI/_CircleNumber)之间,以创建旋转对称,然后重新创建一个象限相对UV位置(qXqY),以计算出到圆的距离。

相关问题