Author SHA1 Message Date
Redstone1024 ef00dc22b3 GPU Function Library - Done! 2021-01-31 14:35:25 +08:00
Redstone1024 2f409b3606 Procedural Drawing 2021-01-31 14:03:48 +08:00
Redstone1024 a64346ee62 Moving Work to the GPU 2021-01-31 11:17:44 +08:00
Redstone1024 8f4b9e2ae2 From Measuring Performance 2021-01-30 15:51:13 +08:00
Redstone1024 6f6894c29c init commit 2021-01-30 15:49:10 +08:00
17 changed files with 707 additions and 21 deletions
+24
View File
@@ -0,0 +1,24 @@
#if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
StructuredBuffer<float3> _Positions;
#endif
float _Step;
void ConfigureProcedural()
{
#if defined(UNITY_PROCEDURAL_INSTANCING_ENABLED)
float3 position = _Positions[unity_InstanceID];
unity_ObjectToWorld = 0.0;
unity_ObjectToWorld._m03_m13_m23_m33 = float4(position, 1.0);
unity_ObjectToWorld._m00_m11_m22 = _Step;
#endif
}
void ShaderGraphFunction_float (float3 In, out float3 Out) {
Out = In;
}
void ShaderGraphFunction_half (half3 In, out half3 Out) {
Out = In;
}
+9
View File
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 52ba3338a3c5fd040985e2d7cd13ae29
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
+78
View File
@@ -0,0 +1,78 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Point Surface GPU
m_Shader: {fileID: 4800000, guid: 777e5d31099aed84eab73d2aff7dcfca, type: 3}
m_ShaderKeywords:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _BumpScale: 1
- _Cutoff: 0.5
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _GlossMapScale: 1
- _Glossiness: 0.5
- _GlossyReflections: 1
- _Metallic: 0
- _Mode: 0
- _OcclusionStrength: 1
- _Parallax: 0.02
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _UVSec: 0
- _ZWrite: 1
m_Colors:
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 584eab0d393b59e40ac387043a54b24f
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:
+35
View File
@@ -0,0 +1,35 @@
Shader "Graph/Point Surface GPU"
{
Properties
{
_Smoothness("Smoothness", Range(0, 1)) = 0.5
}
SubShader
{
CGPROGRAM
#pragma surface ConfigureSurface Standard fullforwardshadows addshadow
#pragma instancing_options assumeuniformscaling procedural:ConfigureProcedural
#pragma editor_sync_compilation
#pragma target 4.5
#include "Point GPU.hlsl"
struct Input
{
float3 worldPos;
};
float _Smoothness;
void ConfigureSurface(Input input, inout SurfaceOutputStandard surface)
{
surface.Albedo = saturate(input.worldPos * 0.5 + 0.5);
surface.Smoothness = _Smoothness;
}
ENDCG
}
FallBack "Diffuse"
}
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 777e5d31099aed84eab73d2aff7dcfca
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
userData:
assetBundleName:
assetBundleVariant:
+90
View File
@@ -0,0 +1,90 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &-3089080242542461839
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 2
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Point URP GPU
m_Shader: {fileID: -6465566751694194690, guid: edb00fc61da38e141a5047af96ae1a0a,
type: 3}
m_ShaderKeywords:
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
- _AlphaClip: 0
- _Blend: 0
- _BumpScale: 1
- _Cull: 2
- _Cutoff: 0.5
- _DstBlend: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _OcclusionStrength: 1
- _QueueOffset: 0
- _ReceiveShadows: 1
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _Surface: 0
- _WorkflowMode: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 1, g: 1, b: 1, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e470d4aed9c37a448b5bccf749811b9d
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 0
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: edb00fc61da38e141a5047af96ae1a0a
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}
+21 -20
View File
@@ -130,7 +130,7 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 75389716}
- component: {fileID: 75389715}
- component: {fileID: 75389717}
m_Layer: 0
m_Name: Graph
m_TagString: Untagged
@@ -138,25 +138,6 @@ GameObject:
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &75389715
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 75389714}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 14cd06bfa92d53e4ebc0cde4a0e39db8, type: 3}
m_Name:
m_EditorClassIdentifier:
pointPrefab: {fileID: 5221897554875366738, guid: d73a635284aa0ca4eb9cc40879b3267d,
type: 3}
resolution: 50
function: 4
transitionMode: 2
functionDuration: 1
transitionDuration: 1
--- !u!4 &75389716
Transform:
m_ObjectHideFlags: 0
@@ -171,6 +152,26 @@ Transform:
m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &75389717
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 75389714}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e99d61420a0d1f459f961121d6fbe77, type: 3}
m_Name:
m_EditorClassIdentifier:
computeShader: {fileID: 7200000, guid: c7f7fcb3b4a90614b80aa341489318e7, type: 3}
material: {fileID: 2100000, guid: e470d4aed9c37a448b5bccf749811b9d, type: 2}
mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0}
resolution: 1000
function: 4
transitionMode: 1
functionDuration: 1
transitionDuration: 1
--- !u!1 &705507993
GameObject:
m_ObjectHideFlags: 0
+155
View File
@@ -0,0 +1,155 @@
#pragma kernel WaveKernel
#pragma kernel WaveToMultiWaveKernel
#pragma kernel WaveToRippleKernel
#pragma kernel WaveToSphereKernel
#pragma kernel WaveToTorusKernel
#pragma kernel MultiWaveToWaveKernel
#pragma kernel MultiWaveKernel
#pragma kernel MultiWaveToRippleKernel
#pragma kernel MultiWaveToSphereKernel
#pragma kernel MultiWaveToTorusKernel
#pragma kernel RippleToWaveKernel
#pragma kernel RippleToMultiWaveKernel
#pragma kernel RippleKernel
#pragma kernel RippleToSphereKernel
#pragma kernel RippleToTorusKernel
#pragma kernel SphereToWaveKernel
#pragma kernel SphereToMultiWaveKernel
#pragma kernel SphereToRippleKernel
#pragma kernel SphereKernel
#pragma kernel SphereToTorusKernel
#pragma kernel TorusToWaveKernel
#pragma kernel TorusToMultiWaveKernel
#pragma kernel TorusToRippleKernel
#pragma kernel TorusToSphereKernel
#pragma kernel TorusKernel
RWStructuredBuffer<float3> _Positions;
uint _Resolution;
float _Step;
float _Time;
float _TransitionProgress;
float2 GetUV(uint3 id)
{
return (id.xy + 0.5) * _Step - 1.0;
}
void SetPositions(uint3 id, float3 positions)
{
if (id.x < _Resolution && id.y < _Resolution)
{
_Positions[id.x + id.y * _Resolution] = positions;
}
}
#define PI 3.14159265358979323846
float3 Wave(float u, float v, float t)
{
float3 p;
p.x = u;
p.y = sin(PI * (u + v + t));
p.z = v;
return p;
}
float3 MultiWave(float u, float v, float t)
{
float3 p;
p.x = u;
p.y = sin(PI * (u + 0.5 * t));
p.y += 0.5 * sin(2.0 * PI * (v + t));
p.y += sin(PI * (u + v + 0.25 * t));
p.y *= 1.0 / 2.5;
p.z = v;
return p;
}
float3 Ripple(float u, float v, float t)
{
float d = sqrt(u * u + v * v);
float3 p;
p.x = u;
p.y = sin(PI * (4.0 * d - t));
p.y /= 1.0 + 10.0 * d;
p.z = v;
return p;
}
float3 Sphere(float u, float v, float t)
{
float r = 0.9 + 0.1 * sin(PI * (6.0 * u + 4.0 * v + t));
float s = r * cos(0.5 * PI * v);
float3 p;
p.x = s * sin(PI * u);
p.y = r * sin(0.5 * PI * v);
p.z = s * cos(PI * u);
return p;
}
float3 Torus(float u, float v, float t)
{
float r1 = 0.7 + 0.1 * sin(PI * (6.0 * u + 0.5 * t));
float r2 = 0.15 + 0.05 * sin(PI * (8.0 * u + 4.0 * v + 2.0 * t));
float s = r1 + r2 * cos(PI * v);
float3 p;
p.x = s * sin(PI * u);
p.y = r2 * sin(PI * v);
p.z = s * cos(PI * u);
return p;
}
#define KERNEL_FUNCTION(function) \
[numthreads(8, 8, 1)] \
void function##Kernel(uint3 id : SV_DISPATCHTHREADID) \
{ \
float2 uv = GetUV(id); \
SetPositions(id, function(uv.x, uv.y, _Time)); \
}
KERNEL_FUNCTION(Wave)
KERNEL_FUNCTION(MultiWave)
KERNEL_FUNCTION(Ripple)
KERNEL_FUNCTION(Sphere)
KERNEL_FUNCTION(Torus)
#define KERNEL_MOPH_FUNCTION(functionA, functionB) \
[numthreads(8, 8, 1)] \
void functionA##To##functionB##Kernel(uint3 id : SV_DISPATCHTHREADID) \
{ \
float2 uv = GetUV(id); \
float3 position = lerp(functionA(uv.x, uv.y, _Time), functionB(uv.x, uv.y, _Time), _TransitionProgress); \
SetPositions(id, position); \
}
KERNEL_MOPH_FUNCTION(Wave, MultiWave)
KERNEL_MOPH_FUNCTION(Wave, Ripple)
KERNEL_MOPH_FUNCTION(Wave, Sphere)
KERNEL_MOPH_FUNCTION(Wave, Torus)
KERNEL_MOPH_FUNCTION(MultiWave, Wave)
KERNEL_MOPH_FUNCTION(MultiWave, Ripple)
KERNEL_MOPH_FUNCTION(MultiWave, Sphere)
KERNEL_MOPH_FUNCTION(MultiWave, Torus)
KERNEL_MOPH_FUNCTION(Ripple, Wave)
KERNEL_MOPH_FUNCTION(Ripple, MultiWave)
KERNEL_MOPH_FUNCTION(Ripple, Sphere)
KERNEL_MOPH_FUNCTION(Ripple, Torus)
KERNEL_MOPH_FUNCTION(Sphere, Wave)
KERNEL_MOPH_FUNCTION(Sphere, MultiWave)
KERNEL_MOPH_FUNCTION(Sphere, Ripple)
KERNEL_MOPH_FUNCTION(Sphere, Torus)
KERNEL_MOPH_FUNCTION(Torus, Wave)
KERNEL_MOPH_FUNCTION(Torus, MultiWave)
KERNEL_MOPH_FUNCTION(Torus, Ripple)
KERNEL_MOPH_FUNCTION(Torus, Sphere)
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c7f7fcb3b4a90614b80aa341489318e7
ComputeShaderImporter:
externalObjects: {}
currentAPIMask: 4
userData:
assetBundleName:
assetBundleVariant:
+2
View File
@@ -9,6 +9,8 @@ public static class FunctionLibrary
private static Function[] functions = { Wave, MultiWave, Ripple, Sphere, Torus };
public static int functionCount => functions.Length;
public static Function GetFunction(FunctionName name)
{
return functions[(int)name];
+110
View File
@@ -0,0 +1,110 @@
using UnityEngine;
public class GPUGraph : MonoBehaviour
{
[SerializeField]
ComputeShader computeShader = default;
[SerializeField]
Material material = default;
[SerializeField]
Mesh mesh = default;
const int maxResolution = 1000;
[SerializeField, Range(10, maxResolution)]
int resolution = 10;
[SerializeField]
FunctionLibrary.FunctionName function = default;
public enum TransitionMode { Normal, Cycle, Random }
[SerializeField]
TransitionMode transitionMode = TransitionMode.Normal;
[SerializeField, Min(0.0f)]
float functionDuration = 1.0f;
[SerializeField, Min(0.0f)]
float transitionDuration = 1.0f;
float duration = 0.0f;
bool transitioning;
FunctionLibrary.FunctionName transitionFunction;
ComputeBuffer positionsBuffer;
static readonly int positionsId = Shader.PropertyToID("_Positions");
static readonly int resolutionId = Shader.PropertyToID("_Resolution");
static readonly int stepId = Shader.PropertyToID("_Step");
static readonly int timeId = Shader.PropertyToID("_Time");
static readonly int transitionProgressId = Shader.PropertyToID("_TransitionProgress");
private void OnEnable()
{
positionsBuffer = new ComputeBuffer(maxResolution * maxResolution, 3 * 4);
}
private void OnDisable()
{
positionsBuffer.Release();
positionsBuffer = null;
}
private void Update()
{
duration += Time.deltaTime;
if (transitioning)
{
if (duration >= transitionDuration)
{
duration -= transitionDuration;
transitioning = false;
}
}
else if (duration >= functionDuration)
{
duration -= functionDuration;
transitioning = true;
transitionFunction = function;
PickNextFunction();
}
UpdateFunctionOnGPU();
}
private void PickNextFunction()
{
if (transitionMode == TransitionMode.Normal) return;
function = transitionMode == TransitionMode.Cycle ?
FunctionLibrary.GetNextFunctionName(function) :
FunctionLibrary.GetRandomFunctionNameOtherThan(function);
}
private void UpdateFunctionOnGPU()
{
var step = 2f / resolution;
computeShader.SetInt(resolutionId, resolution);
computeShader.SetFloat(stepId, step);
computeShader.SetFloat(timeId, Time.time);
if (transitioning)
{
computeShader.SetFloat(transitionProgressId, Mathf.SmoothStep(0f, 1f, duration / transitionDuration));
}
var kernelIndex = (int)function +
(int)(transitioning ? transitionFunction : function) * FunctionLibrary.functionCount;
computeShader.SetBuffer(kernelIndex, positionsId, positionsBuffer);
var groups = Mathf.CeilToInt(resolution / 8f);
computeShader.Dispatch(kernelIndex, groups, groups, 1);
material.SetBuffer(positionsId, positionsBuffer);
material.SetFloat(stepId, step);
var bounds = new Bounds(Vector3.zero, Vector3.one * (2f + 2f / resolution));
Graphics.DrawMeshInstancedProcedural(mesh, 0, material, bounds, resolution * resolution);
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4e99d61420a0d1f459f961121d6fbe77
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+1 -1
View File
@@ -5,7 +5,7 @@ public class Graph : MonoBehaviour
[SerializeField]
Transform pointPrefab = default;
[SerializeField, Range(10, 100)]
[SerializeField, Range(10, 200)]
int resolution = 10;
[SerializeField]