现在的位置: 首页 > 综合 > 正文

AMD Leo Demo 背后的技术

2013年09月16日 ⁄ 综合 ⁄ 共 2913字 ⁄ 字号 评论关闭

前几天,想看看AMD以前的技术演示,看到了这个demo。可惜没有AMD的显卡,看不到的实际效果。网上资料找了半天没有找到,昨天刚刚在桌面上发现了一个ppt,Technology Behind AMD’s “Leo Demo”。去年在GDC上发布的ppt,关于leo Demo的光照。

Leo Demo没有选择延迟渲染,原因有三点,一是材质太复杂,二是灯光总类都,三是支持半透明。其中用到了light culling,思想是将世界坐标系内的灯光在屏幕坐标系内进行分割,分成一个个小的tile,每个tile存储自己的光照信息。其实和战地3里的方法差不多,只不过战地3用的是延迟渲染。

然后在渲染像素的时候找到对应的tile取里面的光照信息,完成光照计算,输出结果。其中很重要的一点事使用了UAV(unorder access view)来存储光照信息,没有这个功能是无法实现的。其实很简单,看看就可以了。

代码如下:

//	1. prepare
	float4 frustum[4];
	float minZ, maxZ;
	{
		ConstructFrustum( frustum );
		minZ = thread_REDUCE(MIN, depth );
		maxZ = thread_REDUCE(MAX, depth );
		ldsMinZ = SIMD_REDUCE(MIN, minZ );
		ldsMaxZ = SIMD_REDUCE(MAX, maxZ );
		minZ = ldsMinZ;
		maxZ = ldsMaxZ;
	}

_local u32 ldsNLights = 0;
	__local u32 ldsLightBuffer[MAX];

	//	2. overlap check, accumulate in LDS
	for(int i=threadIdx; i<nLights; i+=WG_SIZE)
	{
		Light light = fetchAndTransform( lightBuffer[ i ] );
		if( overlaps( light, frustum ) && overlaps ( light, minZ, maxZ ) )
		{
			AtomicAppend( ldsLightBuffer, i );
		}
	}

//	3. export to global
	__local u32 ldsOffset;
	if( threadIdx == 0 )
	{
		ldsOffset  = AtomAdd( ldsNLights );
		globalLightStart[tileIdx] = ldsOffset;
		globalLightEnd[tileIdx] = ldsOffset + ldsNLights;
	}

	for(int i=threadIdx; i< ldsNLights; i+=WG_SIZE)
	{
		int dstIdx = ldsOffset + i;
		globalLightIndexBuffer[dstIdx] = ldsLightBuffer[i];
	}
// BaseLighting.inc     // THIS INC FILE IS ALL THE COMMON LIGHTING CODE

StructuredBuffer<float4>  LightParams          : register(u0);
StructuredBuffer<uint>    LowerBoundLights  : register(u1);
StructuredBuffer<uint>    UpperBoundLights  : register(u2);
StructuredBuffer<int2>    LightIndexBuffer     : register(u3);

uint GetTileIndex(float2 screenPos)
{
   float tileRes  = (float)m_tileRes;
   uint numCellsX = (m_width + m_tileRes - 1)/m_tileRes;
   uint tileIdx   = floor(screenPos.x/tileRes)+floor(screenPos.y/tileRes)*numCellsX;

   return tileIdx;
}

StartHLSL BaseLightLoopBegin	// THIS IS A MACRO, INCLUDED IN MATERIAL SHADERS

 uint tileIdx    = GetTileIndex( pixelScreenPos );
 uint startIdx  = LowerBoundLights[tileIdx]; 
 uint endIdx   = UppweBoundLights[tileIdx];

 [loop]
 for ( uint lightListIdx = startIdx; lightListIdx < endIdx; lightListIdx++ )
 {
	int lightIdx = LightIndexBuffer[lightListIdx];
	
	// Set common light parameters
	float ndotl = max(0, dot(normal, lightVec));
		
	float3 directLight   = 0;
	float3 indirectLight = 0;
    if( lightIdx >= numDirectLightsThisFrame )    {
       CalculateIndirectLight(lightIdx , indirectLight);
    }    else      {
        if( IsConeLight( lightIdx ) )        {        	//    <<==  Can add more light types here
            CalculateDirectSpotlight(lightIdx , directLight);
        }     else     {
         CalculateDirectSpherelight(lightIdx , directLight);
     }
 }	

 float3 incomingLight = (directLight + indirectLight)*ndotl;
 float shadowTerm = CalcShadow();

EndHLSL

StartHLSL BaseLightLoopEnd   
      }
EndHLSL

#include "BaseLighting.inc"

float4 PS ( PSInput i ) : SV_TARGET	
{
     float3 totalDiffuse = 0;
     float3 totalSpec    = GetEnvLighting();;

$include BaseLightLoopBegin

// unique material code goes here!! Light accumulation on the pixel for a given light
// we have total incoming light and direct/indirect light components as well as material params and shadow term
// use these building blocks to integrate lighting terms 

        totalDiffuse += GetDiffuse(incomingLight);
        totalSpec    += CalcPhong(incomingLight);

$include  BaseLightLoopEnd

   float3 finalColor = totalDiffuse + totalSpec;
   return float4( finalColor, 1 );
}

抱歉!评论已关闭.