You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中如何绘制屏幕空间下宽度恒定的线条?

Unity实现屏幕宽度恒定的线条方案

方案一:自定义Shader适配LineRenderer

这是最接近KSP轨道线效果的方案,通过Shader将线条宽度转换为屏幕空间单位,彻底抵消透视投影的缩放影响。

Shader代码示例

Shader "Custom/ScreenSpaceLine"
{
    Properties
    {
        _LineColor ("Line Color", Color) = (1,1,1,1)
        _LineWidth ("Line Width (Pixels)", Float) = 2.0
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
        LOD 100
        Blend SrcAlpha OneMinusSrcAlpha
        ZWrite Off

        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;
                float4 screenPos : TEXCOORD1;
            };

            fixed4 _LineColor;
            float _LineWidth;

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

            fixed4 frag (v2f i) : SV_Target
            {
                // 计算屏幕空间的宽度因子,抵消透视缩放
                float widthFactor = _LineWidth / _ScreenParams.y;
                float2 screenUV = i.screenPos.xy / i.screenPos.w;
                float2 uv = i.uv;

                // 计算线条边缘的抗锯齿
                float edge = smoothstep(0.5 - widthFactor, 0.5, uv.y) - smoothstep(0.5, 0.5 + widthFactor, uv.y);
                fixed4 col = _LineColor * edge;
                return col;
            }
            ENDCG
        }
    }
}

使用方法

  1. 创建上述Shader并赋予LineRenderer的材质
  2. 在材质面板调整Line Width (Pixels)参数,设置你想要的固定屏幕像素宽度
  3. LineRenderer的Width属性可以设为1(Shader会忽略其世界空间宽度,改用屏幕像素宽度)

方案二:动态计算世界空间宽度(无需自定义Shader)

如果不想编写Shader,可以通过脚本实时计算每个线段的世界空间宽度,抵消透视带来的缩放。核心逻辑是:根据线段到相机的距离,计算对应的世界空间宽度,保证屏幕上的宽度一致。

C#代码示例

using UnityEngine;

[RequireComponent(typeof(LineRenderer))]
public class ScreenSpaceLineWidth : MonoBehaviour
{
    [Tooltip("屏幕上的固定宽度(像素)")]
    public float screenWidth = 2f;
    private LineRenderer _lineRenderer;
    private Camera _mainCamera;

    void Start()
    {
        _lineRenderer = GetComponent<LineRenderer>();
        _mainCamera = Camera.main;
        UpdateLineWidths();
    }

    void Update()
    {
        UpdateLineWidths();
    }

    void UpdateLineWidths()
    {
        int pointCount = _lineRenderer.positionCount;
        if (pointCount < 2) return;

        float[] widths = new float[pointCount];
        for (int i = 0; i < pointCount; i++)
        {
            Vector3 worldPos = _lineRenderer.GetPosition(i);
            // 计算点到相机的距离
            float distance = Vector3.Distance(_mainCamera.transform.position, worldPos);
            // 转换为世界空间宽度:屏幕像素宽度 -> 视场角对应的世界单位
            float worldWidth = screenWidth * distance / (_mainCamera.pixelHeight * Mathf.Tan(_mainCamera.fieldOfView * 0.5f * Mathf.Deg2Rad));
            widths[i] = worldWidth;
        }

        _lineRenderer.SetWidths(widths);
    }
}

注意事项

  • 此方案需要在Update中实时更新,若线条点较多可能有性能开销
  • 当相机FOV或分辨率变化时,脚本会自动适配

内容的提问来源于stack exchange,提问作者kharsair

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 03:01:05