浏览代码

fptl: added skybox rendering and a final blit pass, got rid of flip vertical nonsense in the shader

/main
vlad-andreev 8 年前
当前提交
d8b94019
共有 4 个文件被更改,包括 283 次插入21 次删除
  1. 16
      Assets/ScriptableRenderLoop/fptl/FptlLighting.cs
  2. 3
      Assets/ScriptableRenderLoop/fptl/Internal-DeferredReflections.shader
  3. 3
      Assets/ScriptableRenderLoop/fptl/Internal-DeferredShading.shader
  4. 282
      Assets/ScriptableRenderLoop/common/SkyboxHelper.cs

16
Assets/ScriptableRenderLoop/fptl/FptlLighting.cs


static private int kGBufferNormal;
static private int kGBufferEmission;
static private int kGBufferZ;
static private int kCameraTarget;
static private int kCameraDepthTexture;

kGBufferEmission = Shader.PropertyToID("_CameraGBufferTexture3");
kGBufferZ = Shader.PropertyToID("_CameraGBufferZ"); // used while rendering into G-buffer+
kCameraDepthTexture = Shader.PropertyToID("_CameraDepthTexture"); // copy of that for later sampling in shaders
// RenderLoop.renderLoopDelegate += ExecuteRenderLoop;
//var deferredShader = GraphicsSettings.GetCustomShader (BuiltinShaderType.DeferredShading);

//cmd.SetRenderTarget(new RenderTargetIdentifier(kGBufferEmission), new RenderTargetIdentifier(kGBufferZ));
// for whatever reason, the output is flipped in the scene view whenever writing to the camera target.
// TODO: fix this properly.
if (camera.cameraType == CameraType.SceneView)
{
cmd.SetGlobalFloat("g_flipVertical", 0);
}
else
{
cmd.SetGlobalFloat("g_flipVertical", 1);
}
cmd.SetGlobalMatrix("g_mViewToWorld", viewToWorld);
cmd.SetGlobalMatrix("g_mWorldToView", viewToWorld.inverse);
cmd.SetGlobalMatrix("g_mScrProjection", scrProj);

//cmd.Blit (kGBufferNormal, (RenderTexture)null); // debug: display normals
cmd.Blit(kGBufferEmission, BuiltinRenderTextureType.CameraTarget, m_DeferredMaterial, 0);
cmd.Blit(kGBufferEmission, BuiltinRenderTextureType.CameraTarget, m_DeferredReflectionMaterial, 0);
loop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}

DoTiledDeferredLighting(camera, loop, camera.cameraToWorldMatrix, projscr, invProjscr, lightList);
//lightList.Release();
loop.Submit();
}

3
Assets/ScriptableRenderLoop/fptl/Internal-DeferredReflections.shader


uniform float4x4 g_mWorldToView;
uniform float4x4 g_mInvScrProjection;
uniform float4x4 g_mScrProjection;
uniform float g_flipVertical; // giant temp hack, see DoTiledDeferredLighting()
Texture2D _CameraDepthTexture;
Texture2D _CameraGBufferTexture0;

uint nrTilesX = (iWidth+15)/16;
uint nrTilesY = (iHeight+15)/16;
if (g_flipVertical > 0)
pixCoord.y = (iHeight - 1) - pixCoord.y;
uint2 tileIDX = pixCoord / 16;
const int offs = tileIDX.y*nrTilesX+tileIDX.x + nrTilesX*nrTilesY; // offset to where the reflection probes are

3
Assets/ScriptableRenderLoop/fptl/Internal-DeferredShading.shader


uniform float4x4 g_mViewToWorld;
uniform float4x4 g_mInvScrProjection;
uniform float4x4 g_mScrProjection;
uniform float g_flipVertical; // giant temp hack, see DoTiledDeferredLighting()
uniform uint g_nDirLights;
//---------------------------------------------------------------------------------------------------------------------------------------------------------

uint nrTilesX = (iWidth+15)/16;
uint nrTilesY = (iHeight+15)/16;
if (g_flipVertical > 0)
pixCoord.y = (iHeight-1) - pixCoord.y;
uint2 tileIDX = pixCoord / 16;
const int offs = tileIDX.y*nrTilesX+tileIDX.x;

282
Assets/ScriptableRenderLoop/common/SkyboxHelper.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine.Rendering;
using UnityEngine;
public class SkyboxHelper
{
public SkyboxHelper()
{
}
const int NumFullSubdivisions = 3; // 3 subdivs == 2048 triangles
const int NumHorizonSubdivisions = 2;
public void CreateMesh()
{
Vector3[] vertData = new Vector3[8 * 3];
for (int i = 0; i < 8 * 3; i++)
{
vertData[i] = octaVerts[i];
}
// Regular subdivisions
for (int i = 0; i < NumFullSubdivisions; i++)
{
Vector3[] srcData = vertData.Clone() as Vector3[];
List<Vector3> verts = new List<Vector3>();
for (int k = 0; k < srcData.Length; k += 3)
{
Subdivide(verts, srcData[k], srcData[k + 1], srcData[k + 2]);
}
vertData = verts.ToArray();
}
// Horizon subdivisions
float horizonLimit = 1.0f;
for (int i = 0; i < NumHorizonSubdivisions; i++)
{
Vector3[] srcData = vertData.Clone() as Vector3[];
List<Vector3> verts = new List<Vector3>();
horizonLimit *= 0.5f; // First iteration limit to y < +-0.5, next one 0.25 etc.
for (int k = 0; k < srcData.Length; k += 3)
{
float maxAbsY = Mathf.Max(Mathf.Abs(srcData[k].y), Mathf.Abs(srcData[k + 1].y), Mathf.Abs(srcData[k + 2].y));
if (maxAbsY > horizonLimit)
{
// Pass through existing triangle
verts.Add(srcData[k]);
verts.Add(srcData[k + 1]);
verts.Add(srcData[k + 2]);
}
else
{
SubdivideYOnly(verts, srcData[k], srcData[k + 1], srcData[k + 2]);
}
}
vertData = verts.ToArray();
}
// Write out the mesh
int vertexCount = vertData.Length;
var triangles = new int[vertexCount];
for (int i = 0; i < vertexCount; i++)
{
triangles[i] = i;
}
_mesh = new Mesh();
_mesh.vertices = vertData;
_mesh.triangles = triangles;
}
public UnityEngine.Mesh mesh
{
get { return _mesh; }
}
public void Draw(RenderLoop loop, Camera camera)
{
if (camera.clearFlags != CameraClearFlags.Skybox)
{
return;
}
CommandBuffer cmd = new CommandBuffer();
cmd.name = "Skybox";
Light sunLight = RenderSettings.sun;
Color sunColor = new Color(0, 0, 0);
Vector3 sunDir = new Vector3(0, 0, -1);
if (sunLight != null)
{
sunColor = sunLight.color;
Transform xform = sunLight.transform;
sunDir = xform.TransformDirection(sunDir);
}
Material mat = RenderSettings.skybox;
bool looksLikeSixSidedShader = true;
looksLikeSixSidedShader &= (mat.passCount == 6); // should have six passes
//looksLikeSixSidedShader &= !mat.GetShader()->GetShaderLabShader()->HasLightingPasses();
if (looksLikeSixSidedShader)
{
Debug.LogWarning("Six sided skybox not yet supported.");
}
else
{
if (mesh == null)
{
CreateMesh();
}
cmd.SetGlobalVector("_LightColor0", sunColor);
cmd.SetGlobalVector("_WorldSpaceLightPos0", sunDir);
float dist = camera.farClipPlane * 10.0f;
Matrix4x4 world = Matrix4x4.TRS(camera.transform.position, Quaternion.identity, new Vector3(dist, dist, dist));
Matrix4x4 skyboxProj = SkyboxHelper.GetProjectionMatrix(camera);
cmd.SetProjectionAndViewMatrices(skyboxProj, camera.worldToCameraMatrix);
cmd.DrawMesh(mesh, world, mat);
cmd.SetProjectionAndViewMatrices(camera.projectionMatrix, camera.worldToCameraMatrix);
}
loop.ExecuteCommandBuffer(cmd);
cmd.Dispose();
}
static public Matrix4x4 GetProjectionMatrix(Camera camera)
{
Matrix4x4 skyboxProj = Matrix4x4.Perspective(camera.fieldOfView, camera.aspect, camera.nearClipPlane, camera.farClipPlane);
float nearPlane = camera.nearClipPlane * 0.01f;
skyboxProj = AdjustDepthRange(skyboxProj, camera.nearClipPlane, nearPlane, camera.farClipPlane);
return MakeProjectionInfinite(skyboxProj, nearPlane);
}
static Matrix4x4 MakeProjectionInfinite(Matrix4x4 m, float nearPlane)
{
const float epsilon = 1e-6f;
Matrix4x4 r = m;
r[2, 2] = -1.0f + epsilon;
r[2, 3] = (-2.0f + epsilon) * nearPlane;
r[3, 2] = -1.0f;
return r;
}
static Matrix4x4 AdjustDepthRange(Matrix4x4 mat, float origNear, float newNear, float newFar)
{
float x = mat[0, 0];
float y = mat[1, 1];
float w = mat[0, 2];
float z = mat[1, 2];
float r = ((2.0f * origNear) / x) * ((w + 1) * 0.5f);
float t = ((2.0f * origNear) / y) * ((z + 1) * 0.5f);
float l = ((2.0f * origNear) / x) * (((w + 1) * 0.5f) - 1);
float b = ((2.0f * origNear) / y) * (((z + 1) * 0.5f) - 1);
float ratio = (newNear / origNear);
r *= ratio;
t *= ratio;
l *= ratio;
b *= ratio;
Matrix4x4 ret = new Matrix4x4();
ret[0, 0] = (2.0f * newNear) / (r - l); ret[0, 1] = 0; ret[0, 2] = (r + l) / (r - l); ret[0, 3] = 0;
ret[1, 0] = 0; ret[1, 1] = (2.0f * newNear) / (t - b); ret[1, 2] = (t + b) / (t - b); ret[1, 3] = 0;
ret[2, 0] = 0; ret[2, 1] = 0; ret[2, 2] = -(newFar + newNear) / (newFar - newNear); ret[2, 3] = -(2.0f * newFar * newNear) / (newFar - newNear);
ret[3, 0] = 0; ret[3, 1] = 0; ret[3, 2] = -1.0f; ret[3, 3] = 0;
return ret;
}
// Octahedron vertices
Vector3[] octaVerts =
{
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f), new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), new Vector3(-1.0f, 0.0f, 0.0f),
new Vector3(0.0f, 1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f), new Vector3(1.0f, 0.0f, 0.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(-1.0f, 0.0f, 0.0f), new Vector3(0.0f, 0.0f, 1.0f),
new Vector3(0.0f, -1.0f, 0.0f), new Vector3(0.0f, 0.0f, -1.0f), new Vector3(-1.0f, 0.0f, 0.0f),
};
Vector3 SubDivVert(Vector3 v1, Vector3 v2)
{
return Vector3.Normalize(v1 + v2);
}
void Subdivide(List<Vector3> dest, Vector3 v1, Vector3 v2, Vector3 v3)
{
Vector3 v12 = SubDivVert(v1, v2);
Vector3 v23 = SubDivVert(v2, v3);
Vector3 v13 = SubDivVert(v1, v3);
dest.Add(v1);
dest.Add(v12);
dest.Add(v13);
dest.Add(v12);
dest.Add(v2);
dest.Add(v23);
dest.Add(v23);
dest.Add(v13);
dest.Add(v12);
dest.Add(v3);
dest.Add(v13);
dest.Add(v23);
}
void SubdivideYOnly(List<Vector3> dest, Vector3 v1, Vector3 v2, Vector3 v3)
{
// Find out which vertex is furthest out from the others on the y axis
float d12 = Mathf.Abs(v2.y - v1.y);
float d23 = Mathf.Abs(v2.y - v3.y);
float d31 = Mathf.Abs(v3.y - v1.y);
Vector3 top, va, vb;
if (d12 < d23 && d12 < d31)
{
top = v3;
va = v1;
vb = v2;
}
else if (d23 < d12 && d23 < d31)
{
top = v1;
va = v2;
vb = v3;
}
else
{
top = v2;
va = v3;
vb = v1;
}
Vector3 v12 = SubDivVert(top, va);
Vector3 v13 = SubDivVert(top, vb);
dest.Add(top);
dest.Add(v12);
dest.Add(v13);
// A bit of extra logic to prevent triangle slivers: choose the shorter of (13->va), (12->vb) as triangle base
if ((v13 - va).sqrMagnitude > (v12 - vb).sqrMagnitude)
{
dest.Add(v12);
dest.Add(va);
dest.Add(vb);
dest.Add(v13);
dest.Add(v12);
dest.Add(vb);
}
else
{
dest.Add(v13);
dest.Add(v12);
dest.Add(va);
dest.Add(v13);
dest.Add(va);
dest.Add(vb);
}
}
Mesh _mesh;
}
正在加载...
取消
保存