From 609d5c47b14fff0e185462244488fa1ecfab8f71 Mon Sep 17 00:00:00 2001 From: hoishi Date: Tue, 10 Oct 2017 16:11:11 +0900 Subject: [PATCH 1/2] =?UTF-8?q?BoidsSimulationOnGPU=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/BoidsSimulationOnGPU.meta | 9 + .../BoidsSimulationOnGPU.unity | 348 ++++++++++++++++++ .../BoidsSimulationOnGPU.unity.meta | 8 + .../BoidsSimulationOnGPU/ComputeShaders.meta | 9 + .../ComputeShaders/Boids.compute | 206 +++++++++++ .../ComputeShaders/Boids.compute.meta | 9 + Assets/BoidsSimulationOnGPU/Materials.meta | 9 + .../Materials/BoidsRender.mat | 76 ++++ .../Materials/BoidsRender.mat.meta | 9 + Assets/BoidsSimulationOnGPU/Scripts.meta | 9 + .../Scripts/BoidsRender.cs | 99 +++++ .../Scripts/BoidsRender.cs.meta | 16 + .../BoidsSimulationOnGPU/Scripts/GPUBoids.cs | 195 ++++++++++ .../Scripts/GPUBoids.cs.meta | 13 + Assets/BoidsSimulationOnGPU/Shaders.meta | 9 + .../Shaders/BoidsRender.shader | 109 ++++++ .../Shaders/BoidsRender.shader.meta | 9 + 17 files changed, 1142 insertions(+) create mode 100644 Assets/BoidsSimulationOnGPU.meta create mode 100644 Assets/BoidsSimulationOnGPU/BoidsSimulationOnGPU.unity create mode 100644 Assets/BoidsSimulationOnGPU/BoidsSimulationOnGPU.unity.meta create mode 100644 Assets/BoidsSimulationOnGPU/ComputeShaders.meta create mode 100644 Assets/BoidsSimulationOnGPU/ComputeShaders/Boids.compute create mode 100644 Assets/BoidsSimulationOnGPU/ComputeShaders/Boids.compute.meta create mode 100644 Assets/BoidsSimulationOnGPU/Materials.meta create mode 100644 Assets/BoidsSimulationOnGPU/Materials/BoidsRender.mat create mode 100644 Assets/BoidsSimulationOnGPU/Materials/BoidsRender.mat.meta create mode 100644 Assets/BoidsSimulationOnGPU/Scripts.meta create mode 100644 Assets/BoidsSimulationOnGPU/Scripts/BoidsRender.cs create mode 100644 Assets/BoidsSimulationOnGPU/Scripts/BoidsRender.cs.meta create mode 100644 Assets/BoidsSimulationOnGPU/Scripts/GPUBoids.cs create mode 100644 Assets/BoidsSimulationOnGPU/Scripts/GPUBoids.cs.meta create mode 100644 Assets/BoidsSimulationOnGPU/Shaders.meta create mode 100644 Assets/BoidsSimulationOnGPU/Shaders/BoidsRender.shader create mode 100644 Assets/BoidsSimulationOnGPU/Shaders/BoidsRender.shader.meta diff --git a/Assets/BoidsSimulationOnGPU.meta b/Assets/BoidsSimulationOnGPU.meta new file mode 100644 index 0000000..6ecd390 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: b95d633f81bd1114f97481999c5fbad6 +folderAsset: yes +timeCreated: 1507619339 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/BoidsSimulationOnGPU.unity b/Assets/BoidsSimulationOnGPU/BoidsSimulationOnGPU.unity new file mode 100644 index 0000000..2644e4b --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/BoidsSimulationOnGPU.unity @@ -0,0 +1,348 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 8 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1} +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_TemporalCoherenceThreshold: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 1 + m_LightmapEditorSettings: + serializedVersion: 9 + m_Resolution: 2 + m_BakeResolution: 40 + m_TextureWidth: 1024 + m_TextureHeight: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVRFiltering: 0 + m_PVRFilteringMode: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousColorSigma: 1 + m_PVRFilteringAtrousNormalSigma: 1 + m_PVRFilteringAtrousPositionSigma: 1 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &257653479 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 257653481} + - component: {fileID: 257653480} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &257653480 +Light: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 257653479} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 4 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_FalloffTable: + m_Table[0]: 0 + m_Table[1]: 0 + m_Table[2]: 0 + m_Table[3]: 0 + m_Table[4]: 0 + m_Table[5]: 0 + m_Table[6]: 0 + m_Table[7]: 0 + m_Table[8]: 0 + m_Table[9]: 0 + m_Table[10]: 0 + m_Table[11]: 0 + m_Table[12]: 0 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &257653481 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 257653479} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &583646679 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 583646681} + - component: {fileID: 583646680} + - component: {fileID: 583646683} + m_Layer: 0 + m_Name: GPUBoids + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &583646680 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 583646679} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4be9a8d5d645e4545886be6914d2e5e9, type: 3} + m_Name: + m_EditorClassIdentifier: + MaxObjectNum: 16384 + CohesionNeighborhoodRadius: 2 + AlignmentNeighborhoodRadius: 2 + SeparateNeighborhoodRadius: 1 + MaxSpeed: 5 + MaxSteerForce: 0.5 + CohesionWeight: 1 + AlignmentWeight: 1 + SeparateWeight: 3 + AvoidWallWeight: 10 + WallCenter: {x: 0, y: 0, z: 0} + WallSize: {x: 32, y: 32, z: 32} + BoidsCS: {fileID: 7200000, guid: 47567044d261e474db26e25410628c0a, type: 3} +--- !u!4 &583646681 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 583646679} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &583646683 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 583646679} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c1088025d887acd4189b6dc124e0ebc1, type: 3} + m_Name: + m_EditorClassIdentifier: + ObjectScale: {x: 0.1, y: 0.2, z: 0.5} + GPUBoidsScript: {fileID: 583646680} + InstanceMesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} + InstanceRenderMaterial: {fileID: 2100000, guid: 91dbb6b6149df404a986444779bcb3a3, + type: 2} +--- !u!1 &2028803004 +GameObject: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 5 + m_Component: + - component: {fileID: 2028803009} + - component: {fileID: 2028803008} + - component: {fileID: 2028803007} + - component: {fileID: 2028803006} + - component: {fileID: 2028803005} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &2028803005 +AudioListener: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 2028803004} + m_Enabled: 1 +--- !u!124 &2028803006 +Behaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 2028803004} + m_Enabled: 1 +--- !u!92 &2028803007 +Behaviour: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 2028803004} + m_Enabled: 1 +--- !u!20 &2028803008 +Camera: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 2028803004} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 + m_StereoMirrorMode: 0 +--- !u!4 &2028803009 +Transform: + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 2028803004} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/BoidsSimulationOnGPU/BoidsSimulationOnGPU.unity.meta b/Assets/BoidsSimulationOnGPU/BoidsSimulationOnGPU.unity.meta new file mode 100644 index 0000000..ebfe090 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/BoidsSimulationOnGPU.unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 90cd09b78ebf02a41b70bb555bded046 +timeCreated: 1505730664 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/ComputeShaders.meta b/Assets/BoidsSimulationOnGPU/ComputeShaders.meta new file mode 100644 index 0000000..5341d58 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/ComputeShaders.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 0032263264a507740a31df52d45c578c +folderAsset: yes +timeCreated: 1505730621 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/ComputeShaders/Boids.compute b/Assets/BoidsSimulationOnGPU/ComputeShaders/Boids.compute new file mode 100644 index 0000000..30491cb --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/ComputeShaders/Boids.compute @@ -0,0 +1,206 @@ +// カーネル関数を指定 +#pragma kernel ForceCS // 操舵力を計算 +#pragma kernel IntegrateCS // 速度, 位置を計算 + +// Boidデータの構造体 +struct BoidData +{ + float3 velocity; // 速度 + float3 position; // 位置 +}; + +// スレッドグループのスレッドのサイズ +#define SIMULATION_BLOCK_SIZE 256 + +// Boidデータのバッファ(読み取り用) +StructuredBuffer _BoidDataBufferRead; +// Boidデータのバッファ(読み取り, 書き込み用) +RWStructuredBuffer _BoidDataBufferWrite; +// Boidの操舵力のバッファ(読み取り用) +StructuredBuffer _BoidForceBufferRead; +// Boidの操舵力のバッファ(読み取り, 書き込み用) +RWStructuredBuffer _BoidForceBufferWrite; + +int _MaxBoidObjectNum; // Boidオブジェクト数 + +float _DeltaTime; // 前フレームから経過した時間 + +float _SeparateNeighborhoodRadius; // 分離を適用する他の個体との距離 +float _AlignmentNeighborhoodRadius; // 整列を適用する他の個体との距離 +float _CohesionNeighborhoodRadius; // 結合を適用する他の個体との距離 + +float _MaxSpeed; // 速度の最大値 +float _MaxSteerForce; // 操舵する力の最大値 + +float _SeparateWeight; // 分離適用時の重み +float _AlignmentWeight; // 整列適用時の重み +float _CohesionWeight; // 結合適用時の重み + +float4 _WallCenter; // 壁の中心座標 +float4 _WallSize; // 壁のサイズ +float _AvoidWallWeight; // 壁を避ける強さの重み + + +// ベクトルの大きさを制限する +float3 limit(float3 vec, float max) +{ + float length = sqrt(dot(vec, vec)); // 大きさ + return (length > max && length > 0) ? vec.xyz * (max / length) : vec.xyz; +} + +// 壁に当たった時に逆向きの力を返す +float3 avoidWall(float3 position) +{ + float3 wc = _WallCenter.xyz; + float3 ws = _WallSize.xyz; + float3 acc = float3(0, 0, 0); + // x + acc.x = (position.x < wc.x - ws.x * 0.5) ? acc.x + 1.0 : acc.x; + acc.x = (position.x > wc.x + ws.x * 0.5) ? acc.x - 1.0 : acc.x; + + // y + acc.y = (position.y < wc.y - ws.y * 0.5) ? acc.y + 1.0 : acc.y; + acc.y = (position.y > wc.y + ws.y * 0.5) ? acc.y - 1.0 : acc.y; + + // z + acc.z = (position.z < wc.z - ws.z * 0.5) ? acc.z + 1.0 : acc.z; + acc.z = (position.z > wc.z + ws.z * 0.5) ? acc.z - 1.0 : acc.z; + + return acc; +} + +// シェアードメモリ Boidデータ格納用 +groupshared BoidData boid_data[SIMULATION_BLOCK_SIZE]; + +// 操舵力の計算用カーネル関数 +[numthreads(SIMULATION_BLOCK_SIZE, 1, 1)] +void ForceCS +( + uint3 DTid : SV_DispatchThreadID, // スレッド全体で固有のID + uint3 Gid : SV_GroupID, // グループのID + uint3 GTid : SV_GroupThreadID, // グループ内のスレッドID + uint GI : SV_GroupIndex // SV_GroupThreadIDを一次元にしたもの 0-255 +) +{ + const unsigned int P_ID = DTid.x; // 自身のID + float3 P_position = _BoidDataBufferRead[P_ID].position; // 自身の位置 + float3 P_velocity = _BoidDataBufferRead[P_ID].velocity; // 自身の速度 + + float3 force = float3(0, 0, 0); // 操舵力を初期化 + + float3 sepPosSum = float3(0, 0, 0); // 分離計算用 位置加算変数 + int sepCount = 0; // 分離のために計算した他の個体の数のカウント用変数 + + float3 aliVelSum = float3(0, 0, 0); // 整列計算用 速度加算変数 + int aliCount = 0; // 整列のために計算した他の個体の数のカウント用変数 + + float3 cohPosSum = float3(0, 0, 0); // 結合計算用 位置加算変数 + int cohCount = 0; // 結合のために計算した他の個体の数のカウント用変数 + + // SIMULATION_BLOCK_SIZE(グループスレッド数)ごとの実行 (グループ数分実行) + [loop] + for (uint N_block_ID = 0; N_block_ID < (uint)_MaxBoidObjectNum; + N_block_ID += SIMULATION_BLOCK_SIZE) + { + // SIMULATION_BLOCK_SIZE分のBoidデータを、シェアードメモリに格納 + boid_data[GI] = _BoidDataBufferRead[N_block_ID + GI]; + + // すべてのグループ共有アクセスが完了し、 + // グループ内のすべてのスレッドがこの呼び出しに到達するまで、 + // グループ内のすべてのスレッドの実行をブロックする + GroupMemoryBarrierWithGroupSync(); + + // 他の個体との計算 + for (int N_tile_ID = 0; N_tile_ID < SIMULATION_BLOCK_SIZE; N_tile_ID++) + { + float3 N_position = boid_data[N_tile_ID].position; // 他の個体の位置 + float3 N_velocity = boid_data[N_tile_ID].velocity; // 他の個体の速度 + + float3 diff = P_position - N_position; // 自身と他の個体の位置の差 + float dist = sqrt(dot(diff, diff)); // 自身と他の個体の位置の距離 + + // --- 分離(Separation) --- + if (dist > 0.0 && dist <= _SeparateNeighborhoodRadius) + { + // 他の個体の位置から自身へ向かうベクトル + float3 repulse = normalize(P_position - N_position); + // 自身と他の個体の位置の距離で割る(距離が遠ければ影響を小さく) + repulse /= dist; + sepPosSum += repulse; // 加算 + sepCount++; // 個体数カウント + } + + // --- 整列(Alignment) --- + if (dist > 0.0 && dist <= _AlignmentNeighborhoodRadius) + { + aliVelSum += N_velocity; // 加算 + aliCount++; // 個体数カウント + } + + // --- 結合(Cohesion) --- + if (dist > 0.0 && dist <= _CohesionNeighborhoodRadius) + { + cohPosSum += N_position; // 加算 + cohCount++; // 個体数カウント + } + } + GroupMemoryBarrierWithGroupSync(); + } + + // 操舵力(分離) + float3 sepSteer = (float3)0.0; + if (sepCount > 0) + { + sepSteer = sepPosSum / (float)sepCount; // 平均を求める + sepSteer = normalize(sepSteer) * _MaxSpeed; // 最大速度に調整 + sepSteer = sepSteer - P_velocity; // 操舵力を計算 + sepSteer = limit(sepSteer, _MaxSteerForce); // 操舵力を制限 + } + + // 操舵力(整列) + float3 aliSteer = (float3)0.0; + if (aliCount > 0) + { + aliSteer = aliVelSum / (float)aliCount; // 近い個体の速度の平均を求める + aliSteer = normalize(aliSteer) * _MaxSpeed; // 最大速度に調整 + aliSteer = aliSteer - P_velocity; // 操舵力を計算 + aliSteer = limit(aliSteer, _MaxSteerForce); // 操舵力を制限 + } + // 操舵力(結合) + float3 cohSteer = (float3)0.0; + if (cohCount > 0) + { + cohPosSum = cohPosSum / (float)cohCount; // 近い個体の位置の平均を求める + cohSteer = cohPosSum - P_position; // 平均位置方向へのベクトルを求める + cohSteer = normalize(cohSteer) * _MaxSpeed; // 最大速度に調整 + cohSteer = cohSteer - P_velocity; // 操舵力を計算 + cohSteer = limit(cohSteer, _MaxSteerForce); // 操舵力を制限 + } + force += aliSteer * _AlignmentWeight; // 操舵力に整列する力を加える + force += cohSteer * _CohesionWeight; // 操舵力に結合する力を加える + force += sepSteer * _SeparateWeight; // 操舵力に分離する力を加える + + _BoidForceBufferWrite[P_ID] = force; // 書き込み +} + +// 速度, 位置計算用カーネル関数 +[numthreads(SIMULATION_BLOCK_SIZE, 1, 1)] +void IntegrateCS +( + uint3 DTid : SV_DispatchThreadID // スレッド全体で固有のID +) +{ + const unsigned int P_ID = DTid.x; // インデックスを取得 + + BoidData b = _BoidDataBufferWrite[P_ID]; // 現在のBoidデータを読み込む + float3 force = _BoidForceBufferRead[P_ID]; // 操舵力を読み込む + + // 壁に近づいたら反発する力を与える + force += avoidWall(b.position) * _AvoidWallWeight; + + b.velocity += force * _DeltaTime; // 操舵力を速度に適用 + b.velocity = limit(b.velocity, _MaxSpeed); // 速度を制限 + b.position += b.velocity * _DeltaTime; // 位置を更新 + + _BoidDataBufferWrite[P_ID] = b; // 計算結果を書き込む +} \ No newline at end of file diff --git a/Assets/BoidsSimulationOnGPU/ComputeShaders/Boids.compute.meta b/Assets/BoidsSimulationOnGPU/ComputeShaders/Boids.compute.meta new file mode 100644 index 0000000..2f29996 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/ComputeShaders/Boids.compute.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 47567044d261e474db26e25410628c0a +timeCreated: 1505731768 +licenseType: Pro +ComputeShaderImporter: + currentAPIMask: 4 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/Materials.meta b/Assets/BoidsSimulationOnGPU/Materials.meta new file mode 100644 index 0000000..8a15fbf --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Materials.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f5ff61eb07d00644fae8d25fb3168c98 +folderAsset: yes +timeCreated: 1505731715 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/Materials/BoidsRender.mat b/Assets/BoidsSimulationOnGPU/Materials/BoidsRender.mat new file mode 100644 index 0000000..d27be51 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Materials/BoidsRender.mat @@ -0,0 +1,76 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!21 &2100000 +Material: + serializedVersion: 6 + m_ObjectHideFlags: 0 + m_PrefabParentObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_Name: BoidsRender + m_Shader: {fileID: 4800000, guid: f4853a7a0065e734dacad53805b3b7e3, type: 3} + m_ShaderKeywords: + m_LightmapFlags: 4 + m_EnableInstancingVariants: 1 + 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 + - _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} diff --git a/Assets/BoidsSimulationOnGPU/Materials/BoidsRender.mat.meta b/Assets/BoidsSimulationOnGPU/Materials/BoidsRender.mat.meta new file mode 100644 index 0000000..90e8263 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Materials/BoidsRender.mat.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 91dbb6b6149df404a986444779bcb3a3 +timeCreated: 1505737684 +licenseType: Pro +NativeFormatImporter: + mainObjectFileID: 2100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/Scripts.meta b/Assets/BoidsSimulationOnGPU/Scripts.meta new file mode 100644 index 0000000..b517641 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Scripts.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: d357b58f29a0c2c4cbec99353e5dcdd1 +folderAsset: yes +timeCreated: 1505730621 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/Scripts/BoidsRender.cs b/Assets/BoidsSimulationOnGPU/Scripts/BoidsRender.cs new file mode 100644 index 0000000..e9c7966 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Scripts/BoidsRender.cs @@ -0,0 +1,99 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +namespace BoidsSimulationOnGPU +{ + // 同GameObjectに、GPUBoidsコンポーネントがアタッチされていること保証 + [RequireComponent(typeof(GPUBoids))] + public class BoidsRender : MonoBehaviour + { + #region Paremeters + // 描画するBoidsオブジェクトのスケール + public Vector3 ObjectScale = new Vector3(0.1f, 0.2f, 0.5f); + #endregion + + #region Script References + // GPUBoidsスクリプトの参照 + public GPUBoids GPUBoidsScript; + #endregion + + #region Built-in Resources + // 描画するメッシュの参照 + public Mesh InstanceMesh; + // 描画のためのマテリアルの参照 + public Material InstanceRenderMaterial; + #endregion + + #region Private Variables + // GPUインスタンシングのための引数(ComputeBufferへの転送用) + // インスタンスあたりのインデックス数, インスタンス数, + // 開始インデックス位置, ベース頂点位置, インスタンスの開始位置 + uint[] args = new uint[5] { 0, 0, 0, 0, 0 }; + // GPUインスタンシングのための引数バッファ + ComputeBuffer argsBuffer; + #endregion + + #region MonoBehaviour Functions + void Start() + { + // 引数バッファを初期化 + argsBuffer = new ComputeBuffer(1, args.Length * sizeof(uint), + ComputeBufferType.IndirectArguments); + } + + void Update() + { + // メッシュをインスタンシング + RenderInstancedMesh(); + } + + void OnDisable() + { + // 引数バッファを解放 + if (argsBuffer != null) + argsBuffer.Release(); + argsBuffer = null; + } + #endregion + + #region Private Functions + void RenderInstancedMesh() + { + // 描画用マテリアルがNull, または, GPUBoidsスクリプトがNull, + // またはGPUインスタンシングがサポートされていなければ, 処理をしない + if (InstanceRenderMaterial == null || GPUBoidsScript == null || + !SystemInfo.supportsInstancing) + return; + + // 指定したメッシュのインデックス数を取得 + uint numIndices = (InstanceMesh != null) ? + (uint)InstanceMesh.GetIndexCount(0) : 0; + args[0] = numIndices; // メッシュのインデックス数をセット + args[1] = (uint)GPUBoidsScript.GetMaxObjectNum(); // インスタンス数をセット + argsBuffer.SetData(args); // バッファにセット + + // Boidデータを格納したバッファをマテリアルにセット + InstanceRenderMaterial.SetBuffer("_BoidDataBuffer", + GPUBoidsScript.GetBoidDataBuffer()); + // Boidオブジェクトスケールをセット + InstanceRenderMaterial.SetVector("_ObjectScale", ObjectScale); + // 境界領域を定義 + var bounds = new Bounds + ( + GPUBoidsScript.GetSimulationAreaCenter(), // 中心 + GPUBoidsScript.GetSimulationAreaSize() // サイズ + ); + // メッシュをGPUインスタンシングして描画 + Graphics.DrawMeshInstancedIndirect + ( + InstanceMesh, // インスタンシングするメッシュ + 0, // submeshのインデックス + InstanceRenderMaterial, // 描画を行うマテリアル + bounds, // 境界領域 + argsBuffer // GPUインスタンシングのための引数のバッファ + ); + } + #endregion + } +} \ No newline at end of file diff --git a/Assets/BoidsSimulationOnGPU/Scripts/BoidsRender.cs.meta b/Assets/BoidsSimulationOnGPU/Scripts/BoidsRender.cs.meta new file mode 100644 index 0000000..7b92eb6 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Scripts/BoidsRender.cs.meta @@ -0,0 +1,16 @@ +fileFormatVersion: 2 +guid: c1088025d887acd4189b6dc124e0ebc1 +timeCreated: 1507467374 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - GPUBoidsScript: {instanceID: 0} + - InstanceMesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} + - InstanceRenderMaterial: {fileID: 2100000, guid: 91dbb6b6149df404a986444779bcb3a3, + type: 2} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/Scripts/GPUBoids.cs b/Assets/BoidsSimulationOnGPU/Scripts/GPUBoids.cs new file mode 100644 index 0000000..7d46e96 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Scripts/GPUBoids.cs @@ -0,0 +1,195 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace BoidsSimulationOnGPU +{ + public class GPUBoids : MonoBehaviour + { + // Boidデータの構造体 + [System.Serializable] + struct BoidData + { + public Vector3 Velocity; // 速度 + public Vector3 Position; // 位置 + } + // スレッドグループのスレッドのサイズ + const int SIMULATION_BLOCK_SIZE = 256; + + #region Boids Parameters + // 最大オブジェクト数 + [Range(256, 32768)] + public int MaxObjectNum = 16384; + + // 結合を適用する他の個体との半径 + public float CohesionNeighborhoodRadius = 2.0f; + // 整列を適用する他の個体との半径 + public float AlignmentNeighborhoodRadius = 2.0f; + // 分離を適用する他の個体との半径 + public float SeparateNeighborhoodRadius = 1.0f; + + // 速度の最大値 + public float MaxSpeed = 5.0f; + // 操舵力の最大値 + public float MaxSteerForce = 0.5f; + + // 結合する力の重み + public float CohesionWeight = 1.0f; + // 整列する力の重み + public float AlignmentWeight = 1.0f; + // 分離する力の重み + public float SeparateWeight = 3.0f; + + // 壁を避ける力の重み + public float AvoidWallWeight = 10.0f; + + // 壁の中心座標 + public Vector3 WallCenter = Vector3.zero; + // 壁のサイズ + public Vector3 WallSize = new Vector3(32.0f, 32.0f, 32.0f); + #endregion + + #region Built-in Resources + // Boidsシミュレーションを行うComputeShaderの参照 + public ComputeShader BoidsCS; + #endregion + + #region Private Resources + // Boidの操舵力(Force)を格納したバッファ + ComputeBuffer _boidForceBuffer; + // Boidの基本データ(速度, 位置, Transformなど)を格納したバッファ + ComputeBuffer _boidDataBuffer; + #endregion + + #region Accessors + // Boidの基本データを格納したバッファを取得 + public ComputeBuffer GetBoidDataBuffer() + { + return this._boidDataBuffer != null ? this._boidDataBuffer : null; + } + + // オブジェクト数を取得 + public int GetMaxObjectNum() + { + return this.MaxObjectNum; + } + + // シミュレーション領域の中心座標を返す + public Vector3 GetSimulationAreaCenter() + { + return this.WallCenter; + } + + // シミュレーション領域のボックスのサイズを返す + public Vector3 GetSimulationAreaSize() + { + return this.WallSize; + } + #endregion + + #region MonoBehaviour Functions + void Start() + { + // バッファを初期化 + InitBuffer(); + } + + void Update() + { + // シミュレーション + Simulation(); + } + + void OnDestroy() + { + // バッファを破棄 + ReleaseBuffer(); + } + + void OnDrawGizmos() + { + // デバッグとしてシミュレーション領域をワイヤーフレームで描画 + Gizmos.color = Color.cyan; + Gizmos.DrawWireCube(WallCenter, WallSize); + } + #endregion + + #region Private Functions + // バッファを初期化 + void InitBuffer() + { + // バッファを初期化 + _boidDataBuffer = new ComputeBuffer(MaxObjectNum, + Marshal.SizeOf(typeof(BoidData))); + _boidForceBuffer = new ComputeBuffer(MaxObjectNum, + Marshal.SizeOf(typeof(Vector3))); + + // Boidデータ, Forceバッファを初期化 + var forceArr = new Vector3[MaxObjectNum]; + var boidDataArr = new BoidData[MaxObjectNum]; + for (var i = 0; i < MaxObjectNum; i++) + { + forceArr[i] = Vector3.zero; + boidDataArr[i].Position = Random.insideUnitSphere * 1.0f; + boidDataArr[i].Velocity = Random.insideUnitSphere * 0.1f; + } + _boidForceBuffer.SetData(forceArr); + _boidDataBuffer.SetData(boidDataArr); + forceArr = null; + boidDataArr = null; + } + + // シミュレーション + void Simulation() + { + ComputeShader cs = BoidsCS; + int id = -1; + + // スレッドグループの数を求める + int threadGroupSize = Mathf.CeilToInt(MaxObjectNum / SIMULATION_BLOCK_SIZE); + + // 操舵力を計算 + id = cs.FindKernel("ForceCS"); // カーネルIDを取得 + cs.SetInt("_MaxBoidObjectNum", MaxObjectNum); + cs.SetFloat("_CohesionNeighborhoodRadius", CohesionNeighborhoodRadius); + cs.SetFloat("_AlignmentNeighborhoodRadius", AlignmentNeighborhoodRadius); + cs.SetFloat("_SeparateNeighborhoodRadius", SeparateNeighborhoodRadius); + cs.SetFloat("_MaxSpeed", MaxSpeed); + cs.SetFloat("_MaxSteerForce", MaxSteerForce); + cs.SetFloat("_SeparateWeight", SeparateWeight); + cs.SetFloat("_CohesionWeight", CohesionWeight); + cs.SetFloat("_AlignmentWeight", AlignmentWeight); + cs.SetVector("_WallCenter", WallCenter); + cs.SetVector("_WallSize", WallSize); + cs.SetFloat("_AvoidWallWeight", AvoidWallWeight); + cs.SetBuffer(id, "_BoidDataBufferRead", _boidDataBuffer); + cs.SetBuffer(id, "_BoidForceBufferWrite", _boidForceBuffer); + cs.Dispatch(id, threadGroupSize, 1, 1); // ComputeShaderを実行 + + // 操舵力から、速度と位置を計算 + id = cs.FindKernel("IntegrateCS"); // カーネルIDを取得 + cs.SetFloat("_DeltaTime", Time.deltaTime); + cs.SetBuffer(id, "_BoidForceBufferRead", _boidForceBuffer); + cs.SetBuffer(id, "_BoidDataBufferWrite", _boidDataBuffer); + cs.Dispatch(id, threadGroupSize, 1, 1); // ComputeShaderを実行 + } + + // バッファを解放 + void ReleaseBuffer() + { + if (_boidDataBuffer != null) + { + _boidDataBuffer.Release(); + _boidDataBuffer = null; + } + + if (_boidForceBuffer != null) + { + _boidForceBuffer.Release(); + _boidForceBuffer = null; + } + } + #endregion + } // class +} // namespace \ No newline at end of file diff --git a/Assets/BoidsSimulationOnGPU/Scripts/GPUBoids.cs.meta b/Assets/BoidsSimulationOnGPU/Scripts/GPUBoids.cs.meta new file mode 100644 index 0000000..faae5bb --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Scripts/GPUBoids.cs.meta @@ -0,0 +1,13 @@ +fileFormatVersion: 2 +guid: 4be9a8d5d645e4545886be6914d2e5e9 +timeCreated: 1507467386 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: + - BoidsCS: {fileID: 7200000, guid: 47567044d261e474db26e25410628c0a, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/Shaders.meta b/Assets/BoidsSimulationOnGPU/Shaders.meta new file mode 100644 index 0000000..8c3c8ba --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Shaders.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 3cf58ec6d88ff7d47aa5d3cb91553ab7 +folderAsset: yes +timeCreated: 1505730621 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/BoidsSimulationOnGPU/Shaders/BoidsRender.shader b/Assets/BoidsSimulationOnGPU/Shaders/BoidsRender.shader new file mode 100644 index 0000000..10a4052 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Shaders/BoidsRender.shader @@ -0,0 +1,109 @@ +Shader "Hidden/BoidsSimulationOnGPU/BoidsRender" +{ + Properties + { + _Color ("Color", Color) = (1,1,1,1) + _MainTex ("Albedo (RGB)", 2D) = "white" {} + _Glossiness ("Smoothness", Range(0,1)) = 0.5 + _Metallic ("Metallic", Range(0,1)) = 0.0 + } + SubShader + { + Tags { "RenderType"="Opaque" } + LOD 200 + + CGPROGRAM + #pragma surface surf Standard vertex:vert addshadow + #pragma instancing_options procedural:setup + + struct Input + { + float2 uv_MainTex; + }; + // Boidの構造体 + struct BoidData + { + float3 velocity; // 速度 + float3 position; // 位置 + }; + + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED + // Boidデータの構造体バッファ + StructuredBuffer _BoidDataBuffer; + #endif + + sampler2D _MainTex; // テクスチャ + + half _Glossiness; // 光沢 + half _Metallic; // 金属特性 + fixed4 _Color; // カラー + + float3 _ObjectScale; // Boidオブジェクトのスケール + + // オイラー角(ラジアン)を回転行列に変換 + float4x4 eulerAnglesToRotationMatrix(float3 angles) + { + float ch = cos(angles.y); float sh = sin(angles.y); // heading + float ca = cos(angles.z); float sa = sin(angles.z); // attitude + float cb = cos(angles.x); float sb = sin(angles.x); // bank + + // Ry-Rx-Rz (Yaw Pitch Roll) + return float4x4( + ch * ca + sh * sb * sa, -ch * sa + sh * sb * ca, sh * cb, 0, + cb * sa, cb * ca, -sb, 0, + -sh * ca + ch * sb * sa, sh * sa + ch * sb * ca, ch * cb, 0, + 0, 0, 0, 1 + ); + } + + // 頂点シェーダ + void vert(inout appdata_full v) + { + #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED + + // インスタンスIDからBoidのデータを取得 + BoidData boidData = _BoidDataBuffer[unity_InstanceID]; + + float3 pos = boidData.position.xyz; // Boidの位置を取得 + float3 scl = _ObjectScale; // Boidのスケールを取得 + + // オブジェクト座標からワールド座標に変換する行列を定義 + float4x4 object2world = (float4x4)0; + // スケール値を代入 + object2world._11_22_33_44 = float4(scl.xyz, 1.0); + // 速度からY軸についての回転を算出 + float rotY = + atan2(-boidData.velocity.z, boidData.velocity.x) + UNITY_PI * 0.5; + // 速度からX軸についての回転を算出 + float rotX = + -asin(boidData.velocity.y / (length(boidData.velocity.xyz) + 1e-8)); + // オイラー角(ラジアン)から回転行列を求める + float4x4 rotMatrix = eulerAnglesToRotationMatrix(float3(rotX, rotY, 0)); + // 行列に回転を適用 + object2world = mul(rotMatrix, object2world); + // 行列に位置(平行移動)を適用 + object2world._14_24_34 += pos.xyz; + + // 頂点を座標変換 + v.vertex = mul(object2world, v.vertex); + // 法線を座標変換 + v.normal = normalize(mul(object2world, v.normal)); + #endif + } + + void setup() + { + } + + // サーフェスシェーダ + void surf (Input IN, inout SurfaceOutputStandard o) + { + fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; + o.Albedo = c.rgb; + o.Metallic = _Metallic; + o.Smoothness = _Glossiness; + } + ENDCG + } + FallBack "Diffuse" +} \ No newline at end of file diff --git a/Assets/BoidsSimulationOnGPU/Shaders/BoidsRender.shader.meta b/Assets/BoidsSimulationOnGPU/Shaders/BoidsRender.shader.meta new file mode 100644 index 0000000..102c0d8 --- /dev/null +++ b/Assets/BoidsSimulationOnGPU/Shaders/BoidsRender.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: f4853a7a0065e734dacad53805b3b7e3 +timeCreated: 1505738193 +licenseType: Pro +ShaderImporter: + defaultTextures: [] + userData: + assetBundleName: + assetBundleVariant: From b3c9ca1150915747893aa58d92f94415cf3bc1c2 Mon Sep 17 00:00:00 2001 From: hiroakioishi Date: Tue, 10 Oct 2017 17:04:35 +0900 Subject: [PATCH 2/2] modified README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 30e2007..792b259 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,5 @@ UnityGraphicsProgramming - 雰囲気で始めるMarchingCubes入門 [@kaiware007](https://github.com/kaiware007) - https://github.com/IndieVisualLab/UnityGraphicsProgramming/tree/master/Assets/GPUMarchingCubes - SPH法による流体シミュレーション [@kodai100](https://github.com/kodai100) - https://github.com/IndieVisualLab/UnityGraphicsProgramming/tree/master/Assets/SPHFluid + +- 群のシミュレーションのGPU実装 [@hiroakioishi](https://github.com/hiroakioishi) - https://github.com/IndieVisualLab/UnityGraphicsProgramming/tree/master/Assets/BoidsSimulationOnGPU