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