unity3d 更改linerender中每个元素的颜色不起作用

o8x7eapl  于 2023-03-19  发布在  其他
关注(0)|答案(3)|浏览(552)

我想改变每一行(元素)的颜色,就像在颜色切换。但我的代码不工作。我的代码有什么问题?

void Start()
{
    lineGeneratorPrefab = new GameObject();
    DrawLine();
}

private void DrawLine()
{
    GameObject myLine = new GameObject();
    myLine.transform.position = start;
    myLine.AddComponent<LineRenderer>();
    LineRenderer lr = myLine.GetComponent<LineRenderer>();

    lr.positionCount = 4;

    lr.SetPosition(0, new Vector3(-2, 0, 0));
    lr.SetPosition(1, new Vector3(2, 0, 0));
    lr.SetPosition(2, new Vector3(2, -2, 0));
    lr.SetPosition(3, new Vector3(-2, -2, 0));
    lr.materials[2].color = Color.blue;
    lr.materials[3].color = Color.red;
}
rxztt3cl

rxztt3cl1#

看看here
您可以通过colorGradient属性更改线条呈现器的渐变,而不是更改各种材质。
因此,在您的情况下,您可以添加以下内容:

gradient.SetKeys(
    new GradientColorKey[] { 
            new GradientColorKey(Color.red,0.0f), 
            new GradientColorKey(Color.red, 0.25f),
            new GradientColorKey(Color.blue, 0.5f),
            new GradientColorKey(Color.blue, 1.0f)},
            // Alpha key
        );

如果需要更突然的过渡,可以在0.49和0.51处添加颜色关键帧。

42fyovps

42fyovps2#

谢谢你的回答KTobiasson!我确实移植了你的着色器来使用内置的渲染管道。代码只是稍微修改了一下,因为我需要线是透明的,并且在VR中正确渲染。

Shader "Unlit/CustomLineRenderer"
{
    Properties
    {
        [MainColor] _ColorTint("Tint", Color) = (1, 1, 1, 1)
        _VertexColorMap("Vertex Color Map", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Transparent"}
        LOD 100
        
        ZWrite Off
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
    
            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                uint vertexID : SV_VertexID;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct Interpolators {
                float4 color : COLOR;
                float4 vertex  : SV_POSITION;
                UNITY_VERTEX_OUTPUT_STEREO
            };
            
            sampler2D _VertexColorMap;

            CBUFFER_START(UnityPerMaterial)
                float4 _VertexColorMap_ST;
                float4 _ColorTint;
                float4 _VertexColorMap_TexelSize;
            CBUFFER_END
            
            Interpolators vert (appdata v)
            {
                Interpolators o;

                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                
                float2 uv = float2((v.vertexID == 0) ? _VertexColorMap_TexelSize.x : v.vertexID * _VertexColorMap_TexelSize.x, 0.5);
                o.color = tex2Dlod(_VertexColorMap, float4(uv.xy, 0.0f, 0.0f));
                o.vertex = UnityObjectToClipPos(v.vertex.xyz);
                
                return o;
            }
            
            fixed4 frag (Interpolators i) : SV_Target
            {
                return i.color * _ColorTint;
            }
            ENDCG
        }
    }
}
pxyaymoc

pxyaymoc3#

我也遇到过这个问题,无论你是否把渐变键设置得很紧,都会发生意想不到的颜色混合,除非你的LineRenderer分辨率真的很高。我的用例根本不需要混合(只是颜色之间的突然变化)。我通过创建一个着色器来解决这个问题,该着色器基于运行时设置的顶点颜色贴图/纹理来改变顶点颜色。
要使其工作,LineRenderer需要在Corner Vertices属性中至少设置一个。您还需要设置颜色发生变化的位置,但我使其易于与以下着色器、类和结构一起使用。
以下是着色器(未点亮且适用于URP):

Shader "Unlit/LineRenderer"
{
    Properties {
        [Header(Surface options)]

        [MainColor] _ColorTint("Tint", Color) = (1, 1, 1, 1)
        _VertexColorMap("Vertex Color Map", 2D) = "white"
    }
    SubShader{

        Tags {"RenderType" = "Opaque" "IgnoreProjector" = "True" "RenderPipeline" = "UniversalPipeline"}
        LOD 100

        Pass
        {
            Name "ForwardLit"
            Tags{"LightMode" = "UniversalForward"}

            HLSLPROGRAM 

            #pragma vertex Vertex
            #pragma fragment Fragment

            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct Attributes {
                float4 positionOS   : POSITION;
                uint vertexID : SV_VertexID;
            };

            struct Interpolators {
                float4 color : COLOR;
                float4 positionHCS  : SV_POSITION;
            };

            TEXTURE2D(_VertexColorMap);
            SAMPLER(sampler_VertexColorMap);

            CBUFFER_START(UnityPerMaterial)
                float4 _VertexColorMap_ST;
                float4 _ColorTint;
                float4 _VertexColorMap_TexelSize;
            CBUFFER_END

            Interpolators Vertex(Attributes input) {
                Interpolators output;

                float2 uv = float2((input.vertexID == 0) ? _VertexColorMap_TexelSize.x : input.vertexID * _VertexColorMap_TexelSize.x, 0.5);
                output.color = SAMPLE_TEXTURE2D_ARRAY_LOD(_VertexColorMap, sampler_VertexColorMap, uv.xy, 0.0, 0.0);
                output.positionHCS = TransformObjectToHClip(input.positionOS.xyz);

                return output;
            }

            float4 Fragment(Interpolators input) : SV_TARGET {
                return input.color * _ColorTint;
            }

            ENDHLSL
        }
    }
}

只需将着色器放在材质上,并设置线条渲染器使用该材质。然后,您还需要静态LineRendererExtension类和LineRendererPositionParams结构体:

using System.Linq;
using System.Collections.Generic;
using UnityEngine;

public struct LineRendererPositionParams
{
    public Vector3 Position { get; }
    public Color32 InColor { get; }
    public Color32 OutColor { get; }

    public LineRendererPositionParams(
        Vector3 position,
        Color32 inColor,
        Color32 outColor)
    {
        Position = position;
        InColor = inColor;
        OutColor = outColor;
    }
}

public static class LineRendererExtensions
{
    public static List<Color32> SetPositionsWithColors(this LineRenderer @this, List<LineRendererPositionParams> positionParams)
    {
        @this.positionCount = positionParams.Count;
        @this.SetPositions(positionParams.Select(p => p.Position).ToArray());

        var colors = @this.GetEndCapColors(positionParams[0].InColor);

        for (var i = 1; i < positionParams.Count-1; i++)
            colors.AddRange(@this.GetSegmentConnectionColors(positionParams[i]));

        colors.AddRange(@this.GetEndCapColors(positionParams[positionParams.Count-1].InColor));

        return colors;
    }

    public static void SetVertexColorMap(this LineRenderer @this, Color32[] colors, Texture2D texture)
    {
        if (texture.width != colors.Length)
            texture.Reinitialize(colors.Length, 1);

        texture.SetPixels32(colors.ToArray());
        texture.Apply();
        @this.material.SetTexture("_VertexColorMap", texture);
    }

    private static List<Color32> GetSegmentConnectionColors(this LineRenderer @this, LineRendererPositionParams positionParams)
    {
        Debug.Assert(@this.numCornerVertices > 1,
            $"The number of corner vertices of a {nameof(LineRenderer)} cannot be less than 1 when using {nameof(LineRendererPositionParams)}");

        var colors = new List<Color32>();
        var half = (@this.numCornerVertices/2) * 2 + 2;

        for (var i = 0; i < half; i++)
            colors.Add(positionParams.InColor);

        if (@this.numCornerVertices%2 != 0)
            colors.AddRange(@this.GetMidPointColors(positionParams));

        for (var i = 0; i < half; i++)
            colors.Add(positionParams.OutColor);

        return colors;
    }

    private static List<Color32> GetMidPointColors(this LineRenderer @this, LineRendererPositionParams positionParams)
    {
        var color = Color32.Lerp(positionParams.InColor, positionParams.OutColor, 0.5f);
        return new List<Color32>() {color, color};
    }

    private static List<Color32> GetEndCapColors(this LineRenderer @this, Color32 color)
    {
        if (@this.numCapVertices == 0)
            return new List<Color32>() {color, color};

        var colors = new List<Color32>() {color, color, color, color, color, color};
        var remaining = (@this.numCapVertices - 1) * 2 + 2;

        for (var i = 0; i < remaining; i++)
            colors.Add(color);

        return colors;
    }
}

所以你只需要创建一个LineRendererPositionParams列表,其中包含LineRenderer的所有位置和颜色,然后使用扩展lineRenderer.SetPositionsWithColors(positionParams);,它返回一个颜色列表,你在另一个扩展lineRenderer.SetVertexColorMap(lineRenderer.SetPositionsWithColors(positionParams), texture);上使用它,它应该能像预期的那样工作。

相关问题