<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Unity3D學(xué)習(xí)筆記6——GPU實(shí)例化(1)

      1. 概述

      在之前的文章中說(shuō)到,一種材質(zhì)對(duì)應(yīng)一次繪制調(diào)用的指令。即使是這種情況,兩個(gè)三維物體使用同一種材質(zhì),但它們使用的材質(zhì)參數(shù)不一樣,那么最終仍然會(huì)造成兩次繪制指令。原因在于,圖形工作都是一種狀態(tài)機(jī),狀態(tài)發(fā)生了變化,就必須進(jìn)行一次繪制調(diào)用指令。

      GPU實(shí)例化用于解決這樣的問(wèn)題:對(duì)于像草地、樹(shù)木這樣的物體,它們往往是數(shù)據(jù)量很大,但同時(shí)又只存在微小的差別如位置、姿態(tài)、顏色等。如果像常規(guī)物體那樣進(jìn)行渲染,所使用的繪制指令必然很多,資源占用必然很大。一個(gè)合理的策略就是,我們指定一個(gè)需要繪制物體對(duì)象,以及大量該對(duì)象不同的參數(shù),然后根據(jù)參數(shù)在一個(gè)繪制調(diào)用中繪制出來(lái)——這就是所謂的GPU實(shí)例化。

      2. 詳論

      首先,我們創(chuàng)建一個(gè)空的GameObject對(duì)象,并且掛接如下腳本:

      using UnityEngine;
      
      //實(shí)例化參數(shù)
      public struct InstanceParam
      {  
          public Color color;
          public Matrix4x4 instanceToObjectMatrix;        //實(shí)例化到物方矩陣
      }
      
      [ExecuteInEditMode]
      public class Note6Main : MonoBehaviour
      {
          public Mesh mesh;
          public Material material;
      
          int instanceCount = 200;
          Bounds instanceBounds;
      
          ComputeBuffer bufferWithArgs = null;
          ComputeBuffer instanceParamBufferData = null;
      
          // Start is called before the first frame update
          void Start()
          {
              instanceBounds = new Bounds(new Vector3(0, 0, 0), new Vector3(100, 100, 100));
      
              uint[] args = new uint[5] { 0, 0, 0, 0, 0 };
              bufferWithArgs = new ComputeBuffer(1, args.Length * sizeof(uint), ComputeBufferType.IndirectArguments);
              int subMeshIndex = 0;
              args[0] = mesh.GetIndexCount(subMeshIndex);
              args[1] = (uint)instanceCount;
              args[2] = mesh.GetIndexStart(subMeshIndex);
              args[3] = mesh.GetBaseVertex(subMeshIndex);
              bufferWithArgs.SetData(args);
              
              InstanceParam[] instanceParam = new InstanceParam[instanceCount];
      
              for (int i = 0; i < instanceCount; i++)
              {   
                  Vector3 position = Random.insideUnitSphere * 5;        
                  Quaternion q =  Quaternion.Euler(Random.Range(0.0f, 90.0f), Random.Range(0.0f, 90.0f), Random.Range(0.0f, 90.0f));
                  float s = Random.value;
                  Vector3 scale = new Vector3(s, s, s);
      
                  instanceParam[i].instanceToObjectMatrix = Matrix4x4.TRS(position, q, scale);
                  instanceParam[i].color = Random.ColorHSV();
              }
      
              int stride = System.Runtime.InteropServices.Marshal.SizeOf(typeof(InstanceParam));
              instanceParamBufferData = new ComputeBuffer(instanceCount, stride);
              instanceParamBufferData.SetData(instanceParam);
              material.SetBuffer("dataBuffer", instanceParamBufferData);
              material.SetMatrix("ObjectToWorld", Matrix4x4.identity);
          }
      
          // Update is called once per frame
          void Update()
          {        
              if(bufferWithArgs != null)
              {         
                  Graphics.DrawMeshInstancedIndirect(mesh, 0, material, instanceBounds, bufferWithArgs, 0);
              }        
          }
      
          private void OnDestroy()
          {
              if (bufferWithArgs != null)
              {
                  bufferWithArgs.Release();
              }
              
              if(instanceParamBufferData != null)
              {
                  instanceParamBufferData.Release();
              }        
          }
      }
      

      這個(gè)腳本的意思是,設(shè)置一個(gè)網(wǎng)格和一個(gè)材質(zhì),通過(guò)隨機(jī)獲取的實(shí)例化參數(shù),渲染這個(gè)網(wǎng)格的多個(gè)實(shí)例:
      imglink1

      GPU實(shí)例化的關(guān)鍵接口是Graphics.DrawMeshInstancedIndirect()。Graphics對(duì)象的一系列接口是Unity的底層API,它是需要每一幀調(diào)用的。Graphics.DrawMeshInstanced()也可以實(shí)例繪制,但是最多只能繪制1023個(gè)實(shí)例。所以還是Graphics.DrawMeshInstancedIndirect()比較好。

      實(shí)例化參數(shù)InstanceParam和GPU緩沖區(qū)參數(shù)bufferWithArgs都是存儲(chǔ)于一個(gè)ComputeBuffer對(duì)象中。ComputeBuffe定義了一個(gè)GPU數(shù)據(jù)緩沖區(qū)對(duì)象,能夠映射到Unity Shader中的 StructuredBuffer中。實(shí)例化參數(shù)InstanceParam存儲(chǔ)了每個(gè)實(shí)例化對(duì)象的位置,姿態(tài)、縮放以及顏色信息,通過(guò)Material.SetBuffer(),傳遞到著色器中:

      Shader "Custom/SimpleInstanceShader"
      {
          Properties
          {        
          }
          SubShader
          {
      		Tags{"Queue" = "Geometry"}
      
      		Pass
      		{	
      			CGPROGRAM
      			#include "UnityCG.cginc" 
      			#pragma vertex vert	
      			#pragma fragment frag
      			#pragma target 4.5
      
      			sampler2D _MainTex;
      			
      			float4x4 ObjectToWorld;
      	
      			struct InstanceParam
      			{			
      				float4 color;
      				float4x4 instanceToObjectMatrix;
      			};
      	
      		#if SHADER_TARGET >= 45			
      			StructuredBuffer<InstanceParam> dataBuffer;
      		#endif
      		
      			//頂點(diǎn)著色器輸入
      			struct a2v
      			{
      				float4  position : POSITION;
      				float3  normal: NORMAL;
      				float2  texcoord : TEXCOORD0;	
       			};
      
      			//頂點(diǎn)著色器輸出
      			struct v2f
      			{
      				float4 position: SV_POSITION;
      				float2 texcoord: TEXCOORD0;
      				float4 color: COLOR;
      			};
      
      			v2f vert(a2v v, uint instanceID : SV_InstanceID)
      			{
      			#if SHADER_TARGET >= 45
      				float4x4 instanceToObjectMatrix = dataBuffer[instanceID].instanceToObjectMatrix;
      				float4 color = dataBuffer[instanceID].color;
      			#else
      				float4x4 instanceToObjectMatrix = float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
      				float4 color = float4(1.0f, 1.0f, 1.0f, 1.0f);
      			#endif
      
      				float4 localPosition = mul(instanceToObjectMatrix, v.position);
      				//float4 localPosition = v.position;
      				float4 worldPosition = mul(ObjectToWorld, localPosition);						
      
      				v2f o;
      				//o.position = UnityObjectToClipPos(v.position);
      				o.position = mul(UNITY_MATRIX_VP, worldPosition);		
      				o.texcoord = v.texcoord;
      				o.color = color;
      
      				return o;
      			}
      
      			fixed4 frag(v2f i) : SV_Target 
      			{												
      				return i.color;					
      			}
      
                  ENDCG
              }
          }
      
      	Fallback "Diffuse"
      }
      

      這是一個(gè)改進(jìn)自《Unity3D學(xué)習(xí)筆記3——Unity Shader的初步使用》的簡(jiǎn)單實(shí)例化著色器。實(shí)例化繪制往往位置并不是固定的,這意味著Shader中獲取的模型矩陣UNITY_MATRIX_M一般是不正確的。因而實(shí)例化繪制的關(guān)鍵就在于對(duì)模型矩陣的重新計(jì)算,否則繪制的位置是不正確的。實(shí)例化的數(shù)據(jù)往往位置比較接近,所以可以先傳入一個(gè)基準(zhǔn)位置(矩陣ObjectToWorld),然后實(shí)例化數(shù)據(jù)就可以只傳入于這個(gè)位置的相對(duì)矩陣(instanceToObjectMatrix)。

      最終的運(yùn)行結(jié)果如下,繪制了大量不同位置、不同姿態(tài)、不同大小以及不同顏色的膠囊體,并且性能基本上不受影響。

      imglink2

      3. 參考

      1. 《Unity3D學(xué)習(xí)筆記3——Unity Shader的初步使用》
      2. Graphics.DrawMeshInstanced

      具體實(shí)現(xiàn)代碼

      posted @ 2022-07-06 13:00  charlee44  閱讀(1814)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 国产免费AV片在线看| 口爆少妇在线视频免费观看| 中文字幕无码免费久久99| 性欧美VIDEOFREE高清大喷水| 越南毛茸茸的少妇| 青草青草久热精品视频在线播放 | 綦江县| 亚洲无人区码一二三区别| 伊川县| 高清有码国产一区二区| 亚洲精品日韩在线观看| 美女内射无套日韩免费播放| 国产精品麻豆欧美日韩ww| 性色在线视频精品| 色成人精品免费视频| 男女猛烈激情xx00免费视频| 又湿又紧又大又爽A视频男| 日韩在线视频网| 黄色段片一区二区三区| 呦系列视频一区二区三区| 天堂网在线.www天堂在线资源| 青青青久热国产精品视频| 国产成人精品视频不卡| 国产一区二区四区不卡| 国产亚洲精品成人aa片新蒲金 | 国产中文成人精品久久久| 国产三级精品福利久久| 亚洲国产精品久久久久秋霞| 欧美日韩在线第一页免费观看| 内射视频福利在线观看| 67194熟妇在线观看线路| 亚洲中文字幕有综合久久| 无线日本视频精品| 你懂的亚洲一区二区三区| 免费现黄频在线观看国产| 久久99国产精品尤物| 亚洲国产高清第一第二区| 国产午夜在线观看视频播放 | 亚洲AV毛片一区二区三区| 白嫩少妇无套内谢视频| 久久99精品久久久久麻豆|