Created
October 26, 2019 11:14
-
-
Save mzandvliet/fd5a1abb4a7767e28080e465211edbc9 to your computer and use it in GitHub Desktop.
Sketch of how you procedurally generate data using Burst, then pass it to gpu through compute buffers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// C# side | |
public class LineRenderer : MonoBehaviour { | |
[SerializeField] private Camera _camera; | |
[SerializeField] private Material _lineMaterial; | |
private NativeArray<float3> _linePoints; | |
private ComputeBuffer _linePointBuffer; | |
private ComputeBuffer _lineIndexBuffer; | |
private int _lineCount; | |
private void Awake() { | |
_linePoints = new NativeArray<float3>(_lineCapacity * _numPointsPerLine, Allocator.Persistent, NativeArrayOptions.ClearMemory); | |
var indices = new uint[] { 2, 1, 0, 1, 2, 3 }; // left right left, right left right | |
_lineIndexBuffer = new ComputeBuffer(indices.Length, sizeof(uint)); | |
_lineIndexBuffer.SetData(indices); | |
_linePointBuffer = new ComputeBuffer(_linePoints.Length, Marshal.SizeOf(typeof(float3))); | |
_linePointBuffer.SetData(_linePoints); | |
var commandBuffer = new CommandBuffer(); | |
commandBuffer.DrawProcedural(Matrix4x4.identity, _lineMaterial, 0, MeshTopology.Triangles, 6, 4); | |
_camera.AddCommandBuffer(CameraEvent.AfterForwardOpaque, commandBuffer); | |
_lineMaterial.SetBuffer("indices", _lineIndexBuffer); | |
_lineMaterial.SetBuffer("points", _linePointBuffer); | |
} | |
private void OnDestroy() { | |
_linePoints.Dispose(); | |
_linePointBuffer.Dispose(); | |
_lineIndexBuffer.Dispose(); | |
} | |
} | |
// GPU side | |
Shader "Custom/TessellatedLine" { | |
Properties { | |
_MainTex("Texture", 2D) = "white" {} | |
} | |
SubShader{ | |
Tags{ "LightMode" = "ForwardBase" } | |
Cull Back | |
Pass{ | |
CGPROGRAM | |
#include "UnityCG.cginc" | |
#pragma target 5.0 | |
#pragma vertex vertex_shader | |
#pragma fragment fragment_shader | |
sampler2D _MainTex; | |
float4 _MainTex_ST; | |
uniform fixed4 _LightColor0; | |
float _AspectRatio; | |
StructuredBuffer<float3> points; | |
StructuredBuffer<uint> indices; // Since Unity doesn't offer DrawProceduralIndexed | |
struct v2f { | |
float4 pos : SV_POSITION; | |
float4 col : COLOR; | |
float2 uv : TEXCOORD0; | |
}; | |
v2f vertex_shader(uint id : SV_VertexID, uint inst : SV_InstanceID) | |
{ | |
v2f o; | |
// evens are left, odds are right -> -1 or 1 | |
int side = (id % 2) * 2 - 1; | |
// high indices are part of the end of segment, low indices are part of the start | |
int bottomTop = indices[id] > 1 ? 1 : 0; | |
float4 posA = mul(UNITY_MATRIX_VP, float4(points[inst * 2 + 0], 1)); | |
float4 posB = mul(UNITY_MATRIX_VP, float4(points[inst * 2 + 1], 1)); | |
float3 worldPos = points[inst * 2 + bottomTop]; | |
float4 tangentScreen = posB - posA; | |
float2 normalScreen = normalize(float2(-tangentScreen.y, tangentScreen.x)); | |
normalScreen.x /= _AspectRatio; | |
o.pos = mul(UNITY_MATRIX_VP, float4(worldPos, 1)); | |
o.pos += float4(normalScreen * (0.5 * side), 0, 0); | |
float2 uv = float2(1 - (id % 2), id / 2);//float2((id % 2), (id / 2) % 2); | |
o.uv = TRANSFORM_TEX(uv, _MainTex); | |
o.col = float4(id % 3 == 0, id % 3 == 1, id % 3 == 2, 1); | |
return o; | |
} | |
fixed4 fragment_shader(v2f i) : SV_Target | |
{ | |
fixed4 final = tex2D(_MainTex, i.uv); | |
final *= i.col; | |
return final; | |
} | |
ENDCG | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment