浏览代码

Refactored LowEndMobile pipeline to have constant nomeclature across all modules. Organized project strucuture for clearer reference.

/vr_sandbox
Felipe Lira 8 年前
当前提交
870e00ba
共有 39 个文件被更改,包括 1765 次插入17 次删除
  1. 27
      Assets/LowEndMobilePipeline/Editor/LowendMobilePipelineMaterialEditor.cs
  2. 4
      Assets/LowEndMobilePipeline/TestScenes/Materials/LDRenderPipeMaterials/MobileColors.mat
  3. 8
      Assets/LowEndMobilePipeline/LowEndMobilePipeline.shader
  4. 26
      Assets/LowEndMobilePipeline/Editor/LegacyMobileToLowendMobileUpgrader.cs
  5. 113
      Assets/LowEndMobilePipeline/Editor/LowendPipelineAssetInspector.cs
  6. 22
      Assets/LowEndMobilePipeline/Editor/StandardToLowEndMaterialUpgrader.cs
  7. 381
      Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs
  8. 25
      Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset
  9. 9
      Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset.meta
  10. 145
      Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs
  11. 12
      Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs.meta
  12. 9
      Assets/LowEndMobilePipeline/TestScenes.meta
  13. 1001
      Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.unity
  14. 0
      /Assets/LowEndMobilePipeline.meta
  15. 0
      /Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs.meta
  16. 0
      /Assets/LowEndMobilePipeline/TestScenes/Materials.meta
  17. 0
      /Assets/LowEndMobilePipeline/TestScenes/Textures.meta
  18. 0
      /Assets/LowEndMobilePipeline/TestScenes/Textures
  19. 0
      /Assets/LowEndMobilePipeline/Editor.meta
  20. 0
      /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage
  21. 0
      /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.meta
  22. 0
      /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.unity.meta
  23. 0
      /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage.meta
  24. 0
      /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage.unity
  25. 0
      /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage.unity.meta
  26. 0
      /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene
  27. 0
      /Assets/LowEndMobilePipeline/Editor/StandardToLowEndMaterialUpgrader.cs.meta
  28. 0
      /Assets/LowEndMobilePipeline/Editor/LegacyMobileToLowendMobileUpgrader.cs.meta
  29. 0
      /Assets/LowEndMobilePipeline/Editor/LowendMobilePipelineMaterialEditor.cs.meta
  30. 0
      /Assets/LowEndMobilePipeline/Editor/LowendPipelineAssetInspector.cs.meta
  31. 0
      /Assets/LowEndMobilePipeline/Editor/LowendMobilePipelineMaterialEditor.cs
  32. 0
      /Assets/LowEndMobilePipeline/TestScenes/Materials
  33. 0
      /Assets/LowEndMobilePipeline/LowEndMobilePipeline.shader.meta
  34. 0
      /Assets/LowEndMobilePipeline/LowEndMobilePipeline.shader

27
Assets/LowEndMobilePipeline/Editor/LowendMobilePipelineMaterialEditor.cs


using UnityEditor;
using UnityEngine;
// TODO: Implement AssignNewShaderToMaterial to handle cases from update to different mobile shaders having different props
public class LDRenderPipelineMaterialEditor : MaterialEditor
public class LowendMobilePipelineMaterialEditor : MaterialEditor
{
private MaterialProperty blendMode = null;
private MaterialProperty albedoMap = null;

new GUIContent("Base (RGB)", "Base Color (RGB)")
};
public static GUIContent albedoAlphaLabel = new GUIContent("Base (RGB) Alpha (A)", "Base Color (RGB) and Transparency (A)");
public static GUIContent albedoAlphaLabel = new GUIContent("Base (RGB) Alpha (A)",
"Base Color (RGB) and Transparency (A)");
public static GUIContent[] specularGlossMapLabels =
{

public static GUIContent normalMapText = new GUIContent("Normal Map", "Normal Map");
public static GUIContent alphaCutoutWarning = new GUIContent("This material has alpha cutout enabled. Alpha cutout has severe performance impact on mobile!");
public static GUIContent alphaCutoutWarning =
new GUIContent(
"This material has alpha cutout enabled. Alpha cutout has severe performance impact on mobile!");
public static GUIStyle warningStyle = new GUIStyle();
public static readonly string[] blendNames = Enum.GetNames(typeof(BlendMode));
public static readonly string[] specSourceNames = Enum.GetNames(typeof(SpecularSource));

blendMode = GetMaterialProperty(mats, "_Mode");
albedoMap = GetMaterialProperty(mats, "_MainTex");
albedoColor = GetMaterialProperty(mats, "_Color");
alphaCutoff = GetMaterialProperty(mats, "_Cutoff");
specularSource = GetMaterialProperty(mats, "_SpecSource");
glossinessSourceProp = GetMaterialProperty(mats, "_GlossinessSource");

EditorGUILayout.Space();
EditorGUILayout.Space();
if ((BlendMode) blendMode.floatValue == BlendMode.Cutout)
if ((BlendMode)blendMode.floatValue == BlendMode.Cutout)
{
Styles.warningStyle.normal.textColor = Color.yellow;
EditorGUILayout.LabelField(Styles.alphaCutoutWarning, Styles.warningStyle);

if (mode == BlendMode.Opaque)
{
int glossSource = (int) glossinessSourceProp.floatValue;
int glossSource = (int)glossinessSourceProp.floatValue;
TexturePropertySingleLine(Styles.albedoGlosinessLabels[glossSource], albedoMap, albedoColor);
TextureScaleOffsetProperty(albedoMap);
}

SpecularSource specSource = (SpecularSource)specularSource.floatValue;
if (specSource != SpecularSource.NoSpecular)
{
int glossinessSource = (int) glossinessSourceProp.floatValue;
int glossinessSource = (int)glossinessSourceProp.floatValue;
glossinessSource = EditorGUILayout.Popup(Styles.glossinessSourceLable, glossinessSource, Styles.glossinessSourceNames);
glossinessSource = EditorGUILayout.Popup(Styles.glossinessSourceLable, glossinessSource,
Styles.glossinessSourceNames);
if (EditorGUI.EndChangeCheck())
glossinessSourceProp.floatValue = (float)glossinessSource;
}

private void UpdateMaterialSpecularSource(Material material)
{
SpecularSource specSource = (SpecularSource) specularSource.floatValue;
SpecularSource specSource = (SpecularSource)specularSource.floatValue;
if (specSource == SpecularSource.NoSpecular)
{
SetKeyword(material, "_SHARED_SPECULAR_DIFFUSE", false);

SetKeyword(material, "_SPECULAR_COLOR", true);
}
GlossinessSource glossSource = (GlossinessSource) glossinessSourceProp.floatValue;
GlossinessSource glossSource = (GlossinessSource)glossinessSourceProp.floatValue;
if (glossSource == GlossinessSource.AlphaFromBaseTextureAndColor)
SetKeyword(material, "_GLOSSINESS_FROM_BASE_ALPHA", true);
else

4
Assets/LowEndMobilePipeline/TestScenes/Materials/LDRenderPipeMaterials/MobileColors.mat


m_PrefabInternal: {fileID: 0}
m_Name: MobileColors
m_Shader: {fileID: 4800000, guid: 8d2bb70cbf9db8d4da26e15b26e74248, type: 3}
m_ShaderKeywords: _EMISSION _GLOSSINESS_FROM_BASE_ALPHA _NORMALMAP _SHARED_SPECULAR_DIFFUSE
m_ShaderKeywords: _EMISSION _GLOSSINESS_FROM_BASE_ALPHA _NORMALMAP _SPECULAR_COLOR
m_LightmapFlags: 1
m_EnableInstancingVariants: 0
m_CustomRenderQueue: -1

- _OcclusionStrength: 1
- _Parallax: 0.02
- _SmoothnessTextureChannel: 0
- _SpecSource: 1
- _SpecSource: 0
- _SpecularHighlights: 1
- _SpecularStrength: 200
- _SrcBlend: 1

8
Assets/LowEndMobilePipeline/LowEndMobilePipeline.shader


// Shader targeted for LowEnd mobile devices. Single Pass Forward Rendering. Shader Model 2
Shader "LDRenderPipeline/Specular"
Shader "LowEndMobilePipeline/Specular"
{
// Keep properties of StandardSpecular shader for upgrade reasons.
Properties

SubShader
{
Tags { "RenderType" = "Opaque" "PerformanceChecks" = "False" "RenderPipeline" = "LDRenderPipeline" }
Tags { "RenderType" = "Opaque" "RenderPipeline" = "LowEndMobilePipeline" }
Tags { "LightMode" = "LDForwardLight" }
Tags { "LightMode" = "LowEndMobileForward" }
// Use same blending / depth states as Standard shader
Blend[_SrcBlend][_DstBlend]

}
}
Fallback "Standard (Specular setup)"
CustomEditor "LDRenderPipelineMaterialEditor"
CustomEditor "LowendMobilePipelineMaterialEditor"
}

26
Assets/LowEndMobilePipeline/Editor/LegacyMobileToLowendMobileUpgrader.cs


using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Experimental.Rendering;
public class LegacyMobileToLowendMobileUpgrader : MaterialUpgrader
{
[MenuItem("LowEndMobilePipeline/Material Upgraders/Upgrade Legacy Mobile Materials to LowEndMobile")]
public static void UpgradeMaterialsToLD()
{
List<MaterialUpgrader> materialUpgraders = new List<MaterialUpgrader>();
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Diffuse"));
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Bumped Specular"));
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Bumped Specular(1 Directional Light)"));
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Bumped Diffuse"));
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/Unlit (Supports Lightmap)"));
materialUpgraders.Add(new LegacyMobileToLowendMobileUpgrader("Mobile/VertexLit"));
MaterialUpgrader.UpgradeProjectFolder(materialUpgraders, "Upgrade to LD Materials");
}
LegacyMobileToLowendMobileUpgrader(string oldShaderName)
{
RenameShader(oldShaderName, "LowEndMobilePipeline/Specular");
RenameFloat("_Shininess", "_Glossiness");
}
}

113
Assets/LowEndMobilePipeline/Editor/LowendPipelineAssetInspector.cs


using UnityEditor;
namespace UnityEngine.Experimental.Rendering.LowendMobile
{
[CustomEditor(typeof(LowEndMobilePipelineAsset))]
public class LowendPipelineAssetInspector : Editor
{
internal class Styles
{
public static GUIContent renderingLabel = new GUIContent("Rendering");
public static GUIContent shadowLabel = new GUIContent("Shadows");
public static GUIContent maxPixelLights = new GUIContent("Max per-pixel lights supported",
"Amount of dynamic lights processed in fragment shader. More than 1 per-pixel light is not recommended.");
public static GUIContent enableVertexLightLabel = new GUIContent("Enable Vertex Light",
"Enable up to 4 per-vertex dynamic lights.");
public static GUIContent enableLightmap = new GUIContent("Enable Lightmap",
"Only non-directional lightmaps are supported");
public static GUIContent enableAmbientProbe = new GUIContent("Enable Ambient Probe",
"Uses light probes as ambient light source for non-lightmapped objects.");
public static GUIContent shadowType = new GUIContent("Shadow Type",
"Single directional shadow supported. SOFT_SHADOWS applies shadow filtering.");
public static GUIContent shadowNearPlaneOffset = new GUIContent("Shadow Near Plane Offset",
"Offset shadow near plane to account for large triangles being distorted by pancaking");
public static GUIContent shadowDistante = new GUIContent("Shadow Distance", "Max shadow drawing distance");
public static GUIContent shadowBias = new GUIContent("Shadow Bias");
public static GUIContent shadowAtlasResolution = new GUIContent("Shadow Map Resolution",
"Resolution of shadow map texture. If cascades are enabled all cascades will be packed into this texture resolution.");
public static GUIContent shadowCascades = new GUIContent("Shadow Cascades",
"Number of cascades for directional shadows");
public static GUIContent shadowCascadeSplit = new GUIContent("Shadow Cascade Split",
"Percentages to split shadow volume");
}
private SerializedProperty m_MaxPixelLights;
private SerializedProperty m_SupportsVertexLightProp;
private SerializedProperty m_EnableLightmapsProp;
private SerializedProperty m_EnableAmbientProbeProp;
private SerializedProperty m_ShadowTypeProp;
private SerializedProperty m_ShadowNearPlaneOffsetProp;
private SerializedProperty m_ShadowBiasProperty;
private SerializedProperty m_ShadowDistanceProp;
private SerializedProperty m_ShadowAtlasResolutionProp;
private SerializedProperty m_ShadowCascadesProp;
private SerializedProperty m_ShadowCascade2SplitProp;
private SerializedProperty m_ShadowCascade4SplitProp;
void OnEnable()
{
m_MaxPixelLights = serializedObject.FindProperty("m_MaxPixelLights");
m_SupportsVertexLightProp = serializedObject.FindProperty("m_SupportsVertexLight");
m_EnableLightmapsProp = serializedObject.FindProperty("m_EnableLightmaps");
m_EnableAmbientProbeProp = serializedObject.FindProperty("m_EnableAmbientProbe");
m_ShadowTypeProp = serializedObject.FindProperty("m_ShadowType");
m_ShadowNearPlaneOffsetProp = serializedObject.FindProperty("m_ShadowNearPlaneOffset");
m_ShadowBiasProperty = serializedObject.FindProperty("m_ShadowBias");
m_ShadowDistanceProp = serializedObject.FindProperty("m_ShadowDistance");
m_ShadowAtlasResolutionProp = serializedObject.FindProperty("m_ShadowAtlasResolution");
m_ShadowCascadesProp = serializedObject.FindProperty("m_ShadowCascades");
m_ShadowCascade2SplitProp = serializedObject.FindProperty("m_Cascade2Split");
m_ShadowCascade4SplitProp = serializedObject.FindProperty("m_Cascade4Split");
}
public override void OnInspectorGUI()
{
LowEndMobilePipelineAsset pipeAsset = target as LowEndMobilePipelineAsset;
serializedObject.Update();
EditorGUILayout.Space();
EditorGUILayout.LabelField(Styles.renderingLabel, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_MaxPixelLights, Styles.maxPixelLights);
EditorGUILayout.PropertyField(m_SupportsVertexLightProp, Styles.enableVertexLightLabel);
EditorGUILayout.PropertyField(m_EnableLightmapsProp, Styles.enableLightmap);
EditorGUILayout.PropertyField(m_EnableAmbientProbeProp, Styles.enableAmbientProbe);
EditorGUI.indentLevel--;
EditorGUILayout.Space();
EditorGUILayout.Space();
EditorGUILayout.LabelField(Styles.shadowLabel, EditorStyles.boldLabel);
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_ShadowTypeProp, Styles.shadowType);
EditorGUILayout.PropertyField(m_ShadowAtlasResolutionProp, Styles.shadowAtlasResolution);
EditorGUILayout.PropertyField(m_ShadowNearPlaneOffsetProp, Styles.shadowNearPlaneOffset);
EditorGUILayout.PropertyField(m_ShadowBiasProperty, Styles.shadowBias);
EditorGUILayout.PropertyField(m_ShadowDistanceProp, Styles.shadowDistante);
EditorGUILayout.PropertyField(m_ShadowCascadesProp, Styles.shadowCascades);
ShadowCascades cascades = (ShadowCascades) m_ShadowCascadesProp.intValue;
if (cascades == ShadowCascades.FOUR_CASCADES)
{
EditorGUILayout.PropertyField(m_ShadowCascade4SplitProp, Styles.shadowCascadeSplit);
}
else if (cascades == ShadowCascades.TWO_CASCADES)
{
EditorGUILayout.PropertyField(m_ShadowCascade2SplitProp, Styles.shadowCascadeSplit);
}
EditorGUI.indentLevel--;
serializedObject.ApplyModifiedProperties();
}
}
}

22
Assets/LowEndMobilePipeline/Editor/StandardToLowEndMaterialUpgrader.cs


using System.Collections.Generic;
using UnityEditor;
using UnityEditor.Experimental.Rendering;
public class StandardToLowEndMaterialUpgrader : MaterialUpgrader
{
[MenuItem("LowEndMobilePipeline/Material Upgraders/Upgrade Standard Materials to LDRenderPipeline")]
private static void UpgradeMaterialsToLD()
{
List<MaterialUpgrader> upgraders = new List<MaterialUpgrader>();
upgraders.Add(new StandardToLowEndMaterialUpgrader("Standard (Specular setup)"));
upgraders.Add(new StandardToLowEndMaterialUpgrader("Standard"));
upgraders.Add(new StandardToLowEndMaterialUpgrader("TerrainSurface"));
MaterialUpgrader.UpgradeProjectFolder(upgraders, "Upgrade to LD Materials");
}
StandardToLowEndMaterialUpgrader(string oldShaderName)
{
RenameShader(oldShaderName, "LowEndMobilePipeline/Specular");
}
}

381
Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs


using System;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
namespace UnityEngine.Experimental.Rendering.LowendMobile
{
public class LowEndMobilePipeline : RenderPipeline
{
private readonly LowEndMobilePipelineAsset m_Asset;
private static readonly int kMaxCascades = 4;
private static readonly int kMaxLights = 8;
private int m_ShadowMapProperty;
private RenderTargetIdentifier m_ShadowMapRTID;
private int m_DepthBufferBits = 24;
private static readonly ShaderPassName m_ForwardBasePassName = new ShaderPassName("LowEndMobileForward");
private Vector4[] m_LightPositions = new Vector4[kMaxLights];
private Vector4[] m_LightColors = new Vector4[kMaxLights];
private Vector4[] m_LightAttenuations = new Vector4[kMaxLights];
private Vector4[] m_LightSpotDirections = new Vector4[kMaxLights];
private ShadowSettings m_ShadowSettings = ShadowSettings.Default;
private ShadowSliceData[] m_ShadowSlices = new ShadowSliceData[kMaxCascades];
public LowEndMobilePipeline(LowEndMobilePipelineAsset asset)
{
m_Asset = asset;
BuildShadowSettings();
m_ShadowMapProperty = Shader.PropertyToID("_ShadowMap");
m_ShadowMapRTID = new RenderTargetIdentifier(m_ShadowMapProperty);
}
public override void Render(ScriptableRenderContext context, Camera[] cameras)
{
var prevPipe = Shader.globalRenderPipeline;
Shader.globalRenderPipeline = "LowEndMobilePipeline";
base.Render(context, cameras);
foreach (Camera camera in cameras)
{
CullingParameters cullingParameters;
camera.farClipPlane = 1000.0f;
if (!CullResults.GetCullingParameters(camera, out cullingParameters))
continue;
cullingParameters.shadowDistance = m_ShadowSettings.maxShadowDistance;
CullResults cull = CullResults.Cull(ref cullingParameters, context);
var cmd = new CommandBuffer() {name = "Clear"};
cmd.ClearRenderTarget(true, true, Color.black);
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();
// Render Shadow Map
bool shadowsRendered = RenderShadows(cull, context);
// Draw Opaques with support to one directional shadow cascade
// Setup camera matrices
context.SetupCameraProperties(camera);
// Setup light and shadow shader constants
SetupLightShaderVariables(cull.visibleLights, context);
if (shadowsRendered)
SetupShadowShaderVariables(context, camera.nearClipPlane, cullingParameters.shadowDistance,
m_ShadowSettings.directionalLightCascadeCount);
// Render Opaques
var settings = new DrawRendererSettings(cull, camera, m_ForwardBasePassName);
settings.sorting.flags = SortFlags.CommonOpaque;
settings.inputFilter.SetQueuesOpaque();
if (m_Asset.EnableLightmap)
settings.rendererConfiguration = settings.rendererConfiguration |
RendererConfiguration.PerObjectLightmaps;
if (m_Asset.EnableAmbientProbe)
settings.rendererConfiguration = settings.rendererConfiguration |
RendererConfiguration.PerObjectLightProbe;
context.DrawRenderers(ref settings);
var discardRT = new CommandBuffer();
discardRT.ReleaseTemporaryRT(m_ShadowMapProperty);
context.ExecuteCommandBuffer(discardRT);
discardRT.Dispose();
// TODO: Check skybox shader
context.DrawSkybox(camera);
// Render Alpha blended
settings.sorting.flags = SortFlags.CommonTransparent;
settings.inputFilter.SetQueuesTransparent();
context.DrawRenderers(ref settings);
}
context.Submit();
Shader.globalRenderPipeline = prevPipe;
}
private void BuildShadowSettings()
{
m_ShadowSettings = ShadowSettings.Default;
m_ShadowSettings.directionalLightCascadeCount = m_Asset.CascadeCount;
m_ShadowSettings.shadowAtlasWidth = m_Asset.ShadowAtlasResolution;
m_ShadowSettings.shadowAtlasHeight = m_Asset.ShadowAtlasResolution;
m_ShadowSettings.maxShadowDistance = m_Asset.ShadowDistance;
switch (m_ShadowSettings.directionalLightCascadeCount)
{
case 1:
m_ShadowSettings.directionalLightCascades = new Vector3(1.0f, 0.0f, 0.0f);
break;
case 2:
m_ShadowSettings.directionalLightCascades = new Vector3(m_Asset.Cascade2Split, 1.0f, 0.0f);
break;
default:
m_ShadowSettings.directionalLightCascades = m_Asset.Cascade4Split;
break;
}
}
#region HelperMethods
private void SetupLightShaderVariables(VisibleLight[] lights, ScriptableRenderContext context)
{
if (lights.Length <= 0)
return;
int pixelLightCount = Mathf.Min(lights.Length, m_Asset.MaxSupportedPixelLights);
int vertexLightCount = (m_Asset.SupportsVertexLight)
? Mathf.Min(lights.Length - pixelLightCount, kMaxLights)
: 0;
int totalLightCount = pixelLightCount + vertexLightCount;
for (int i = 0; i < totalLightCount; ++i)
{
VisibleLight currLight = lights[i];
if (currLight.lightType == LightType.Directional)
{
Vector4 dir = -currLight.localToWorld.GetColumn(2);
m_LightPositions[i] = new Vector4(dir.x, dir.y, dir.z, 0.0f);
}
else
{
Vector4 pos = currLight.localToWorld.GetColumn(3);
m_LightPositions[i] = new Vector4(pos.x, pos.y, pos.z, 1.0f);
}
m_LightColors[i] = currLight.finalColor;
float rangeSq = currLight.range*currLight.range;
float quadAtten = (currLight.lightType == LightType.Directional) ? 0.0f : 25.0f/rangeSq;
if (currLight.lightType == LightType.Spot)
{
Vector4 dir = currLight.localToWorld.GetColumn(2);
m_LightSpotDirections[i] = new Vector4(-dir.x, -dir.y, -dir.z, 0.0f);
float spotAngle = Mathf.Deg2Rad*currLight.spotAngle;
float cosOuterAngle = Mathf.Cos(spotAngle*0.5f);
float cosInneAngle = Mathf.Cos(spotAngle*0.25f);
float angleRange = cosInneAngle - cosOuterAngle;
m_LightAttenuations[i] = new Vector4(cosOuterAngle,
Mathf.Approximately(angleRange, 0.0f) ? 1.0f : angleRange, quadAtten, rangeSq);
}
else
{
m_LightSpotDirections[i] = new Vector4(0.0f, 0.0f, 1.0f, 0.0f);
m_LightAttenuations[i] = new Vector4(-1.0f, 1.0f, quadAtten, rangeSq);
}
}
CommandBuffer cmd = new CommandBuffer() {name = "SetupShadowShaderConstants"};
cmd.SetGlobalVectorArray("globalLightPos", m_LightPositions);
cmd.SetGlobalVectorArray("globalLightColor", m_LightColors);
cmd.SetGlobalVectorArray("globalLightAtten", m_LightAttenuations);
cmd.SetGlobalVectorArray("globalLightSpotDir", m_LightSpotDirections);
cmd.SetGlobalVector("globalLightCount", new Vector4(pixelLightCount, totalLightCount, 0.0f, 0.0f));
SetShadowKeywords(cmd);
context.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
private bool RenderShadows(CullResults cullResults, ScriptableRenderContext context)
{
int cascadeCount = m_ShadowSettings.directionalLightCascadeCount;
VisibleLight[] lights = cullResults.visibleLights;
int lightCount = lights.Length;
int shadowResolution = 0;
int lightIndex = -1;
for (int i = 0; i < lightCount; ++i)
{
if (lights[i].light.shadows != LightShadows.None && lights[i].lightType == LightType.Directional)
{
lightIndex = i;
shadowResolution = GetMaxTileResolutionInAtlas(m_ShadowSettings.shadowAtlasWidth,
m_ShadowSettings.shadowAtlasHeight, cascadeCount);
break;
}
}
if (lightIndex < 0)
return false;
Bounds bounds;
if (!cullResults.GetShadowCasterBounds(lightIndex, out bounds))
return false;
var setRenderTargetCommandBuffer = new CommandBuffer();
setRenderTargetCommandBuffer.name = "Render packed shadows";
setRenderTargetCommandBuffer.GetTemporaryRT(m_ShadowMapProperty, m_ShadowSettings.shadowAtlasWidth,
m_ShadowSettings.shadowAtlasHeight, m_DepthBufferBits, FilterMode.Bilinear, RenderTextureFormat.Depth,
RenderTextureReadWrite.Linear);
setRenderTargetCommandBuffer.SetRenderTarget(m_ShadowMapRTID);
setRenderTargetCommandBuffer.ClearRenderTarget(true, true, Color.black);
context.ExecuteCommandBuffer(setRenderTargetCommandBuffer);
setRenderTargetCommandBuffer.Dispose();
float shadowNearPlane = m_Asset.ShadowNearOffset;
Vector3 splitRatio = m_ShadowSettings.directionalLightCascades;
Vector3 lightDir = lights[lightIndex].light.transform.forward;
for (int cascadeIdx = 0; cascadeIdx < cascadeCount; ++cascadeIdx)
{
Matrix4x4 view, proj;
var settings = new DrawShadowsSettings(cullResults, lightIndex);
bool needRendering = cullResults.ComputeDirectionalShadowMatricesAndCullingPrimitives(lightIndex,
cascadeIdx, cascadeCount, splitRatio, shadowResolution, shadowNearPlane, out view, out proj,
out settings.splitData);
if (needRendering)
{
SetupShadowSliceTransform(cascadeIdx, shadowResolution, proj, view);
RenderShadowSlice(ref context, lightDir, cascadeIdx, proj, view, settings);
}
}
return true;
}
private void SetupShadowSliceTransform(int cascadeIndex, int shadowResolution, Matrix4x4 proj, Matrix4x4 view)
{
// Assumes MAX_CASCADES = 4
m_ShadowSlices[cascadeIndex].atlasX = (cascadeIndex%2)*shadowResolution;
m_ShadowSlices[cascadeIndex].atlasY = (cascadeIndex/2)*shadowResolution;
m_ShadowSlices[cascadeIndex].shadowResolution = shadowResolution;
m_ShadowSlices[cascadeIndex].shadowTransform = Matrix4x4.identity;
var matScaleBias = Matrix4x4.identity;
matScaleBias.m00 = 0.5f;
matScaleBias.m11 = 0.5f;
matScaleBias.m22 = 0.5f;
matScaleBias.m03 = 0.5f;
matScaleBias.m23 = 0.5f;
matScaleBias.m13 = 0.5f;
// Later down the pipeline the proj matrix will be scaled to reverse-z in case of DX.
// We need account for that scale in the shadowTransform.
if (SystemInfo.usesReversedZBuffer)
matScaleBias.m22 = -0.5f;
var matTile = Matrix4x4.identity;
matTile.m00 = (float) m_ShadowSlices[cascadeIndex].shadowResolution/
(float) m_ShadowSettings.shadowAtlasWidth;
matTile.m11 = (float) m_ShadowSlices[cascadeIndex].shadowResolution/
(float) m_ShadowSettings.shadowAtlasHeight;
matTile.m03 = (float) m_ShadowSlices[cascadeIndex].atlasX/(float) m_ShadowSettings.shadowAtlasWidth;
matTile.m13 = (float) m_ShadowSlices[cascadeIndex].atlasY/(float) m_ShadowSettings.shadowAtlasHeight;
m_ShadowSlices[cascadeIndex].shadowTransform = matTile*matScaleBias*proj*view;
}
private void RenderShadowSlice(ref ScriptableRenderContext context, Vector3 lightDir, int cascadeIndex,
Matrix4x4 proj, Matrix4x4 view, DrawShadowsSettings settings)
{
var buffer = new CommandBuffer() {name = "Prepare Shadowmap Slice"};
buffer.SetViewport(new Rect(m_ShadowSlices[cascadeIndex].atlasX, m_ShadowSlices[cascadeIndex].atlasY,
m_ShadowSlices[cascadeIndex].shadowResolution, m_ShadowSlices[cascadeIndex].shadowResolution));
buffer.SetViewProjectionMatrices(view, proj);
buffer.SetGlobalVector("_WorldLightDirAndBias",
new Vector4(-lightDir.x, -lightDir.y, -lightDir.z, m_Asset.ShadowBias));
context.ExecuteCommandBuffer(buffer);
buffer.Dispose();
context.DrawShadows(ref settings);
}
private int GetMaxTileResolutionInAtlas(int atlasWidth, int atlasHeight, int tileCount)
{
int resolution = Mathf.Min(atlasWidth, atlasHeight);
if (tileCount > Mathf.Log(resolution))
{
Debug.LogError(
String.Format(
"Cannot fit {0} tiles into current shadowmap atlas of size ({1}, {2}). ShadowMap Resolution set to zero.",
tileCount, atlasWidth, atlasHeight));
return 0;
}
int currentTileCount = atlasWidth/resolution*atlasHeight/resolution;
while (currentTileCount < tileCount)
{
resolution = resolution >> 1;
currentTileCount = atlasWidth/resolution*atlasHeight/resolution;
}
return resolution;
}
void SetupShadowShaderVariables(ScriptableRenderContext context, float shadowNear, float shadowFar,
int cascadeCount)
{
float shadowResolution = m_ShadowSlices[0].shadowResolution;
// PSSM distance settings
float shadowFrustumDepth = shadowFar - shadowNear;
Vector3 shadowSplitRatio = m_ShadowSettings.directionalLightCascades;
// We set PSSMDistance to infinity for non active cascades so the comparison test always fails for unavailable cascades
Vector4 PSSMDistances = new Vector4(
shadowNear + shadowSplitRatio.x*shadowFrustumDepth,
(shadowSplitRatio.y > 0.0f) ? shadowNear + shadowSplitRatio.y*shadowFrustumDepth : Mathf.Infinity,
(shadowSplitRatio.z > 0.0f) ? shadowNear + shadowSplitRatio.z*shadowFrustumDepth : Mathf.Infinity,
1.0f/shadowResolution);
const int maxShadowCascades = 4;
Matrix4x4[] shadowMatrices = new Matrix4x4[maxShadowCascades];
for (int i = 0; i < cascadeCount; ++i)
shadowMatrices[i] = (cascadeCount >= i) ? m_ShadowSlices[i].shadowTransform : Matrix4x4.identity;
// TODO: shadow resolution per cascade in case cascades endup being supported.
float invShadowResolution = 1.0f/shadowResolution;
float[] pcfKernel =
{
-0.5f*invShadowResolution, 0.5f*invShadowResolution,
0.5f*invShadowResolution, 0.5f*invShadowResolution,
-0.5f*invShadowResolution, -0.5f*invShadowResolution,
0.5f*invShadowResolution, -0.5f*invShadowResolution
};
var setupShadow = new CommandBuffer() {name = "SetupShadowShaderConstants"};
SetShadowKeywords(setupShadow);
setupShadow.SetGlobalMatrixArray("_WorldToShadow", shadowMatrices);
setupShadow.SetGlobalVector("_PSSMDistancesAndShadowResolution", PSSMDistances);
setupShadow.SetGlobalFloatArray("_PCFKernel", pcfKernel);
SetShadowKeywords(setupShadow);
context.ExecuteCommandBuffer(setupShadow);
setupShadow.Dispose();
}
void SetShadowKeywords(CommandBuffer cmd)
{
switch (m_Asset.CurrShadowType)
{
case ShadowType.NO_SHADOW:
cmd.DisableShaderKeyword("HARD_SHADOWS");
cmd.DisableShaderKeyword("SOFT_SHADOWS");
break;
case ShadowType.HARD_SHADOWS:
cmd.EnableShaderKeyword("HARD_SHADOWS");
cmd.DisableShaderKeyword("SOFT_SHADOWS");
break;
case ShadowType.SOFT_SHADOWS:
cmd.DisableShaderKeyword("HARD_SHADOWS");
cmd.EnableShaderKeyword("SOFT_SHADOWS");
break;
}
}
#endregion
}
}

25
Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset


%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3}
m_Name: LowEndMobilePipelineAsset
m_EditorClassIdentifier:
m_MaxPixelLights: 1
m_SupportsVertexLight: 1
m_EnableLightmaps: 1
m_EnableAmbientProbe: 1
m_ShadowType: 1
m_ShadowAtlasResolution: 1024
m_ShadowNearPlaneOffset: 2
m_ShadowDistance: 50
m_ShadowBias: 0.05
m_ShadowCascades: 4
m_Cascade2Split: 0.25
m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467}

9
Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset.meta


fileFormatVersion: 2
guid: 877878ed40e8ad94095582ff91179016
timeCreated: 1488808435
licenseType: Pro
NativeFormatImporter:
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

145
Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs


namespace UnityEngine.Experimental.Rendering.LowendMobile
{
public enum ShadowCascades
{
NO_CASCADES = 1,
TWO_CASCADES = 2,
FOUR_CASCADES = 4,
}
public enum ShadowType
{
NO_SHADOW = 0,
HARD_SHADOWS,
SOFT_SHADOWS,
}
public enum ShadowResolution
{
_512 = 512,
_1024 = 1024,
_2048 = 2048
}
public class LowEndMobilePipelineAsset : RenderPipelineAsset
{
#region AssetAndPipelineCreation
#if UNITY_EDITOR
[UnityEditor.MenuItem("LowEndMobilePipeline/Create Pipeline Asset")]
static void CreateLowEndPipeline()
{
var instance = ScriptableObject.CreateInstance<LowEndMobilePipelineAsset>();
UnityEditor.AssetDatabase.CreateAsset(instance,
"Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.asset");
}
#endif
protected override IRenderPipeline InternalCreatePipeline()
{
return new LowEndMobilePipeline(this);
}
#endregion
#region PipelineAssetSettings
[SerializeField] private int m_MaxPixelLights = 1;
[SerializeField] private bool m_SupportsVertexLight = true;
[SerializeField] private bool m_EnableLightmaps = true;
[SerializeField] private bool m_EnableAmbientProbe = true;
[SerializeField] private ShadowType m_ShadowType = ShadowType.HARD_SHADOWS;
[SerializeField] private ShadowResolution m_ShadowAtlasResolution = ShadowResolution._1024;
[SerializeField] private float m_ShadowNearPlaneOffset = 2.0f;
[SerializeField] private float m_ShadowDistance = 50.0f;
[SerializeField] private float m_ShadowBias = 0.0005f;
[SerializeField] private ShadowCascades m_ShadowCascades = ShadowCascades.NO_CASCADES;
[SerializeField] private float m_Cascade2Split = 0.25f;
[SerializeField] private Vector3 m_Cascade4Split = new Vector3(0.067f, 0.2f, 0.467f);
public int MaxSupportedPixelLights
{
get { return m_MaxPixelLights; }
private set { m_MaxPixelLights = value; }
}
public bool SupportsVertexLight
{
get { return m_SupportsVertexLight; }
private set { m_SupportsVertexLight = value; }
}
public bool EnableLightmap
{
get { return m_EnableLightmaps; }
private set { m_EnableLightmaps = value; }
}
public bool EnableAmbientProbe
{
get { return m_EnableAmbientProbe; }
private set { m_EnableAmbientProbe = value; }
}
public ShadowType CurrShadowType
{
get { return m_ShadowType; }
private set { m_ShadowType = value; }
}
public int ShadowAtlasResolution
{
get { return (int) m_ShadowAtlasResolution; }
private set { m_ShadowAtlasResolution = (ShadowResolution) value; }
}
public float ShadowNearOffset
{
get { return m_ShadowNearPlaneOffset; }
private set { m_ShadowNearPlaneOffset = value; }
}
public float ShadowDistance
{
get { return m_ShadowDistance; }
private set { m_ShadowDistance = value; }
}
public float ShadowBias
{
get { return m_ShadowBias; }
private set { m_ShadowBias = value; }
}
public int CascadeCount
{
get { return (int) m_ShadowCascades; }
private set { m_ShadowCascades = (ShadowCascades) value; }
}
public float Cascade2Split
{
get { return m_Cascade2Split; }
private set { m_Cascade2Split = value; }
}
public Vector3 Cascade4Split
{
get { return m_Cascade4Split; }
private set { m_Cascade4Split = value; }
}
#endregion
}
}

12
Assets/LowEndMobilePipeline/LowEndMobilePipelineAsset.cs.meta


fileFormatVersion: 2
guid: bf2edee5c58d82540a51f03df9d42094
timeCreated: 1488808083
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

9
Assets/LowEndMobilePipeline/TestScenes.meta


fileFormatVersion: 2
guid: 2c0fa72aa713a664b9be2de857697293
folderAsset: yes
timeCreated: 1488808638
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

1001
Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.unity
文件差异内容过多而无法显示
查看文件

/Assets/LowEndRenderPipeline.meta → /Assets/LowEndMobilePipeline.meta

/Assets/LowEndRenderPipeline/LowEndRenderPipeline.cs.meta → /Assets/LowEndMobilePipeline/LowEndMobilePipeline.cs.meta

/Assets/LowEndRenderPipeline/Materials.meta → /Assets/LowEndMobilePipeline/TestScenes/Materials.meta

/Assets/LowEndRenderPipeline/Textures.meta → /Assets/LowEndMobilePipeline/TestScenes/Textures.meta

/Assets/LowEndRenderPipeline/Textures → /Assets/LowEndMobilePipeline/TestScenes/Textures

/Assets/LowEndRenderPipeline/Editor.meta → /Assets/LowEndMobilePipeline/Editor.meta

/Assets/LowEndRenderPipeline/LDRenderPipelineVikingVillage → /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage

/Assets/LowEndRenderPipeline/LDRenderPipelineBasicScene.meta → /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.meta

/Assets/LowEndRenderPipeline/LDRenderPipelineBasicScene.unity.meta → /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene.unity.meta

/Assets/LowEndRenderPipeline/LDRenderPipelineVikingVillage.meta → /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage.meta

/Assets/LowEndRenderPipeline/LDRenderPipelineVikingVillage.unity → /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage.unity

/Assets/LowEndRenderPipeline/LDRenderPipelineVikingVillage.unity.meta → /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineVikingVillage.unity.meta

/Assets/LowEndRenderPipeline/LDRenderPipelineBasicScene → /Assets/LowEndMobilePipeline/TestScenes/LDRenderPipelineBasicScene

/Assets/LowEndRenderPipeline/Editor/StandardSpecularToLDMaterialUpgrader.cs.meta → /Assets/LowEndMobilePipeline/Editor/StandardToLowEndMaterialUpgrader.cs.meta

/Assets/LowEndRenderPipeline/Editor/MobileToLDMaterialUpgrader.cs.meta → /Assets/LowEndMobilePipeline/Editor/LegacyMobileToLowendMobileUpgrader.cs.meta

/Assets/LowEndRenderPipeline/Editor/LDRenderPipelineMaterialEditor.cs.meta → /Assets/LowEndMobilePipeline/Editor/LowendMobilePipelineMaterialEditor.cs.meta

/Assets/LowEndRenderPipeline/Editor/LDRenderPipelineInspector.cs.meta → /Assets/LowEndMobilePipeline/Editor/LowendPipelineAssetInspector.cs.meta

/Assets/LowEndRenderPipeline/Editor/LDRenderPipelineMaterialEditor.cs → /Assets/LowEndMobilePipeline/Editor/LowendMobilePipelineMaterialEditor.cs

/Assets/LowEndRenderPipeline/Materials → /Assets/LowEndMobilePipeline/TestScenes/Materials

/Assets/LowEndRenderPipeline/Shaders/LDRenderPipe-Specular.shader.meta → /Assets/LowEndMobilePipeline/LowEndMobilePipeline.shader.meta

/Assets/LowEndRenderPipeline/Shaders/LDRenderPipe-Specular.shader → /Assets/LowEndMobilePipeline/LowEndMobilePipeline.shader

正在加载...
取消
保存