提交 8f2532f0 编写于 作者: H happyfire

- GPU Rasterizer

上级 a4e2e6c3
......@@ -62,8 +62,12 @@
<Compile Include="Assets\URasterizer\Codes\CPURasterizer.cs" />
<Compile Include="Assets\URasterizer\Codes\GPURasterizer.cs" />
<Compile Include="Assets\URasterizer\Codes\TransformTool.cs" />
<None Include="Assets\URasterizer\Shaders\URVertexShader.hlsl" />
<None Include="Assets\URasterizer\DefaultAssets\DefaultShader.shader" />
<None Include="Assets\URasterizer\DefaultAssets\URComputeShader.compute" />
<None Include="Assets\URasterizer\Shaders\URCommon.hlsl" />
<None Include="Assets\URasterizer\Shaders\URTriangleProcess.hlsl" />
<None Include="Assets\URasterizer\Shaders\URFragmentShader.hlsl" />
<None Include="Assets\URasterizer\Shaders\URComputeShader.compute" />
<Reference Include="UnityEngine">
<HintPath>C:/Program Files/Unity/Hub/Editor/Unity 2020.3.25f1c1/Editor/Data/Managed/UnityEngine/UnityEngine.dll</HintPath>
</Reference>
......
......@@ -465,6 +465,7 @@ Transform:
- {fileID: 270156317}
- {fileID: 1326646622}
- {fileID: 949938250}
- {fileID: 1976593447}
m_Father: {fileID: 1977655288}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
......@@ -716,6 +717,102 @@ Animator:
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorControllerStateOnDisable: 0
--- !u!1 &1976593446
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1976593447}
- component: {fileID: 1976593450}
- component: {fileID: 1976593449}
- component: {fileID: 1976593448}
m_Layer: 0
m_Name: Sphere
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1976593447
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1976593446}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1.57, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 1651153439}
m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1976593448
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1976593446}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 275ec1cd091f7d54cb532cf4c552b27a, type: 3}
m_Name:
m_EditorClassIdentifier:
mesh: {fileID: 0}
DoubleSideRendering: 0
--- !u!23 &1976593449
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1976593446}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!33 &1976593450
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1976593446}
m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0}
--- !u!1 &1977655287
GameObject:
m_ObjectHideFlags: 0
......
......@@ -161,7 +161,7 @@ MeshRenderer:
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 2100000, guid: f9f96ee2bf6b64945b16abad7a676453, type: 2}
- {fileID: 10302, guid: 0000000000000000f000000000000000, type: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
......@@ -400,7 +400,6 @@ GameObject:
- component: {fileID: 1297680263}
- component: {fileID: 1297680262}
- component: {fileID: 1297680261}
- component: {fileID: 1297680260}
- component: {fileID: 1297680264}
- component: {fileID: 1297680265}
m_Layer: 0
......@@ -410,20 +409,6 @@ GameObject:
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!64 &1297680260
MeshCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1297680259}
m_Material: {fileID: 0}
m_IsTrigger: 0
m_Enabled: 1
serializedVersion: 4
m_Convex: 0
m_CookingOptions: 30
m_Mesh: {fileID: 10210, guid: 0000000000000000e000000000000000, type: 0}
--- !u!23 &1297680261
MeshRenderer:
m_ObjectHideFlags: 0
......
......@@ -13,25 +13,7 @@ namespace URasterizer
Matrix4x4 _matModel;
Matrix4x4 _matView;
Matrix4x4 _matProjection;
public Matrix4x4 ModelMatrix
{
get => _matModel;
set => _matModel = value;
}
public Matrix4x4 ViewMatrix
{
get => _matView;
set => _matView = value;
}
public Matrix4x4 ProjectionMatrix
{
get => _matProjection;
set => _matProjection = value;
}
Matrix4x4 _matProjection;
Color[] frame_buf;
float[] depth_buf;
......@@ -126,7 +108,7 @@ namespace URasterizer
public void Clear(BufferMask mask)
{
ProfileManager.BeginSample("Rasterizer.Clear");
ProfileManager.BeginSample("CPURasterizer.Clear");
if (_config.MSAA != MSAALevel.Disabled && !_config.WireframeMode)
{
......@@ -156,43 +138,48 @@ namespace URasterizer
ProfileManager.EndSample();
}
}
public void SetupViewProjectionMatrix(Camera camera)
public void SetupUniforms(Camera camera, Light mainLight)
{
//左手坐标系转右手坐标系,以下坐标和向量z取反
var camPos = camera.transform.position;
camPos.z *= -1;
var lookAt = camera.transform.forward;
lookAt.z *= -1;
var up = camera.transform.up;
up.z *= -1;
ViewMatrix = TransformTool.GetViewMatrix(camPos, lookAt, up);
if (camera.orthographic)
switch (_config.FragmentShaderType)
{
float halfOrthHeight = camera.orthographicSize;
float halfOrthWidth = halfOrthHeight * Aspect;
float f = -camera.farClipPlane;
float n = -camera.nearClipPlane;
ProjectionMatrix = TransformTool.GetOrthographicProjectionMatrix(-halfOrthWidth, halfOrthWidth, -halfOrthHeight, halfOrthHeight, f, n);
}
else
{
ProjectionMatrix = TransformTool.GetPerspectiveProjectionMatrix(camera.fieldOfView, Aspect, camera.nearClipPlane, camera.farClipPlane);
case ShaderType.VertexColor:
CurrentFragmentShader = ShaderContext.FSVertexColor;
break;
case ShaderType.BlinnPhong:
CurrentFragmentShader = ShaderContext.FSBlinnPhong;
break;
case ShaderType.NormalVisual:
CurrentFragmentShader = ShaderContext.FSNormalVisual;
break;
default:
CurrentFragmentShader = ShaderContext.FSBlinnPhong;
break;
}
ShaderContext.Config = _config;
var camPos = camera.transform.position;
camPos.z *= -1;
ShaderContext.Uniforms.WorldSpaceCameraPos = camPos;
var lightDir = mainLight.transform.forward;
lightDir.z *= -1;
ShaderContext.Uniforms.WorldSpaceLightDir = -lightDir;
ShaderContext.Uniforms.LightColor = mainLight.color * mainLight.intensity;
ShaderContext.Uniforms.AmbientColor = _config.AmbientColor;
TransformTool.SetupViewProjectionMatrix(camera, Aspect, out _matView, out _matProjection);
}
public void Draw(RenderingObject ro, Camera camera)
public void DrawObject(RenderingObject ro)
{
ProfileManager.BeginSample("Rasterizer.Draw");
ProfileManager.BeginSample("CPURasterizer.DrawObject");
Mesh mesh = ro.mesh;
SetupViewProjectionMatrix(camera);
ModelMatrix = ro.GetModelMatrix();
_matModel = ro.GetModelMatrix();
Matrix4x4 mvp = _matProjection * _matView * _matModel;
Matrix4x4 normalMat = _matModel.inverse.transpose;
......@@ -533,7 +520,7 @@ namespace URasterizer
private void RasterizeWireframe(Triangle t)
{
ProfileManager.BeginSample("Rasterizer.RasterizeWireframe");
ProfileManager.BeginSample("CPURasterizer.RasterizeWireframe");
DrawLine(t.Vertex0.Position, t.Vertex1.Position, t.Vertex0.Color, t.Vertex1.Color);
DrawLine(t.Vertex1.Position, t.Vertex2.Position, t.Vertex1.Color, t.Vertex2.Color);
DrawLine(t.Vertex2.Position, t.Vertex0.Position, t.Vertex2.Color, t.Vertex0.Color);
......@@ -547,7 +534,7 @@ namespace URasterizer
//Screen space rasterization
void RasterizeTriangle(Triangle t, RenderingObject ro)
{
ProfileManager.BeginSample("Rasterizer.RasterizeTriangle");
ProfileManager.BeginSample("CPURasterizer.RasterizeTriangle");
var v = _tmpVector4s;
v[0] = t.Vertex0.Position;
v[1] = t.Vertex1.Position;
......@@ -703,7 +690,7 @@ namespace URasterizer
bool IsInsideTriangle(int x, int y, Triangle t, float offsetX=0.5f, float offsetY=0.5f)
{
ProfileManager.BeginSample("Rasterizer.IsInsideTriangle");
ProfileManager.BeginSample("CPURasterizer.IsInsideTriangle");
var v = _tmpVector3s;
v[0] = new Vector3(t.Vertex0.Position.x, t.Vertex0.Position.y, t.Vertex0.Position.z);
v[1] = new Vector3(t.Vertex1.Position.x, t.Vertex1.Position.y, t.Vertex1.Position.z);
......@@ -738,7 +725,7 @@ namespace URasterizer
Vector3 ComputeBarycentric2D(float x, float y, Triangle t)
{
ProfileManager.BeginSample("Rasterizer.ComputeBarycentric2D");
ProfileManager.BeginSample("CPURasterizer.ComputeBarycentric2D");
var v = _tmpVector4s;
v[0] = t.Vertex0.Position;
v[1] = t.Vertex1.Position;
......@@ -770,7 +757,7 @@ namespace URasterizer
public void UpdateFrame()
{
ProfileManager.BeginSample("CameraRenderer.UpdateFrame");
ProfileManager.BeginSample("CPURasterizer.UpdateFrame");
switch (_config.DisplayBuffer)
{
......
......@@ -33,7 +33,9 @@ namespace URasterizer
private void OnPostRender()
{
Render();
if(_config.EnableRendering){
Render();
}
}
void Init()
......@@ -88,39 +90,14 @@ namespace URasterizer
var r = _rasterizer;
r.Clear(BufferMask.Color | BufferMask.Depth);
switch (_config.FragmentShaderType)
{
case ShaderType.VertexColor:
r.CurrentFragmentShader = ShaderContext.FSVertexColor;
break;
case ShaderType.BlinnPhong:
r.CurrentFragmentShader = ShaderContext.FSBlinnPhong;
break;
case ShaderType.NormalVisual:
r.CurrentFragmentShader = ShaderContext.FSNormalVisual;
break;
default:
r.CurrentFragmentShader = ShaderContext.FSBlinnPhong;
break;
}
ShaderContext.Config = _config;
var camPos = transform.position;
camPos.z *= -1;
ShaderContext.Uniforms.WorldSpaceCameraPos = camPos;
var lightDir = _mainLight.transform.forward;
lightDir.z *= -1;
ShaderContext.Uniforms.WorldSpaceLightDir = -lightDir;
ShaderContext.Uniforms.LightColor = _mainLight.color * _mainLight.intensity;
ShaderContext.Uniforms.AmbientColor = _config.AmbientColor;
r.SetupUniforms(_camera, _mainLight);
for (int i=0; i<renderingObjects.Count; ++i)
{
if (renderingObjects[i].gameObject.activeInHierarchy)
{
r.Draw(renderingObjects[i], _camera);
r.DrawObject(renderingObjects[i]);
}
}
......
......@@ -13,37 +13,10 @@ namespace URasterizer
Matrix4x4 _matModel;
Matrix4x4 _matView;
Matrix4x4 _matProjection;
public Matrix4x4 ModelMatrix
{
get => _matModel;
set => _matModel = value;
}
public Matrix4x4 ViewMatrix
{
get => _matView;
set => _matView = value;
}
public Matrix4x4 ProjectionMatrix
{
get => _matProjection;
set => _matProjection = value;
}
Color[] frame_buf;
float[] depth_buf;
Color[] temp_buf;
Color[] samplers_color_MSAA;
bool[] samplers_mask_MSAA;
float[] samplers_depth_MSAA;
Matrix4x4 _matProjection;
RenderTexture _colorTexture;
public FragmentShader CurrentFragmentShader {get; set;}
RenderTexture _depthTexture;
//Stats
int _trianglesAll, _trianglesRendered;
......@@ -51,31 +24,38 @@ namespace URasterizer
public OnRasterizerStatUpdate StatDelegate;
//优化GC
Vector4[] _tmpVector4s = new Vector4[3];
Vector3[] _tmpVector3s = new Vector3[3];
//Compute shader
ComputeShader computeShader;
int kernelClearFrame;
int kernelVertexProcess;
int kernelTriangleSetup;
int kernelRasterizeTriangle;
int kernelTriangleProcess;
//ids of compute shader variables
int frameColorTextureId;
//ids of compute shader variables
int vertexBufferId;
int normalBufferId;
int vertexOutBufferId;
int uvBufferId;
int triangleBufferId;
int renderTriangleBufferId;
int vertexOutBufferId;
int frameColorTextureId;
int frameDepthTextureId;
int clearColorId;
int matMVPId;
int matModelId;
int frameBufferSizeId;
int worldSpaceCameraPosId;
int worldSpaceLightDirId;
int lightColorId;
int ambientColorId;
public String Name { get=>"GPU"; }
int meshTextureId;
public Texture ColorTexture { get=>_colorTexture; }
public String Name { get=>"GPU Driven"; }
public Texture ColorTexture {
get => _colorTexture;
}
public GPURasterizer(int w, int h, RenderingConfig config)
......@@ -87,32 +67,41 @@ namespace URasterizer
_width = w;
_height = h;
frame_buf = new Color[w * h];
depth_buf = new float[w * h];
temp_buf = new Color[w * h];
_colorTexture = new RenderTexture(w, h, 0);
_colorTexture.enableRandomWrite = true;
_colorTexture.Create();
_colorTexture.filterMode = FilterMode.Point;
_depthTexture = new RenderTexture(w, h, 0, RenderTextureFormat.RFloat);
_depthTexture.enableRandomWrite = true;
_depthTexture.Create();
_depthTexture.filterMode = FilterMode.Point;
//init for compute shader
computeShader = config.ComputeShader;
kernelClearFrame = computeShader.FindKernel("ClearFrame");
kernelVertexProcess = computeShader.FindKernel("VertexProcess");
kernelTriangleSetup = computeShader.FindKernel("TriangleSetup");
kernelRasterizeTriangle = computeShader.FindKernel("RasterizeTriangle");
frameColorTextureId = Shader.PropertyToID("frameColorTexture");
kernelTriangleProcess = computeShader.FindKernel("TriangleProcess");
vertexBufferId = Shader.PropertyToID("vertexBuffer");
normalBufferId = Shader.PropertyToID("normalBuffer");
uvBufferId = Shader.PropertyToID("uvBuffer");
triangleBufferId = Shader.PropertyToID("triangleBuffer");
vertexOutBufferId = Shader.PropertyToID("vertexOutBuffer");
triangleBufferId = Shader.PropertyToID("triangleBuffer");
renderTriangleBufferId = Shader.PropertyToID("renderTriangleBuffer");
frameColorTextureId = Shader.PropertyToID("frameColorTexture");
frameDepthTextureId = Shader.PropertyToID("frameDepthTexture");
clearColorId = Shader.PropertyToID("clearColor");
matMVPId = Shader.PropertyToID("matMVP");
matModelId = Shader.PropertyToID("matModel");
frameBufferSizeId = Shader.PropertyToID("frameBufferSize");
worldSpaceCameraPosId = Shader.PropertyToID("worldSpaceCameraPos");
worldSpaceLightDirId = Shader.PropertyToID("worldSpaceLightDir");
lightColorId = Shader.PropertyToID("lightColor");
ambientColorId = Shader.PropertyToID("ambientColor");
meshTextureId = Shader.PropertyToID("meshTexture");
}
......@@ -126,65 +115,59 @@ namespace URasterizer
public void Clear(BufferMask mask)
{
ProfileManager.BeginSample("Rasterizer.Clear GPU");
ProfileManager.BeginSample("GPURasterizer.Clear");
var shader = _config.ComputeShader;
shader.SetTexture(kernelClearFrame, frameColorTextureId, _colorTexture);
shader.SetTexture(kernelClearFrame, frameDepthTextureId, _depthTexture);
var clearColor = _config.ClearColor;
shader.SetFloats("ClearColor", clearColor.r, clearColor.g, clearColor.b, clearColor.a);
shader.SetFloats(clearColorId, clearColor.r, clearColor.g, clearColor.b, clearColor.a);
int groupX = Mathf.CeilToInt(_colorTexture.width/32f);
int groupY = Mathf.CeilToInt(_colorTexture.height/24f);
groupX = groupX==0? 1 : groupX;
groupY = groupY==0? 1 : groupY;
int groupY = Mathf.CeilToInt(_colorTexture.height/24f);
shader.Dispatch(kernelClearFrame, groupX, groupY, 1);
_trianglesAll = _trianglesRendered = 0;
_verticesAll = 0;
ProfileManager.EndSample();
}
}
public void SetupViewProjectionMatrix(Camera camera)
public void SetupUniforms(Camera camera, Light mainLight)
{
//左手坐标系转右手坐标系,以下坐标和向量z取反
var shader = _config.ComputeShader;
var camPos = camera.transform.position;
camPos.z *= -1;
var lookAt = camera.transform.forward;
lookAt.z *= -1;
var up = camera.transform.up;
up.z *= -1;
camPos.z *= -1;
shader.SetFloats(worldSpaceCameraPosId, camPos.x, camPos.y, camPos.z);
var lightDir = mainLight.transform.forward;
lightDir.z *= -1;
shader.SetFloats(worldSpaceLightDirId, -lightDir.x, -lightDir.y, -lightDir.z);
var lightColor = mainLight.color * mainLight.intensity;
shader.SetFloats(lightColorId, lightColor.r, lightColor.g, lightColor.b, lightColor.a);
ViewMatrix = TransformTool.GetViewMatrix(camPos, lookAt, up);
shader.SetFloats(ambientColorId, _config.AmbientColor.r, _config.AmbientColor.g, _config.AmbientColor.b, _config.AmbientColor.a);
if (camera.orthographic)
{
float halfOrthHeight = camera.orthographicSize;
float halfOrthWidth = halfOrthHeight * Aspect;
float f = -camera.farClipPlane;
float n = -camera.nearClipPlane;
ProjectionMatrix = TransformTool.GetOrthographicProjectionMatrix(-halfOrthWidth, halfOrthWidth, -halfOrthHeight, halfOrthHeight, f, n);
}
else
{
ProjectionMatrix = TransformTool.GetPerspectiveProjectionMatrix(camera.fieldOfView, Aspect, camera.nearClipPlane, camera.farClipPlane);
}
TransformTool.SetupViewProjectionMatrix(camera, Aspect, out _matView, out _matProjection);
}
public void Draw(RenderingObject ro, Camera camera)
public void DrawObject(RenderingObject ro)
{
ProfileManager.BeginSample("Rasterizer.Draw");
Mesh mesh = ro.mesh;
ProfileManager.BeginSample("GPURasterizer.Draw");
SetupViewProjectionMatrix(camera);
Mesh mesh = ro.mesh;
ModelMatrix = ro.GetModelMatrix();
_matModel = ro.GetModelMatrix();
Matrix4x4 mvp = _matProjection * _matView * _matModel;
Matrix4x4 normalMat = _matModel.inverse.transpose;
int triangleCount = ro.MeshTriangles.Length / 3;
_verticesAll += mesh.vertexCount;
_trianglesAll += ro.MeshTriangles.Length / 3;
_trianglesAll += triangleCount;
ProfileManager.BeginSample("GPURasterizer.VertexProcess");
......@@ -193,267 +176,36 @@ namespace URasterizer
shader.SetMatrix(matModelId, _matModel);
shader.SetBuffer(kernelVertexProcess, vertexBufferId, ro.VertexBuffer);
shader.SetBuffer(kernelVertexProcess, normalBufferId, ro.NormalBuffer);
shader.SetBuffer(kernelVertexProcess, uvBufferId, ro.UVBuffer);
shader.SetBuffer(kernelVertexProcess, vertexOutBufferId, ro.VertexOutBuffer);
int groupCnt = Mathf.CeilToInt(mesh.vertexCount/768f);
groupCnt = groupCnt==0? 1: groupCnt;
int groupCnt = Mathf.CeilToInt(mesh.vertexCount/512f);
shader.Dispatch(kernelVertexProcess, groupCnt, 1, 1);
ProfileManager.EndSample();
ProfileManager.BeginSample("GPURasterizer.TriangleSetup");
shader.SetInts("FrameBufferSize", _colorTexture.width, _colorTexture.height);
ro.RenderTriangleBuffer.SetCounterValue(0);
shader.SetBuffer(kernelTriangleSetup, triangleBufferId, ro.TriangleBuffer);
shader.SetBuffer(kernelTriangleSetup, renderTriangleBufferId, ro.RenderTriangleBuffer);
shader.SetBuffer(kernelTriangleSetup, vertexOutBufferId, ro.VertexOutBuffer);
ProfileManager.BeginSample("GPURasterizer.TriangleProcess");
groupCnt = Mathf.CeilToInt((ro.MeshTriangles.Length/3)/768f);
groupCnt = groupCnt==0? 1: groupCnt;
shader.Dispatch(kernelTriangleSetup, groupCnt, 1, 1);
ComputeBuffer tmpBuf = new ComputeBuffer(1, sizeof(uint), ComputeBufferType.IndirectArguments);
shader.SetInts(frameBufferSizeId, _colorTexture.width, _colorTexture.height);
shader.SetBuffer(kernelTriangleProcess, triangleBufferId, ro.TriangleBuffer);
shader.SetBuffer(kernelTriangleProcess, vertexOutBufferId, ro.VertexOutBuffer);
shader.SetTexture(kernelTriangleProcess, frameColorTextureId, _colorTexture);
shader.SetTexture(kernelTriangleProcess, frameDepthTextureId, _depthTexture);
shader.SetTexture(kernelTriangleProcess, meshTextureId, ro.texture);
ComputeBuffer.CopyCount(ro.RenderTriangleBuffer, tmpBuf, 0);
uint[] tmpData = new uint[1];
tmpBuf.GetData(tmpData);
_trianglesRendered = (int)tmpData[0];
tmpBuf.Release();
groupCnt = Mathf.CeilToInt(triangleCount/512f);
shader.Dispatch(kernelTriangleProcess, groupCnt, 1, 1);
ProfileManager.EndSample();
//对每个triangle进行光栅化
for(int i=0; i < _trianglesRendered; ++i){
shader.SetBuffer(kernelRasterizeTriangle, "renderCosumeBuffer", ro.RenderTriangleBuffer);
shader.SetBuffer(kernelRasterizeTriangle, vertexOutBufferId, ro.VertexOutBuffer);
shader.SetTexture(kernelRasterizeTriangle, frameColorTextureId, _colorTexture);
int groupX = Mathf.CeilToInt(_colorTexture.width/32f);
int groupY = Mathf.CeilToInt(_colorTexture.height/24f);
groupX = groupX==0? 1 : groupX;
groupY = groupY==0? 1 : groupY;
shader.Dispatch(kernelRasterizeTriangle, groupX, groupY, 1);
}
//Resolve AA
if(_config.MSAA != MSAALevel.Disabled && !_config.WireframeMode)
{
int MSAALevel = (int)_config.MSAA;
int SamplersPerPixel = MSAALevel * MSAALevel;
// for (int y=0; y < _height; ++y)
// {
// for(int x=0; x < _width; ++x)
// {
// int index = GetIndex(x, y);
// Color color = Color.clear;
// float a = 0.0f;
// for(int si=0; si < MSAALevel; ++si)
// {
// for(int sj=0; sj < MSAALevel; ++sj)
// {
// int xi = x * MSAALevel + si;
// int yi = y * MSAALevel + sj;
// int indexSamper = yi * _width * MSAALevel + xi;
// if (samplers_mask_MSAA[indexSamper])
// {
// color += samplers_color_MSAA[indexSamper];
// a += 1.0f;
// }
// }
// }
// if(a > 0.0f)
// {
// frame_buf[index] = color / SamplersPerPixel;
// }
// }
// }
}
ProfileManager.EndSample();
}
//Screen space rasterization
void RasterizeTriangle(Triangle t, RenderingObject ro)
{
ProfileManager.BeginSample("Rasterizer.RasterizeTriangle");
var v = _tmpVector4s;
v[0] = t.Vertex0.Position;
v[1] = t.Vertex1.Position;
v[2] = t.Vertex2.Position;
//Find out the bounding box of current triangle.
float minX = v[0].x;
float maxX = minX;
float minY = v[0].y;
float maxY = minY;
for(int i=1; i<3; ++i)
{
float x = v[i].x;
if(x < minX)
{
minX = x;
} else if(x > maxX)
{
maxX = x;
}
float y = v[i].y;
if(y < minY)
{
minY = y;
}else if(y > maxY)
{
maxY = y;
}
}
int minPX = Mathf.FloorToInt(minX);
minPX = minPX < 0 ? 0 : minPX;
int maxPX = Mathf.CeilToInt(maxX);
maxPX = maxPX > _width ? _width : maxPX;
int minPY = Mathf.FloorToInt(minY);
minPY = minPY < 0 ? 0 : minPY;
int maxPY = Mathf.CeilToInt(maxY);
maxPY = maxPY > _height ? _height : maxPY;
if(_config.MSAA == MSAALevel.Disabled)
{
// 遍历当前三角形包围中的所有像素,判断当前像素是否在三角形中
// 对于在三角形中的像素,使用重心坐标插值得到深度值,并使用z buffer进行深度测试和写入
for(int y = minPY; y < maxPY; ++y)
{
for(int x = minPX; x < maxPX; ++x)
{
//if(IsInsideTriangle(x, y, t)) //-->检测是否在三角形内比使用重心坐标检测要慢,因此先计算重心坐标,再检查3个坐标是否有小于0
{
//计算重心坐标
var c = ComputeBarycentric2D(x, y, t);
float alpha = c.x;
float beta = c.y;
float gamma = c.z;
if(alpha < 0 || beta < 0 || gamma < 0){
continue;
}
//透视校正插值,z为透视校正插值后的view space z值
float z = 1.0f / (alpha / v[0].w + beta / v[1].w + gamma / v[2].w);
//zp为透视校正插值后的screen space z值
float zp = (alpha * v[0].z / v[0].w + beta * v[1].z / v[1].w + gamma * v[2].z / v[2].w) * z;
ProfileManager.EndSample();
//深度测试(注意我们这儿的z值越大越靠近near plane,因此大值通过测试)
int index = GetIndex(x, y);
if(zp >= depth_buf[index])
{
depth_buf[index] = zp;
//透视校正插值
ProfileManager.BeginSample("Rasterizer.RasterizeTriangle.AttributeInterpolation");
Color color_p = (alpha * t.Vertex0.Color / v[0].w + beta * t.Vertex1.Color / v[1].w + gamma * t.Vertex2.Color / v[2].w) * z;
Vector2 uv_p = (alpha * t.Vertex0.Texcoord / v[0].w + beta * t.Vertex1.Texcoord / v[1].w + gamma * t.Vertex2.Texcoord / v[2].w) * z;
Vector3 normal_p = (alpha * t.Vertex0.Normal / v[0].w + beta * t.Vertex1.Normal / v[1].w + gamma * t.Vertex2.Normal / v[2].w) * z;
Vector3 worldPos_p = (alpha * t.Vertex0.WorldPos / v[0].w + beta * t.Vertex1.WorldPos / v[1].w + gamma * t.Vertex2.WorldPos / v[2].w) * z;
Vector3 worldNormal_p = (alpha * t.Vertex0.WorldNormal / v[0].w + beta * t.Vertex1.WorldNormal / v[1].w + gamma * t.Vertex2.WorldNormal / v[2].w) * z;
ProfileManager.EndSample();
if (CurrentFragmentShader != null)
{
FragmentShaderInputData input = new FragmentShaderInputData();
input.Color = color_p;
input.UV = uv_p;
input.Texture = ro.texture;
input.LocalNormal = normal_p;
input.WorldPos = worldPos_p;
input.WorldNormal = worldNormal_p;
ProfileManager.BeginSample("Rasterizer.RasterizeTriangle.FragmentShader");
frame_buf[index] = CurrentFragmentShader(input);
ProfileManager.EndSample();
}
}
}
}
}
}
ProfileManager.EndSample();
}
Vector3 ComputeBarycentric2D(float x, float y, Triangle t)
{
ProfileManager.BeginSample("Rasterizer.ComputeBarycentric2D");
var v = _tmpVector4s;
v[0] = t.Vertex0.Position;
v[1] = t.Vertex1.Position;
v[2] = t.Vertex2.Position;
float c1 = (x * (v[1].y - v[2].y) + (v[2].x - v[1].x) * y + v[1].x * v[2].y - v[2].x * v[1].y) / (v[0].x * (v[1].y - v[2].y) + (v[2].x - v[1].x) * v[0].y + v[1].x * v[2].y - v[2].x * v[1].y);
float c2 = (x * (v[2].y - v[0].y) + (v[0].x - v[2].x) * y + v[2].x * v[0].y - v[0].x * v[2].y) / (v[1].x * (v[2].y - v[0].y) + (v[0].x - v[2].x) * v[1].y + v[2].x * v[0].y - v[0].x * v[2].y);
float c3 = (x * (v[0].y - v[1].y) + (v[1].x - v[0].x) * y + v[0].x * v[1].y - v[1].x * v[0].y) / (v[2].x * (v[0].y - v[1].y) + (v[1].x - v[0].x) * v[2].y + v[0].x * v[1].y - v[1].x * v[0].y);
ProfileManager.EndSample();
return new Vector3(c1, c2, c3);
}
public int GetIndex(int x, int y)
{
return y * _width + x;
}
}
public void UpdateFrame()
{
ProfileManager.BeginSample("CameraRenderer.UpdateFrame");
// switch (_config.DisplayBuffer)
// {
// case DisplayBufferType.Color:
// texture.SetPixels(frame_buf);
// break;
// case DisplayBufferType.DepthRed:
// case DisplayBufferType.DepthGray:
// for (int i = 0; i < depth_buf.Length; ++i)
// {
// //depth_buf中的值范围是[0,1],且最近处为1,最远处为0。因此可视化后背景是黑色
// float c = depth_buf[i];
// if(_config.DisplayBuffer == DisplayBufferType.DepthRed)
// {
// temp_buf[i] = new Color(c, 0, 0);
// }
// else
// {
// temp_buf[i] = new Color(c, c, c);
// }
// }
// texture.SetPixels(temp_buf);
// break;
// }
// texture.Apply();
{
if (StatDelegate != null)
{
StatDelegate(_verticesAll, _trianglesAll, _trianglesRendered);
}
ProfileManager.EndSample();
}
}
......
......@@ -6,12 +6,13 @@ namespace URasterizer
{
string Name { get; }
void Clear(BufferMask mask);
void Draw(RenderingObject ro, Camera camera);
Texture ColorTexture { get; }
void SetupUniforms(Camera camera, Light mainLight);
void DrawObject(RenderingObject ro);
void UpdateFrame();
Texture ColorTexture { get; }
FragmentShader CurrentFragmentShader { get; set; }
void UpdateFrame();
}
}
\ No newline at end of file
......@@ -6,23 +6,24 @@ namespace URasterizer {
[CreateAssetMenu(menuName = "URasterizer/RenderingConfig")]
public class RenderingConfig : ScriptableObject
{
[Header("Common Setting")]
public bool EnableRendering = true;
public Color ClearColor = Color.black;
public Color AmbientColor = Color.black;
public RasterizerType RasterizerType;
[Header("CPU Rasterizer ONLY Setting")]
public bool WireframeMode = false;
public bool BackfaceCulling = true;
public DisplayBufferType DisplayBuffer = DisplayBufferType.Color;
public MSAALevel MSAA = MSAALevel.Disabled;
public bool BilinearSample = true;
public ShaderType FragmentShaderType = ShaderType.BlinnPhong;
public Color AmbientColor = Color.black;
[Header("Vertex Color Setting")]
public VertexColors VertexColors;
[Header("GPU Driven")]
public ComputeShader ComputeShader;
[Header("Current Rasterizer")]
public RasterizerType RasterizerType;
[Header("GPU Driven Setting")]
public ComputeShader ComputeShader;
}
public enum DisplayBufferType
......
......@@ -10,6 +10,7 @@ namespace URasterizer
[HideInInspector, System.NonSerialized]
public Texture2D texture;
#region CPU Rasterizer Use
//缓存避免在draw loop中从mesh copy
[HideInInspector, System.NonSerialized]
public Vector3[] MeshVertices;
......@@ -21,14 +22,17 @@ namespace URasterizer
public Vector2[] MeshUVs;
[HideInInspector, System.NonSerialized]
public VSOutBuf[] vsOutputBuffer;
#endregion
#region GPU Rasterizer Use
public ComputeBuffer VertexBuffer;
public ComputeBuffer NormalBuffer;
public ComputeBuffer UVBuffer;
public ComputeBuffer TriangleBuffer;
public ComputeBuffer VertexOutBuffer;
public ComputeBuffer VertexOutBuffer; //for vertex shader output
public ComputeBuffer RenderTriangleBuffer;
#endregion
private void Start()
{
......@@ -43,7 +47,11 @@ namespace URasterizer
{
texture = meshRenderer.sharedMaterial.mainTexture as Texture2D;
}
if(texture==null){
texture = Texture2D.whiteTexture;
}
//CPU Rasterizer使用的模型数据缓存
MeshVertices = mesh.vertices;
MeshNormals = mesh.normals;
MeshTriangles = mesh.triangles;
......@@ -57,23 +65,25 @@ namespace URasterizer
NormalBuffer = new ComputeBuffer(vertexCnt, 3*sizeof(float));
NormalBuffer.SetData(MeshNormals);
UVBuffer = new ComputeBuffer(vertexCnt, 2*sizeof(float));
UVBuffer.SetData(MeshUVs);
//初始化三角形数组,每个三角形包含3个索引值
//注意这儿对调了v0和v1的索引,因为原来的 0,1,2是顺时针的,对调后是 1,0,2是逆时针的
//Unity Quard模型的两个三角形索引分别是 0,3,1,3,0,2 转换后为 3,0,1,0,3,2
int idxCnt = MeshTriangles.Length;
Vector3Int[] triangles = new Vector3Int[idxCnt/3];
for(int i=0; i < triangles.Length; ++i){
triangles[i].x = MeshTriangles[i*3+1];
triangles[i].y = MeshTriangles[i*3];
triangles[i].z = MeshTriangles[i*3+2];
int triCnt = MeshTriangles.Length/3;
Vector3Int[] triangles = new Vector3Int[triCnt];
for(int i=0; i < triCnt; ++i){
int j = i * 3;
triangles[i].x = MeshTriangles[j+1];
triangles[i].y = MeshTriangles[j];
triangles[i].z = MeshTriangles[j+2];
}
TriangleBuffer = new ComputeBuffer(triangles.Length, 3*sizeof(uint));
TriangleBuffer.SetData(triangles);
VertexOutBuffer = new ComputeBuffer(vertexCnt, 13*sizeof(float));
RenderTriangleBuffer = new ComputeBuffer(MeshTriangles.Length/3, sizeof(uint)*3, ComputeBufferType.Append);
VertexOutBuffer = new ComputeBuffer(vertexCnt, 15*sizeof(float));
}
void OnDestroy()
......@@ -82,12 +92,12 @@ namespace URasterizer
VertexBuffer = null;
NormalBuffer.Release();
NormalBuffer = null;
VertexOutBuffer.Release();
VertexOutBuffer = null;
UVBuffer.Release();
UVBuffer = null;
TriangleBuffer.Release();
TriangleBuffer = null;
RenderTriangleBuffer.Release();
RenderTriangleBuffer = null;
VertexOutBuffer.Release();
VertexOutBuffer = null;
}
......
......@@ -144,6 +144,32 @@ namespace URasterizer
float f = -zFar;
return GetPerspectiveProjectionMatrix(l, r, b, t, f, n);
}
public static void SetupViewProjectionMatrix(Camera camera, float aspect, out Matrix4x4 ViewMatrix, out Matrix4x4 ProjectionMatrix)
{
//左手坐标系转右手坐标系,以下坐标和向量z取反
var camPos = camera.transform.position;
camPos.z *= -1;
var lookAt = camera.transform.forward;
lookAt.z *= -1;
var up = camera.transform.up;
up.z *= -1;
ViewMatrix = TransformTool.GetViewMatrix(camPos, lookAt, up);
if (camera.orthographic)
{
float halfOrthHeight = camera.orthographicSize;
float halfOrthWidth = halfOrthHeight * aspect;
float f = -camera.farClipPlane;
float n = -camera.nearClipPlane;
ProjectionMatrix = GetOrthographicProjectionMatrix(-halfOrthWidth, halfOrthWidth, -halfOrthHeight, halfOrthHeight, f, n);
}
else
{
ProjectionMatrix = GetPerspectiveProjectionMatrix(camera.fieldOfView, aspect, camera.nearClipPlane, camera.farClipPlane);
}
}
}
}
\ No newline at end of file
......@@ -138,7 +138,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.36073107, g: 0, b: 0.98039216, a: 1}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
......
#pragma kernel VertexProcess
#pragma kernel ClearFrame
#pragma kernel TriangleSetup
#pragma kernel RasterizeTriangle
struct VertexOutBuf
{
float4 clipPos;
float3 worldPos;
float3 objectNormal;
float3 worldNormal;
};
float4 ClearColor;
uint2 FrameBufferSize;
float4x4 matMVP;
float4x4 matModel;
uint currentRenderTriangle;
StructuredBuffer<float3> vertexBuffer;
StructuredBuffer<float3> normalBuffer;
RWStructuredBuffer<VertexOutBuf> vertexOutBuffer;
StructuredBuffer<uint3> triangleBuffer; // All triangles of the mesh
AppendStructuredBuffer<uint3> renderTriangleBuffer; //triangles to render
ConsumeStructuredBuffer<uint3> renderCosumeBuffer;
RWTexture2D<float4> frameColorTexture;
[numthreads(32,24,1)]
void ClearFrame(uint3 id : SV_DispatchThreadID)
{
frameColorTexture[id.xy] = ClearColor;
}
[numthreads(768,1,1)]
void VertexProcess (uint3 id : SV_DispatchThreadID)
{
float4 pos = float4(vertexBuffer[id.x].x, vertexBuffer[id.x].y, -vertexBuffer[id.x].z, 1.0f);
float3 normal = float3(normalBuffer[id.x].x, normalBuffer[id.x].y, -normalBuffer[id.x].z);
vertexOutBuffer[id.x].clipPos = mul(matMVP, pos);
vertexOutBuffer[id.x].worldPos = mul(matModel, pos).xyz;
vertexOutBuffer[id.x].objectNormal = normal;
vertexOutBuffer[id.x].worldNormal = mul( (float3x3)matModel , normal);
}
bool Clipped(float4 v[3])
{
//Clip space使用GAMES101规范,右手坐标系,n为+1, f为-1
//裁剪(仅整体剔除)
for (int i = 0; i < 3; ++i)
{
float4 vertex = v[i];
float w = vertex.w;
w = w >= 0 ? w : -w; //由于NDC中总是满足-1<=Zndc<=1, 而当 w < 0 时,-w >= Zclip = Zndc*w >= w。所以此时clip space的坐标范围是[w,-w], 为了比较时更明确,将w取正
bool inside = (vertex.x <= w && vertex.x >= -w
&& vertex.y <= w && vertex.y >= -w
&& vertex.z <= w && vertex.z >= -w);
if (inside)
{
//不裁剪三角形,只要有任意一点在clip space中则三角形整体保留
return false;
}
}
//三个顶点都不在三角形中则剔除
return true;
}
[numthreads(768,1,1)]
void TriangleSetup(uint3 id : SV_DispatchThreadID)
{
uint3 tri = triangleBuffer[id.x];
int idx0 = tri.x;
int idx1 = tri.y;
int idx2 = tri.z;
float4 v[3];
v[0] = vertexOutBuffer[idx0].clipPos;
v[1] = vertexOutBuffer[idx1].clipPos;
v[2] = vertexOutBuffer[idx2].clipPos;
if(Clipped(v)){
return;
}
//Perspective division, clip space to NDC
for (int k=0; k<3; k++)
{
v[k].x /= v[k].w;
v[k].y /= v[k].w;
v[k].z /= v[k].w;
}
//backface culling
float3 e01 = v[1].xyz - v[0].xyz;
float3 e02 = v[2].xyz - v[0].xyz;
float3 crossv = cross(e01, e02);
if (crossv.z < 0)
{
return;
}
//Viewport Transform, NDC to screen space
for (k = 0; k < 3; k++)
{
float4 vec = v[k];
vec.x = 0.5f * FrameBufferSize.x * (vec.x + 1.0f);
vec.y = 0.5f * FrameBufferSize.y * (vec.y + 1.0f);
//在硬件渲染中,NDC的z值经过硬件的透视除法之后就直接写入到depth buffer了,如果要调整需要在投影矩阵中调整
//由于我们是软件渲染,所以可以在这里调整z值。
//GAMES101约定的NDC是右手坐标系,z值范围是[-1,1],但n为1,f为-1,因此值越大越靠近n。
//为了可视化Depth buffer,将最终的z值从[-1,1]映射到[0,1]的范围,因此最终n为1, f为0。离n越近,深度值越大。
//由于远处的z值为0,因此clear时深度要清除为0,然后深度测试时,使用GREATER测试。
//(当然我们也可以在这儿反转z值,然后clear时使用float.MaxValue清除,并且深度测试时使用LESS_EQUAL测试)
//注意:这儿的z值调整并不是必要的,只是为了可视化时便于映射为颜色值。其实也可以在可视化的地方调整。
//但是这么调整后,正好和Unity在DirectX平台的Reverse z一样,让near plane附近的z值的浮点数精度提高。
vec.z = vec.z * 0.5f + 0.5f;
v[k] = vec;
}
//Screen space coordinates saved in clip pos
vertexOutBuffer[idx0].clipPos = v[0];
vertexOutBuffer[idx1].clipPos = v[1];
vertexOutBuffer[idx2].clipPos = v[2];
//triangle actually rendering append to this buffer
renderTriangleBuffer.Append(uint3(idx0, idx1, idx2));
}
float3 ComputeBarycentric2D(float x, float y, float4 v[3])
{
float c1 = (x * (v[1].y - v[2].y) + (v[2].x - v[1].x) * y + v[1].x * v[2].y - v[2].x * v[1].y) / (v[0].x * (v[1].y - v[2].y) + (v[2].x - v[1].x) * v[0].y + v[1].x * v[2].y - v[2].x * v[1].y);
float c2 = (x * (v[2].y - v[0].y) + (v[0].x - v[2].x) * y + v[2].x * v[0].y - v[0].x * v[2].y) / (v[1].x * (v[2].y - v[0].y) + (v[0].x - v[2].x) * v[1].y + v[2].x * v[0].y - v[0].x * v[2].y);
float c3 = (x * (v[0].y - v[1].y) + (v[1].x - v[0].x) * y + v[0].x * v[1].y - v[1].x * v[0].y) / (v[2].x * (v[0].y - v[1].y) + (v[1].x - v[0].x) * v[2].y + v[0].x * v[1].y - v[1].x * v[0].y);
return float3(c1, c2, c3);
}
[numthreads(32,24,1)]
void RasterizeTriangle(uint3 id : SV_DispatchThreadID)
{
uint3 tri = renderCosumeBuffer.Consume();// triangleBuffer[currentRenderTriangle]; //triangleBuffer
int idx0 = tri.x;
int idx1 = tri.y;
int idx2 = tri.z;
float4 v[3];
v[0] = vertexOutBuffer[idx0].clipPos;
v[1] = vertexOutBuffer[idx1].clipPos;
v[2] = vertexOutBuffer[idx2].clipPos;
//这个函数,每个像素都会执行,最好用一个buffer存所有的需要渲染的三角形的AABB,避免每次都在这儿计算
//Find out the bounding box of current triangle.
float minX = v[0].x;
float maxX = minX;
float minY = v[0].y;
float maxY = minY;
for(int i=1; i<3; ++i)
{
float x = v[i].x;
if(x < minX)
{
minX = x;
} else if(x > maxX)
{
maxX = x;
}
float y = v[i].y;
if(y < minY)
{
minY = y;
}else if(y > maxY)
{
maxY = y;
}
}
int minPX = floor(minX);
minPX = minPX < 0 ? 0 : minPX;
int maxPX = ceil(maxX);
maxPX = maxPX > FrameBufferSize.x ? FrameBufferSize.x : maxPX;
int minPY = floor(minY);
minPY = minPY < 0 ? 0 : minPY;
int maxPY = ceil(maxY);
maxPY = maxPY > FrameBufferSize.y ? FrameBufferSize.y : maxPY;
//判断当前像素是否在AABB中
if(id.x < minPX || id.x > maxPX || id.y < minPY || id.y > maxPY){
return;
}
int x = id.x;
int y = id.y;
//计算重心坐标
float3 c = ComputeBarycentric2D(x, y, v);
float alpha = c.x;
float beta = c.y;
float gamma = c.z;
if(alpha < 0 || beta < 0 || gamma < 0){
return;
}
//透视校正插值,z为透视校正插值后的view space z值
float z = 1.0f / (alpha / v[0].w + beta / v[1].w + gamma / v[2].w);
//zp为透视校正插值后的screen space z值
float zp = (alpha * v[0].z / v[0].w + beta * v[1].z / v[1].w + gamma * v[2].z / v[2].w) * z;
//深度测试(注意我们这儿的z值越大越靠近near plane,因此大值通过测试)
//if(zp >= depth_buf[index])
//depth_buf[index] = zp;
//透视校正插值
//float3 color_p = (alpha * t.Vertex0.Color / v[0].w + beta * t.Vertex1.Color / v[1].w + gamma * t.Vertex2.Color / v[2].w) * z;
//Vector2 uv_p = (alpha * t.Vertex0.Texcoord / v[0].w + beta * t.Vertex1.Texcoord / v[1].w + gamma * t.Vertex2.Texcoord / v[2].w) * z;
//Vector3 normal_p = (alpha * t.Vertex0.Normal / v[0].w + beta * t.Vertex1.Normal / v[1].w + gamma * t.Vertex2.Normal / v[2].w) * z;
//Vector3 worldPos_p = (alpha * t.Vertex0.WorldPos / v[0].w + beta * t.Vertex1.WorldPos / v[1].w + gamma * t.Vertex2.WorldPos / v[2].w) * z;
//Vector3 worldNormal_p = (alpha * t.Vertex0.WorldNormal / v[0].w + beta * t.Vertex1.WorldNormal / v[1].w + gamma * t.Vertex2.WorldNormal / v[2].w) * z;
//if (CurrentFragmentShader != null)
{
//FragmentShaderInputData input = new FragmentShaderInputData();
//input.Color = color_p;
//input.UV = uv_p;
//input.Texture = ro.texture;
//input.LocalNormal = normal_p;
//input.WorldPos = worldPos_p;
//input.WorldNormal = worldNormal_p;
frameColorTexture[id.xy] = float4(1,1,1,1);
}
}
// void RasterizeTriangle(Triangle t, RenderingObject ro)
// {
// ProfileManager.BeginSample("Rasterizer.RasterizeTriangle");
// var v = _tmpVector4s;
// v[0] = t.Vertex0.Position;
// v[1] = t.Vertex1.Position;
// v[2] = t.Vertex2.Position;
// //Find out the bounding box of current triangle.
// float minX = v[0].x;
// float maxX = minX;
// float minY = v[0].y;
// float maxY = minY;
// for(int i=1; i<3; ++i)
// {
// float x = v[i].x;
// if(x < minX)
// {
// minX = x;
// } else if(x > maxX)
// {
// maxX = x;
// }
// float y = v[i].y;
// if(y < minY)
// {
// minY = y;
// }else if(y > maxY)
// {
// maxY = y;
// }
// }
// int minPX = Mathf.FloorToInt(minX);
// minPX = minPX < 0 ? 0 : minPX;
// int maxPX = Mathf.CeilToInt(maxX);
// maxPX = maxPX > _width ? _width : maxPX;
// int minPY = Mathf.FloorToInt(minY);
// minPY = minPY < 0 ? 0 : minPY;
// int maxPY = Mathf.CeilToInt(maxY);
// maxPY = maxPY > _height ? _height : maxPY;
// if(_config.MSAA == MSAALevel.Disabled)
// {
// // 遍历当前三角形包围中的所有像素,判断当前像素是否在三角形中
// // 对于在三角形中的像素,使用重心坐标插值得到深度值,并使用z buffer进行深度测试和写入
// for(int y = minPY; y < maxPY; ++y)
// {
// for(int x = minPX; x < maxPX; ++x)
// {
// //if(IsInsideTriangle(x, y, t)) //-->检测是否在三角形内比使用重心坐标检测要慢,因此先计算重心坐标,再检查3个坐标是否有小于0
// {
// //计算重心坐标
// var c = ComputeBarycentric2D(x, y, t);
// float alpha = c.x;
// float beta = c.y;
// float gamma = c.z;
// if(alpha < 0 || beta < 0 || gamma < 0){
// continue;
// }
// //透视校正插值,z为透视校正插值后的view space z值
// float z = 1.0f / (alpha / v[0].w + beta / v[1].w + gamma / v[2].w);
// //zp为透视校正插值后的screen space z值
// float zp = (alpha * v[0].z / v[0].w + beta * v[1].z / v[1].w + gamma * v[2].z / v[2].w) * z;
// //深度测试(注意我们这儿的z值越大越靠近near plane,因此大值通过测试)
// int index = GetIndex(x, y);
// if(zp >= depth_buf[index])
// {
// depth_buf[index] = zp;
// //透视校正插值
// ProfileManager.BeginSample("Rasterizer.RasterizeTriangle.AttributeInterpolation");
// Color color_p = (alpha * t.Vertex0.Color / v[0].w + beta * t.Vertex1.Color / v[1].w + gamma * t.Vertex2.Color / v[2].w) * z;
// Vector2 uv_p = (alpha * t.Vertex0.Texcoord / v[0].w + beta * t.Vertex1.Texcoord / v[1].w + gamma * t.Vertex2.Texcoord / v[2].w) * z;
// Vector3 normal_p = (alpha * t.Vertex0.Normal / v[0].w + beta * t.Vertex1.Normal / v[1].w + gamma * t.Vertex2.Normal / v[2].w) * z;
// Vector3 worldPos_p = (alpha * t.Vertex0.WorldPos / v[0].w + beta * t.Vertex1.WorldPos / v[1].w + gamma * t.Vertex2.WorldPos / v[2].w) * z;
// Vector3 worldNormal_p = (alpha * t.Vertex0.WorldNormal / v[0].w + beta * t.Vertex1.WorldNormal / v[1].w + gamma * t.Vertex2.WorldNormal / v[2].w) * z;
// ProfileManager.EndSample();
// if (CurrentFragmentShader != null)
// {
// FragmentShaderInputData input = new FragmentShaderInputData();
// input.Color = color_p;
// input.UV = uv_p;
// input.Texture = ro.texture;
// input.LocalNormal = normal_p;
// input.WorldPos = worldPos_p;
// input.WorldNormal = worldNormal_p;
// ProfileManager.BeginSample("Rasterizer.RasterizeTriangle.FragmentShader");
// frame_buf[index] = CurrentFragmentShader(input);
// ProfileManager.EndSample();
// }
// }
// }
// }
// }
// }
// ProfileManager.EndSample();
// }
......@@ -12,14 +12,14 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d5fa123a60a768444af03a384cb34a74, type: 3}
m_Name: RenderingConfig
m_EditorClassIdentifier:
ClearColor: {r: 0.056692798, g: 0.41403675, b: 0.9245283, a: 0.24705882}
ClearColor: {r: 0, g: 0, b: 0, a: 1}
AmbientColor: {r: 0.0754717, g: 0.0754717, b: 0.0754717, a: 1}
RasterizerType: 1
WireframeMode: 0
BackfaceCulling: 1
DisplayBuffer: 0
MSAA: 0
BilinearSample: 1
FragmentShaderType: 1
AmbientColor: {r: 0.0754717, g: 0.075044505, b: 0.075044505, a: 1}
VertexColors: {fileID: 11400000, guid: a126a2fdc8a60c54e8a3aadb7db4bb3a, type: 2}
ComputeShader: {fileID: 7200000, guid: caa96f337395ad9449e1be41546efcd6, type: 3}
RasterizerType: 1
fileFormatVersion: 2
guid: db6144c7af5ba0a43b63a0a8e34a1cad
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
struct VertexOutBuf
{
float4 clipPos;
float3 worldPos;
float3 objectNormal;
float3 worldNormal;
float2 uv;
};
float4 clearColor;
int2 frameBufferSize;
float4x4 matMVP;
float4x4 matModel;
float3 worldSpaceCameraPos;
float3 worldSpaceLightDir;
float4 lightColor;
float4 ambientColor;
StructuredBuffer<float3> vertexBuffer;
StructuredBuffer<float3> normalBuffer;
StructuredBuffer<float2> uvBuffer;
StructuredBuffer<uint3> triangleBuffer; // All triangles of the mesh
RWStructuredBuffer<VertexOutBuf> vertexOutBuffer;
RWTexture2D<float4> frameColorTexture;
RWTexture2D<float> frameDepthTexture;
fileFormatVersion: 2
guid: 252a3b656c0fa814fb91d0ef851fb108
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
#pragma kernel VertexProcess
#pragma kernel ClearFrame
#pragma kernel TriangleProcess
#include "URCommon.hlsl"
#include "URVertexShader.hlsl"
#include "URFragmentShader.hlsl"
#include "URTriangleProcess.hlsl"
[numthreads(32,24,1)]
void ClearFrame(uint3 id : SV_DispatchThreadID)
{
frameColorTexture[id.xy] = clearColor;
frameDepthTexture[id.xy] = 0;
}
[numthreads(512,1,1)]
void VertexProcess (uint3 id : SV_DispatchThreadID)
{
VertexTransform(id.x);
}
[numthreads(512,1,1)]
void TriangleProcess(uint3 id : SV_DispatchThreadID)
{
uint3 tri = triangleBuffer[id.x];
int idx0 = tri.x;
int idx1 = tri.y;
int idx2 = tri.z;
float4 v[3];
v[0] = vertexOutBuffer[idx0].clipPos;
v[1] = vertexOutBuffer[idx1].clipPos;
v[2] = vertexOutBuffer[idx2].clipPos;
if(Clipped(v)){
return;
}
//Perspective division, clip space to NDC
for (int k=0; k<3; k++)
{
v[k].x /= v[k].w;
v[k].y /= v[k].w;
v[k].z /= v[k].w;
}
//backface culling
float3 e01 = v[1].xyz - v[0].xyz;
float3 e02 = v[2].xyz - v[0].xyz;
float3 crossv = cross(e01, e02);
if (crossv.z < 0)
{
return;
}
//Viewport Transform, NDC to screen space
for (k = 0; k < 3; k++)
{
float4 vec = v[k];
vec.x = 0.5f * frameBufferSize.x * (vec.x + 1.0f);
vec.y = 0.5f * frameBufferSize.y * (vec.y + 1.0f);
//在硬件渲染中,NDC的z值经过硬件的透视除法之后就直接写入到depth buffer了,如果要调整需要在投影矩阵中调整
//由于我们是软件渲染,所以可以在这里调整z值。
//GAMES101约定的NDC是右手坐标系,z值范围是[-1,1],但n为1,f为-1,因此值越大越靠近n。
//为了可视化Depth buffer,将最终的z值从[-1,1]映射到[0,1]的范围,因此最终n为1, f为0。离n越近,深度值越大。
//由于远处的z值为0,因此clear时深度要清除为0,然后深度测试时,使用GREATER测试。
//(当然我们也可以在这儿反转z值,然后clear时使用float.MaxValue清除,并且深度测试时使用LESS_EQUAL测试)
//注意:这儿的z值调整并不是必要的,只是为了可视化时便于映射为颜色值。其实也可以在可视化的地方调整。
//但是这么调整后,正好和Unity在DirectX平台的Reverse z一样,让near plane附近的z值的浮点数精度提高。
vec.z = vec.z * 0.5f + 0.5f;
v[k] = vec;
}
RasterizeTriangle(idx0, idx1, idx2, v);
}
Texture2D<float4> meshTexture;
SamplerState samplermeshTexture;
float4 FSBlinnPhong(float3 worldPos, float3 worldNormal, float2 uv)
{
float4 textureColor = meshTexture.SampleLevel(samplermeshTexture, uv, 0); //Compute shader中不能使用Sample
float4 ks = float4(0.7937f, 0.7937f, 0.7937f, 1.0f);
float ndotl = dot(worldNormal, worldSpaceLightDir);
float4 diffuse = textureColor * lightColor * saturate(ndotl);
float3 viewDir = normalize(worldSpaceCameraPos - worldPos);
float3 halfDir = normalize(viewDir + worldSpaceLightDir);
float hdotn = dot(halfDir, worldNormal);
float4 specular = ks * lightColor * pow(saturate(hdotn), 150);
return ambientColor + diffuse + specular;
}
fileFormatVersion: 2
guid: 6abde8a54e513cd42950ae3ee5bb48ec
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
bool Clipped(float4 v[3])
{
//Clip space使用GAMES101规范,右手坐标系,n为+1, f为-1
//裁剪(仅整体剔除)
for (int i = 0; i < 3; ++i)
{
float4 vertex = v[i];
float w = vertex.w;
w = w >= 0 ? w : -w; //由于NDC中总是满足-1<=Zndc<=1, 而当 w < 0 时,-w >= Zclip = Zndc*w >= w。所以此时clip space的坐标范围是[w,-w], 为了比较时更明确,将w取正
bool inside = (vertex.x <= w && vertex.x >= -w
&& vertex.y <= w && vertex.y >= -w
&& vertex.z <= w && vertex.z >= -w);
if (inside)
{
//不裁剪三角形,只要有任意一点在clip space中则三角形整体保留
return false;
}
}
//三个顶点都不在三角形中则剔除
return true;
}
float3 ComputeBarycentric2D(float x, float y, float4 v[3])
{
float c1 = (x * (v[1].y - v[2].y) + (v[2].x - v[1].x) * y + v[1].x * v[2].y - v[2].x * v[1].y) / (v[0].x * (v[1].y - v[2].y) + (v[2].x - v[1].x) * v[0].y + v[1].x * v[2].y - v[2].x * v[1].y);
float c2 = (x * (v[2].y - v[0].y) + (v[0].x - v[2].x) * y + v[2].x * v[0].y - v[0].x * v[2].y) / (v[1].x * (v[2].y - v[0].y) + (v[0].x - v[2].x) * v[1].y + v[2].x * v[0].y - v[0].x * v[2].y);
float c3 = (x * (v[0].y - v[1].y) + (v[1].x - v[0].x) * y + v[0].x * v[1].y - v[1].x * v[0].y) / (v[2].x * (v[0].y - v[1].y) + (v[1].x - v[0].x) * v[2].y + v[0].x * v[1].y - v[1].x * v[0].y);
return float3(c1, c2, c3);
}
//v: screen space vertex coordinates
void RasterizeTriangle(int idx0, int idx1, int idx2, float4 v[3])
{
//Find out the bounding box of current triangle.
float minX = v[0].x;
float maxX = minX;
float minY = v[0].y;
float maxY = minY;
for(int i=1; i<3; ++i)
{
float x = v[i].x;
if(x < minX)
{
minX = x;
} else if(x > maxX)
{
maxX = x;
}
float y = v[i].y;
if(y < minY)
{
minY = y;
}else if(y > maxY)
{
maxY = y;
}
}
int minPX = floor(minX);
minPX = minPX < 0 ? 0 : minPX;
int maxPX = ceil(maxX);
maxPX = maxPX > frameBufferSize.x ? frameBufferSize.x : maxPX;
int minPY = floor(minY);
minPY = minPY < 0 ? 0 : minPY;
int maxPY = ceil(maxY);
maxPY = maxPY > frameBufferSize.y ? frameBufferSize.y : maxPY;
VertexOutBuf vertex0 = vertexOutBuffer[idx0];
VertexOutBuf vertex1 = vertexOutBuffer[idx1];
VertexOutBuf vertex2 = vertexOutBuffer[idx2];
for(int y = minPY; y < maxPY; ++y)
{
for(int x = minPX; x < maxPX; ++x)
{
//计算重心坐标
float3 c = ComputeBarycentric2D(x, y, v);
float alpha = c.x;
float beta = c.y;
float gamma = c.z;
if(alpha < 0 || beta < 0 || gamma < 0){
continue;
}
//透视校正插值,z为透视校正插值后的view space z值
float z = 1.0f / (alpha / v[0].w + beta / v[1].w + gamma / v[2].w);
//zp为透视校正插值后的screen space z值
float zp = (alpha * v[0].z / v[0].w + beta * v[1].z / v[1].w + gamma * v[2].z / v[2].w) * z;
//深度测试(注意我们这儿的z值越大越靠近near plane,因此大值通过测试)
if(zp > frameDepthTexture[uint2(x,y)])
{
frameDepthTexture[uint2(x,y)] = zp;
//透视校正插值
//float3 color_p = (alpha * t.Vertex0.Color / v[0].w + beta * t.Vertex1.Color / v[1].w + gamma * t.Vertex2.Color / v[2].w) * z;
float2 uv_p = (alpha * vertex0.uv / v[0].w + beta * vertex1.uv / v[1].w + gamma * vertex2.uv / v[2].w) * z;
float3 normal_p = (alpha * vertex0.objectNormal / v[0].w + beta * vertex1.objectNormal / v[1].w + gamma * vertex2.objectNormal / v[2].w) * z;
float3 worldPos_p = (alpha * vertex0.worldPos / v[0].w + beta * vertex1.worldPos / v[1].w + gamma * vertex2.worldPos / v[2].w) * z;
float3 worldNormal_p = (alpha * vertex0.worldNormal / v[0].w + beta * vertex1.worldNormal / v[1].w + gamma * vertex2.worldNormal / v[2].w) * z;
frameColorTexture[uint2(x,y)] = FSBlinnPhong(worldPos_p, worldNormal_p, uv_p);
}
}
}
}
fileFormatVersion: 2
guid: 85e2d77fa024824419b563f193a7472e
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
void VertexTransform (uint vertexIdx)
{
float4 pos = float4(vertexBuffer[vertexIdx].x, vertexBuffer[vertexIdx].y, -vertexBuffer[vertexIdx].z, 1.0f);
float3 normal = float3(normalBuffer[vertexIdx].x, normalBuffer[vertexIdx].y, -normalBuffer[vertexIdx].z);
vertexOutBuffer[vertexIdx].clipPos = mul(matMVP, pos);
vertexOutBuffer[vertexIdx].worldPos = mul(matModel, pos).xyz;
vertexOutBuffer[vertexIdx].objectNormal = normal;
vertexOutBuffer[vertexIdx].worldNormal = mul( (float3x3)matModel , normal);
vertexOutBuffer[vertexIdx].uv = uvBuffer[vertexIdx];
}
\ No newline at end of file
fileFormatVersion: 2
guid: 436233d9a8473544e826c6008e7b2e3f
ShaderImporter:
externalObjects: {}
defaultTextures: []
nonModifiableTextures: []
preprocessorOverride: 0
userData:
assetBundleName:
assetBundleVariant:
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册