64bbc700fa
- This rendering technique reduces the memory required per pipeline by 750MB compared to the PPLL technique!! - Using 3 screen buffers representing the closest 3 hair gragments depths. - Going through second geometry pass that disqualify any fragment further than the third depth, the technique blends the three closes shaders hair fragments. - Supports the Marschner lighting model (big change from the original TressFX 4.1 implementation) - The current technique is almost twice the performance of the PPLL but not quite as advacned when come to final visual quality. Remarks: Unlike the PPLL, this technique is still lacking some of the advanced features added to the PPLL such as 1. Back lobe (TT) conseal by depth comparison 2. Thickness dependency in light transfer (mainly TT) 3. Allowing TT transfer for thin separated hair strands (might be supported by default with no distinction) Signed-off-by: Adi-Amazon <Adi Bar-Lev 82479970+Adi-Amazon@users.noreply.github.com> Signed-off-by: Adi-Amazon <Adi Bar-Lev barlev@amazon.com> Signed-off-by: Adi-Amazon <Adi Bar-Lev 82479970+Adi-Amazon@users.noreply.github.com> Signed-off-by: Adi-Amazon <Adi Bar-Lev barlev@amazon.com> Co-authored-by: Adi-Amazon <Adi Bar-Lev 82479970+Adi-Amazon@users.noreply.github.com>
131 lines
4.9 KiB
Plaintext
131 lines
4.9 KiB
Plaintext
/*
|
|
* Modifications Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: (Apache-2.0 OR MIT) AND MIT
|
|
*
|
|
*/
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
// Shader code utilities for TressFX
|
|
//-------------------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
//
|
|
// Cutoff to not render hair
|
|
|
|
#pragma once
|
|
|
|
#define SHORTCUT_MIN_ALPHA 0.02
|
|
|
|
#define TRESSFX_FLOAT_EPSILON 1e-7
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
//
|
|
// Controls whether you do mul(M,v) or mul(v,M)
|
|
// i.e., row major vs column major
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
float4 MatrixMult(float4x4 m, float4 v)
|
|
{
|
|
return mul(m, v);
|
|
}
|
|
|
|
// Pack a float4 into an uint
|
|
uint PackFloat4IntoUint(float4 vValue)
|
|
{
|
|
return (((uint)(vValue.x * 255)) << 24) | (((uint)(vValue.y * 255)) << 16) | (((uint)(vValue.z * 255)) << 8) | (uint)(vValue.w * 255);
|
|
}
|
|
|
|
// Unpack a uint into a float4 value
|
|
float4 UnpackUintIntoFloat4(uint uValue)
|
|
{
|
|
return float4(((uValue & 0xFF000000) >> 24) / 255.0, ((uValue & 0x00FF0000) >> 16) / 255.0, ((uValue & 0x0000FF00) >> 8) / 255.0, ((uValue & 0x000000FF)) / 255.0);
|
|
}
|
|
|
|
// Pack a float3 and a uint8 into an uint
|
|
uint PackFloat3ByteIntoUint(float3 vValue, uint uByteValue)
|
|
{
|
|
return (((uint)(vValue.x * 255)) << 24) | (((uint)(vValue.y * 255)) << 16) | (((uint)(vValue.z * 255)) << 8) | uByteValue;
|
|
}
|
|
|
|
// Unpack a uint into a float3 and a uint8 value
|
|
float3 UnpackUintIntoFloat3Byte(uint uValue, out uint uByteValue)
|
|
{
|
|
uByteValue = uValue & 0x000000FF;
|
|
return float3(((uValue & 0xFF000000) >> 24) / 255.0, ((uValue & 0x00FF0000) >> 16) / 255.0, ((uValue & 0x0000FF00) >> 8) / 255.0);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
//
|
|
// Safe_normalize-float2
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
float2 Safe_normalize(float2 vec)
|
|
{
|
|
float len = length(vec);
|
|
return len >= TRESSFX_FLOAT_EPSILON ? (vec * rcp(len)) : float2(0, 0);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
//
|
|
// Safe_normalize-float3
|
|
//
|
|
//--------------------------------------------------------------------------------------
|
|
float3 Safe_normalize(float3 vec)
|
|
{
|
|
float len = length(vec);
|
|
return len >= TRESSFX_FLOAT_EPSILON ? (vec * rcp(len)) : float3(0, 0, 0);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// ComputeCoverage
|
|
//
|
|
// Calculate the pixel coverage of a hair strand by computing the hair width
|
|
//--------------------------------------------------------------------------------------
|
|
float ComputeCoverage(float2 p0, float2 p1, float2 pixelLoc, float2 winSize)
|
|
{
|
|
// p0, p1, pixelLoc are in d3d clip space (-1 to 1)x(-1 to 1)
|
|
|
|
// Scale positions so 1.f = half pixel width
|
|
p0 *= winSize;
|
|
p1 *= winSize;
|
|
pixelLoc *= winSize;
|
|
|
|
float p0dist = length(p0 - pixelLoc);
|
|
float p1dist = length(p1 - pixelLoc);
|
|
float hairWidth = length(p0 - p1);
|
|
|
|
// will be 1.f if pixel outside hair, 0.f if pixel inside hair
|
|
float outside = any(float2(step(hairWidth, p0dist), step(hairWidth, p1dist)));
|
|
|
|
// if outside, set sign to -1, else set sign to 1
|
|
float sign = outside > 0.f ? -1.f : 1.f;
|
|
|
|
// signed distance (positive if inside hair, negative if outside hair)
|
|
float relDist = sign * saturate(min(p0dist, p1dist));
|
|
|
|
// returns coverage based on the relative distance
|
|
// 0, if completely outside hair edge
|
|
// 1, if completely inside hair edge
|
|
return (relDist + 1.f) * 0.5f;
|
|
}
|