1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Graphics.DrawProceduralで好きな形状のポリゴンを描画

Last updated at Posted at 2024-02-28

Graphics.DrawProceduralを使って、
Meshではないポリゴンを描画するサンプルです。
Meshじゃないので変形が楽。indexの数指定出来るので、OpenGL直叩きしてた頃のように可変数のポリゴン描ける。自前でライン描画したい時とかに使えそう。

一応影にも対応させておいた。

ただし現状WebGLでは使えない。StructuredBufferが未対応のため。Graphics.RenderPrimitiveも同様の理由で使えない。

自分用備忘録なので細かい説明は省略します。

Test.cs
///
/// @file   Test.cs
/// @author Kyosei Yukimoto <kochiyukimoto@gmail.com>
/// @date   
///
/// @brief プリミティブ描画実験
///
using UnityEngine;

namespace ProjectMain
{
    public class Test : MonoBehaviour
    {
        // inspector
        [SerializeField] string LayerName = "Default";
        [SerializeField] Material Material;
        [SerializeField] float BoundsSize = 1000;

        // material
        MaterialPropertyBlock MaterialProps;

        // data
        GraphicsBuffer Triangles;
        ComputeBuffer Positions;
        ComputeBuffer UVs;
        int Layer;

        // OnDestroy
        void OnDestroy()
        {
            // dispose
            UVs?.Dispose();
            UVs = null;
            Positions?.Dispose();
            Positions = null;
            Triangles?.Dispose();
            Triangles = null;
            MaterialProps = null;
        }

        // Start
        void Start()
        {
            // material
            MaterialProps = new MaterialPropertyBlock();

            // レイヤー
            Layer = LayerMask.NameToLayer(LayerName);

            // IndexBuffer
            int[] indices =
            {
                0, 2, 1,
            };
            Triangles = new GraphicsBuffer(GraphicsBuffer.Target.Structured, indices.Length, sizeof(int));
            Triangles.SetData(indices);

            // vertices
            Vector3[] vertices =
            {
                new Vector3(-1, 0, 0),
                new Vector3( 1, 0, 0),
                new Vector3( 1, 1, 0),
            };
            Positions = new ComputeBuffer(vertices.Length, sizeof(float) * 3, ComputeBufferType.Default, ComputeBufferMode.SubUpdates);
            Positions.SetData(vertices);
            MaterialProps.SetBuffer("_Positions", Positions);

            // uvs
            Vector2[] uvs =
            {
                new Vector2(0, 0),
                new Vector2(1, 0),
                new Vector2(1, 1),
            };
            UVs = new ComputeBuffer(uvs.Length, sizeof(float) * 2);
            UVs.SetData(uvs);
            MaterialProps.SetBuffer("_UVs", UVs);
        }


        // Update
        void Update()
        {
            // 変形実験
            if (Input.GetKeyDown(KeyCode.UpArrow)) {
                var vertices = Positions.BeginWrite<Vector3>(0, Positions.count);
                vertices[2] += Vector3.up;
                Positions.EndWrite<Vector3>(Positions.count);
            }

            // 描画
            var bounds = new Bounds(ThisTransform.position, Vector3.one * BoundsSize);
            MaterialProps.SetMatrix("_ObjectToWorld", Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale));
            Graphics.DrawProcedural(Material, bounds, MeshTopology.Triangles, Triangles, Triangles.count, 1, Main.MainCamera, MaterialProps, UnityEngine.Rendering.ShadowCastingMode.On, true, Layer);
        }
    }
}
Test.shader
Shader "ProjectMain/Test"
{
    Properties
    {
        [MainTexture] _BaseMap ("BaseMap", 2D) = "white" {}
        [MainColor] _BaseColor("BaseColor", Color) = (1, 1, 1, 1)
        _ShadowAlpha("ShadowAlpha", float) = 1
    }
    SubShader
    {
        Tags {
            "RenderType"="Opaque"
            "RenderPipeline"="UniversalPipeline" // Unity2021では "RenderPipeline"="UniversalRenderPipeline" だったような
            "Queue"="Geometry"
        }
        
        Pass
        {
            Tags { "LightMode"="UniversalForward" }

            HLSLPROGRAM
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fog
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS
            #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE
            #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS
            #pragma multi_compile _ _SHADOWS_SOFT

            struct v2f
            {
                float4 vertex : SV_POSITION;
                float3 posWS : TEXCOORD0;
                float fogFactor: TEXCOORD1;
                float2 uv : TEXCOORD2;
            };

            StructuredBuffer<float3> _Positions;
            StructuredBuffer<float2> _UVs;
            float4x4 _ObjectToWorld;
            float4 _BaseColor;
            float _ShadowAlpha;
            sampler2D _BaseMap;
            float4 _BaseMap_ST;

            v2f vert(uint vertexID: SV_VertexID, uint instanceID : SV_InstanceID)
            {
                v2f o;
                float3 pos = _Positions[vertexID];
                float2 uv = _UVs[vertexID];
                o.posWS = mul(_ObjectToWorld, float4(pos, 1)).xyz;
                o.vertex = TransformWorldToHClip(o.posWS);
                o.fogFactor = ComputeFogFactor(o.vertex.z);
                o.uv = TRANSFORM_TEX(uv, _BaseMap);
                return o;
            }

            float4 frag(v2f i) : SV_Target
            {
                float4 shadowCoord = TransformWorldToShadowCoord(i.posWS);
                Light mainLight = GetMainLight(shadowCoord);
                half shadow = mainLight.shadowAttenuation;
                Light addLight0 = GetAdditionalLight(0, i.posWS);
                shadow *= addLight0.shadowAttenuation;
                float4 col = tex2D(_BaseMap, i.uv) * _BaseColor;
                shadow = 1 - (1 - shadow) * _ShadowAlpha;
                col.rgb *= shadow;
                col.rgb = MixFog(col.rgb, i.fogFactor);
                return col;
            }
            ENDHLSL
        }

        Pass
        {
            Tags { "LightMode"="ShadowCaster" }

            HLSLPROGRAM
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_shadowcaster

            struct v2f
            {
                float4 vertex : SV_POSITION;
            };

            StructuredBuffer<float3> _Positions;
            float4x4 _ObjectToWorld;

            v2f vert(uint vertexID: SV_VertexID, uint instanceID : SV_InstanceID)
            {
                v2f o;
                float3 pos = _Positions[vertexID];
                float3 posWS = mul(_ObjectToWorld, float4(pos, 1)).xyz;
                o.vertex = TransformWorldToHClip(posWS);
                return o;
            }

            float4 frag(v2f i) : SV_Target
            {
                return float4(0, 0, 0, 1);
            }
            ENDHLSL
        }

        // Used for rendering shadowmaps
        UsePass "Universal Render Pipeline/Lit/ShadowCaster"
    }
}

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?