mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-12-02 08:00:10 +00:00
78113981e6
These changes update the mtlPtexViewer implementation to match recent changes to the mtlViewer including: - improved shader organization - correct screenspace tessellation - support for common command line arguments and fit to frame
718 lines
26 KiB
Metal
718 lines
26 KiB
Metal
#line 0 "examples/mtlPtexViewer/mtlPtexViewer.metal"
|
|
//
|
|
// Copyright 2013-2019 Pixar
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "Apache License")
|
|
// with the following modification; you may not use this file except in
|
|
// compliance with the Apache License and the following modification to it:
|
|
// Section 6. Trademarks. is deleted and replaced with:
|
|
//
|
|
// 6. Trademarks. This License does not grant permission to use the trade
|
|
// names, trademarks, service marks, or product names of the Licensor
|
|
// and its affiliates, except as required to comply with Section 4(c) of
|
|
// the License and to reproduce the content of the NOTICE file.
|
|
//
|
|
// You may obtain a copy of the Apache License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the Apache License with the above modification is
|
|
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the Apache License for the specific
|
|
// language governing permissions and limitations under the Apache License.
|
|
//
|
|
|
|
#include <metal_stdlib>
|
|
using namespace metal;
|
|
|
|
#if OSD_IS_ADAPTIVE
|
|
static_assert(!OSD_ENABLE_SCREENSPACE_TESSELLATION || !USE_PTVS_FACTORS, "USE_PTVS_FACTORS cannot be enabled if OSD_ENABLE_SCREENSPACE_TESSELLATION is enabled");
|
|
#endif
|
|
|
|
struct Config {
|
|
float displacementScale;
|
|
float mipmapBias;
|
|
};
|
|
|
|
struct PerFrameConstants {
|
|
float4x4 ModelViewMatrix;
|
|
float4x4 ProjectionMatrix;
|
|
float4x4 ModelViewProjectionMatrix;
|
|
float4x4 ModelViewInverseMatrix;
|
|
float TessLevel;
|
|
};
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const constant float4 patchColors[] = {
|
|
float4(1.0f, 1.0f, 1.0f, 1.0f), // regular
|
|
float4(0.0f, 1.0f, 1.0f, 1.0f), // regular pattern 0
|
|
float4(0.0f, 0.5f, 1.0f, 1.0f), // regular pattern 1
|
|
float4(0.0f, 0.5f, 0.5f, 1.0f), // regular pattern 2
|
|
float4(0.5f, 0.0f, 1.0f, 1.0f), // regular pattern 3
|
|
float4(1.0f, 0.5f, 1.0f, 1.0f), // regular pattern 4
|
|
|
|
float4(1.0f, 0.5f, 0.5f, 1.0f), // single crease
|
|
float4(1.0f, 0.70f, 0.6f, 1.0f), // single crease pattern 0
|
|
float4(1.0f, 0.65f, 0.6f, 1.0f), // single crease pattern 1
|
|
float4(1.0f, 0.60f, 0.6f, 1.0f), // single crease pattern 2
|
|
float4(1.0f, 0.55f, 0.6f, 1.0f), // single crease pattern 3
|
|
float4(1.0f, 0.50f, 0.6f, 1.0f), // single crease pattern 4
|
|
|
|
float4(0.8f, 0.0f, 0.0f, 1.0f), // boundary
|
|
float4(0.0f, 0.0f, 0.75f, 1.0f), // boundary pattern 0
|
|
float4(0.0f, 0.2f, 0.75f, 1.0f), // boundary pattern 1
|
|
float4(0.0f, 0.4f, 0.75f, 1.0f), // boundary pattern 2
|
|
float4(0.0f, 0.6f, 0.75f, 1.0f), // boundary pattern 3
|
|
float4(0.0f, 0.8f, 0.75f, 1.0f), // boundary pattern 4
|
|
|
|
float4(0.0f, 1.0f, 0.0f, 1.0f), // corner
|
|
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 0
|
|
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 1
|
|
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 2
|
|
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 3
|
|
float4(0.5f, 1.0f, 0.5f, 1.0f), // corner pattern 4
|
|
|
|
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
|
|
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
|
|
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
|
|
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
|
|
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
|
|
float4(1.0f, 1.0f, 0.0f, 1.0f), // gregory
|
|
|
|
float4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
|
|
float4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
|
|
float4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
|
|
float4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
|
|
float4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
|
|
float4(1.0f, 0.5f, 0.0f, 1.0f), // gregory boundary
|
|
|
|
float4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
|
|
float4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
|
|
float4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
|
|
float4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
|
|
float4(1.0f, 0.7f, 0.3f, 1.0f), // gregory basis
|
|
float4(1.0f, 0.7f, 0.3f, 1.0f) // gregory basis
|
|
};
|
|
|
|
float4
|
|
getAdaptivePatchColor(int3 patchParam, float sharpness)
|
|
{
|
|
int patchType = 0;
|
|
|
|
int edgeCount = popcount(OsdGetPatchBoundaryMask(patchParam));
|
|
if (edgeCount == 1) {
|
|
patchType = 2; // BOUNDARY
|
|
}
|
|
if (edgeCount > 1) {
|
|
patchType = 3; // CORNER
|
|
}
|
|
|
|
#if OSD_PATCH_ENABLE_SINGLE_CREASE
|
|
if (sharpness > 0) {
|
|
patchType = 1;
|
|
}
|
|
#elif OSD_PATCH_GREGORY
|
|
patchType = 4;
|
|
#elif OSD_PATCH_GREGORY_BOUNDARY
|
|
patchType = 5;
|
|
#elif OSD_PATCH_GREGORY_BASIS
|
|
patchType = 6;
|
|
#elif OSD_PATCH_GREGORY_TRIANGLE
|
|
patchType = 6;
|
|
#endif
|
|
|
|
int pattern = popcount(OsdGetPatchTransitionMask(patchParam));
|
|
|
|
return patchColors[6*patchType + pattern];
|
|
}
|
|
|
|
#if DISPLACEMENT_HW_BILINEAR \
|
|
|| DISPLACEMENT_BILINEAR \
|
|
|| DISPLACEMENT_BIQUADRATIC \
|
|
|| NORMAL_HW_SCREENSPACE \
|
|
|| NORMAL_SCREENSPACE \
|
|
|| NORMAL_BIQUADRATIC \
|
|
|| NORMAL_BIQUADRATIC_WG
|
|
#define USE_DISPLACEMENT_RESOURCES 1
|
|
#endif
|
|
|
|
#if DISPLACEMENT_HW_BILINEAR \
|
|
|| DISPLACEMENT_BILINEAR \
|
|
|| DISPLACEMENT_BIQUADRATIC
|
|
|
|
#define USE_DISPLACEMENT 1
|
|
#undef OSD_DISPLACEMENT_CALLBACK
|
|
#define OSD_DISPLACEMENT_CALLBACK \
|
|
|
|
float3 displacement(float3 position, float3 normal, float4 patchCoord, float mipmapBias, float displacementScale
|
|
#if USE_DISPLACEMENT_RESOURCES
|
|
,texture2d_array<float, access::sample> textureDisplace_Data
|
|
,device ushort* textureDisplace_Packing
|
|
#endif
|
|
)
|
|
{
|
|
#if DISPLACEMENT_HW_BILINEAR
|
|
float disp = PtexLookupFast(patchCoord, mipmapBias,
|
|
textureDisplace_Data,
|
|
textureDisplace_Packing).x;
|
|
#elif DISPLACEMENT_BILINEAR
|
|
float disp = PtexMipmapLookup(patchCoord, mipmapBias,
|
|
textureDisplace_Data,
|
|
textureDisplace_Packing).x;
|
|
#elif DISPLACEMENT_BIQUADRATIC
|
|
float disp = PtexMipmapLookupQuadratic(patchCoord, mipmapBias,
|
|
textureDisplace_Data,
|
|
textureDisplace_Packing).x;
|
|
#else
|
|
float disp(0);
|
|
#endif
|
|
return position + disp*normal * displacementScale;
|
|
}
|
|
#endif
|
|
|
|
float4 GeneratePatchCoord(float2 uv, int3 patchParam) // for non-adaptive
|
|
{
|
|
return OsdInterpolatePatchCoord(uv, patchParam);
|
|
}
|
|
|
|
#if NORMAL_HW_SCREENSPACE || NORMAL_SCREENSPACE
|
|
|
|
float3
|
|
perturbNormalFromDisplacement(float3 position, float3 normal, float4 patchCoord, float mipmapBias
|
|
,texture2d_array<float, access::sample> textureDisplace_Data
|
|
,device ushort* textureDisplace_Packing
|
|
,float displacementScale)
|
|
{
|
|
// by Morten S. Mikkelsen
|
|
// http://jbit.net/~sparky/sfgrad_bump/mm_sfgrad_bump.pdf
|
|
// slightly modified for ptex guttering
|
|
float3 vSigmaS = dfdx(position);
|
|
float3 vSigmaT = dfdy(position);
|
|
float3 vN = normal;
|
|
float3 vR1 = cross(vSigmaT, vN);
|
|
float3 vR2 = cross(vN, vSigmaS);
|
|
float fDet = dot(vSigmaS, vR1);
|
|
#if 0
|
|
// not work well with ptex
|
|
float dBs = dfdx(disp);
|
|
float dBt = dfdy(disp);
|
|
#else
|
|
float2 texDx = dfdx(patchCoord.xy);
|
|
float2 texDy = dfdy(patchCoord.xy);
|
|
|
|
// limit forward differencing to the width of ptex gutter
|
|
const float resolution = 128.0;
|
|
float d = min(1.0f, (0.5/resolution)/max(length(texDx), length(texDy)));
|
|
|
|
float4 STll = patchCoord;
|
|
float4 STlr = patchCoord + d * float4(texDx.x, texDx.y, 0, 0);
|
|
float4 STul = patchCoord + d * float4(texDy.x, texDy.y, 0, 0);
|
|
#if NORMAL_HW_SCREENSPACE
|
|
float Hll = PtexLookupFast(STll, textureDisplace_Data, textureDisplace_Packing).x * displacementScale;
|
|
float Hlr = PtexLookupFast(STlr, textureDisplace_Data, textureDisplace_Packing).x * displacementScale;
|
|
float Hul = PtexLookupFast(STul, textureDisplace_Data, textureDisplace_Packing).x * displacementScale;
|
|
#elif NORMAL_SCREENSPACE
|
|
float Hll = PtexMipmapLookup(STll, mipmapBias, textureDisplace_Data, textureDisplace_Packing).x * displacementScale;
|
|
float Hlr = PtexMipmapLookup(STlr, mipmapBias, textureDisplace_Data, textureDisplace_Packing).x * displacementScale;
|
|
float Hul = PtexMipmapLookup(STul, mipmapBias, textureDisplace_Data, textureDisplace_Packing).x * displacementScale;
|
|
#endif
|
|
float dBs = (Hlr - Hll)/d;
|
|
float dBt = (Hul - Hll)/d;
|
|
#endif
|
|
|
|
float3 vSurfGrad = sign(fDet) * (dBs * vR1 + dBt * vR2);
|
|
return normalize(abs(fDet) * vN - vSurfGrad);
|
|
}
|
|
#endif // NORMAL_SCREENSPACE
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Vertex Shader
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
struct FragmentInput
|
|
{
|
|
float4 positionOut [[position]];
|
|
float3 position;
|
|
float3 normal;
|
|
float3 tangent;
|
|
float3 bitangent;
|
|
float4 patchCoord;
|
|
#if COLOR_PATCHTYPE
|
|
float4 patchColor;
|
|
#endif
|
|
#if OSD_COMPUTE_NORMAL_DERIVATIVES
|
|
float3 Nu;
|
|
float3 Nv;
|
|
#endif
|
|
};
|
|
|
|
#if OSD_IS_ADAPTIVE
|
|
#if USE_STAGE_IN
|
|
#if OSD_PATCH_REGULAR || OSD_PATCH_BOX_SPLINE_TRIANGLE
|
|
struct ControlPoint
|
|
{
|
|
float3 P [[attribute(0)]];
|
|
#if OSD_PATCH_ENABLE_SINGLE_CREASE
|
|
float3 P1 [[attribute(1)]];
|
|
float3 P2 [[attribute(2)]];
|
|
#if !USE_PTVS_SHARPNESS
|
|
float2 vSegments [[attribute(3)]];
|
|
#endif
|
|
#endif
|
|
};
|
|
#elif OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
|
|
struct ControlPoint
|
|
{
|
|
float3 P [[attribute(0)]];
|
|
float3 Ep [[attribute(1)]];
|
|
float3 Em [[attribute(2)]];
|
|
float3 Fp [[attribute(3)]];
|
|
float3 Fm [[attribute(4)]];
|
|
};
|
|
#elif OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY_TRIANGLE
|
|
struct ControlPoint
|
|
{
|
|
float3 position [[attribute(0)]];
|
|
};
|
|
#endif
|
|
|
|
struct PatchInput
|
|
{
|
|
patch_control_point<ControlPoint> cv;
|
|
#if !USE_PTVS_FACTORS
|
|
float4 tessOuterLo [[attribute(5)]];
|
|
float4 tessOuterHi [[attribute(6)]];
|
|
#endif
|
|
int3 patchParam [[attribute(10)]];
|
|
};
|
|
#endif
|
|
|
|
|
|
#if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
|
|
typedef MTLQuadTessellationFactorsHalf PatchTessFactors;
|
|
#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
|
|
typedef MTLTriangleTessellationFactorsHalf PatchTessFactors;
|
|
#endif
|
|
|
|
|
|
kernel void compute_main(
|
|
const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
|
|
unsigned thread_position_in_grid [[thread_position_in_grid]],
|
|
unsigned thread_position_in_threadgroup [[thread_position_in_threadgroup]],
|
|
unsigned threadgroup_position_in_grid [[threadgroup_position_in_grid]],
|
|
OsdPatchParamBufferSet osdBuffers,
|
|
device PatchTessFactors* patchTessellationFactors [[buffer(PATCH_TESSFACTORS_INDEX)]]
|
|
#if OSD_USE_PATCH_INDEX_BUFFER
|
|
,device unsigned* patchIndex [[buffer(OSD_PATCH_INDEX_BUFFER_INDEX)]]
|
|
,device MTLDrawPatchIndirectArguments* drawIndirectCommands [[buffer(OSD_DRAWINDIRECT_BUFFER_INDEX)]]
|
|
#endif
|
|
)
|
|
{
|
|
//----------------------------------------------------------
|
|
// OSD Kernel Setup
|
|
//----------------------------------------------------------
|
|
|
|
#define PATCHES_PER_THREADGROUP (THREADS_PER_THREADGROUP / THREADS_PER_PATCH)
|
|
int const primitiveID = thread_position_in_grid / THREADS_PER_PATCH;
|
|
int const primitiveIDInTG = thread_position_in_threadgroup / THREADS_PER_PATCH;
|
|
int const vertexIndex = threadgroup_position_in_grid * PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH +
|
|
thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD;
|
|
int const vertexIndexInTG = thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD;
|
|
int const invocationID = (thread_position_in_threadgroup * VERTEX_CONTROL_POINTS_PER_THREAD) % (THREADS_PER_PATCH*VERTEX_CONTROL_POINTS_PER_THREAD);
|
|
|
|
//Contains the shared patchParam value used by all threads that act upon a single patch
|
|
//the .z (sharpness) field is set to -1 (NAN) if that patch should be culled to signal other threads to return.
|
|
threadgroup int3 patchParam[PATCHES_PER_THREADGROUP];
|
|
threadgroup PatchVertexType patchVertices[PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH];
|
|
|
|
//----------------------------------------------------------
|
|
// OSD Vertex Transform
|
|
//----------------------------------------------------------
|
|
{
|
|
patchParam[primitiveIDInTG] = OsdGetPatchParam(primitiveID, osdBuffers.patchParamBuffer);
|
|
|
|
for (unsigned threadOffset = 0; threadOffset < CONTROL_POINTS_PER_THREAD; ++threadOffset)
|
|
{
|
|
if (vertexIndexInTG + threadOffset < PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH)
|
|
{
|
|
const auto vertexId = osdBuffers.indexBuffer[(vertexIndex + threadOffset)];
|
|
const auto v = osdBuffers.vertexBuffer[vertexId];
|
|
|
|
threadgroup auto& patchVertex = patchVertices[vertexIndexInTG + threadOffset];
|
|
|
|
//----------------------------------------------------------
|
|
// User Vertex Transform
|
|
//----------------------------------------------------------
|
|
|
|
OsdComputePerVertex(float4(v.position,1), patchVertex, vertexId, frameConsts.ModelViewProjectionMatrix, osdBuffers);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if NEEDS_BARRIER
|
|
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
#endif
|
|
|
|
//----------------------------------------------------------
|
|
// OSD Patch Cull
|
|
//----------------------------------------------------------
|
|
{
|
|
auto patch = patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH;
|
|
|
|
if (!OsdCullPerPatchVertex(patch, frameConsts.ModelViewMatrix))
|
|
{
|
|
#if !OSD_USE_PATCH_INDEX_BUFFER
|
|
#if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
|
|
patchTessellationFactors[primitiveID].edgeTessellationFactor[0] = 0.0h;
|
|
patchTessellationFactors[primitiveID].edgeTessellationFactor[1] = 0.0h;
|
|
patchTessellationFactors[primitiveID].edgeTessellationFactor[2] = 0.0h;
|
|
patchTessellationFactors[primitiveID].edgeTessellationFactor[3] = 0.0h;
|
|
patchTessellationFactors[primitiveID].insideTessellationFactor[0] = 0.0h;
|
|
patchTessellationFactors[primitiveID].insideTessellationFactor[1] = 0.0h;
|
|
#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
|
|
patchTessellationFactors[primitiveID].edgeTessellationFactor[0] = 0.0h;
|
|
patchTessellationFactors[primitiveID].edgeTessellationFactor[1] = 0.0h;
|
|
patchTessellationFactors[primitiveID].edgeTessellationFactor[2] = 0.0h;
|
|
patchTessellationFactors[primitiveID].insideTessellationFactor = 0.0h;
|
|
#endif
|
|
#endif
|
|
|
|
patchParam[primitiveIDInTG].z = -1;
|
|
#if !NEEDS_BARRIER
|
|
return;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#if NEEDS_BARRIER
|
|
threadgroup_barrier(mem_flags::mem_threadgroup);
|
|
#endif
|
|
|
|
//----------------------------------------------------------
|
|
// OSD Patch Compute
|
|
//----------------------------------------------------------
|
|
if (patchParam[primitiveIDInTG].z != -1)
|
|
{
|
|
for (unsigned threadOffset = 0; threadOffset < VERTEX_CONTROL_POINTS_PER_THREAD; ++threadOffset)
|
|
{
|
|
if (invocationID + threadOffset < VERTEX_CONTROL_POINTS_PER_PATCH)
|
|
{
|
|
OsdComputePerPatchVertex(
|
|
patchParam[primitiveIDInTG],
|
|
invocationID + threadOffset,
|
|
primitiveID,
|
|
invocationID + threadOffset + primitiveID * VERTEX_CONTROL_POINTS_PER_PATCH,
|
|
patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH,
|
|
osdBuffers
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if NEEDS_BARRIER
|
|
threadgroup_barrier(mem_flags::mem_device_and_threadgroup);
|
|
#endif
|
|
|
|
//----------------------------------------------------------
|
|
// OSD Tessellation Factors
|
|
//----------------------------------------------------------
|
|
if (invocationID == 0)
|
|
{
|
|
|
|
#if OSD_USE_PATCH_INDEX_BUFFER
|
|
const auto patchId = atomic_fetch_add_explicit((device atomic_uint*)&drawIndirectCommands->patchCount, 1, memory_order_relaxed);
|
|
patchIndex[patchId] = primitiveID;
|
|
#else
|
|
const auto patchId = primitiveID;
|
|
#endif
|
|
|
|
OsdComputePerPatchFactors(
|
|
patchParam[primitiveIDInTG],
|
|
frameConsts.TessLevel,
|
|
primitiveID,
|
|
frameConsts.ProjectionMatrix,
|
|
frameConsts.ModelViewMatrix,
|
|
osdBuffers,
|
|
patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH,
|
|
patchTessellationFactors[patchId]
|
|
);
|
|
}
|
|
}
|
|
|
|
[[patch(quad, VERTEX_CONTROL_POINTS_PER_PATCH)]]
|
|
vertex FragmentInput vertex_main(
|
|
const constant Config& config [[buffer(CONFIG_BUFFER_INDEX)]],
|
|
const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
|
|
#if USE_STAGE_IN
|
|
const PatchInput patchInput [[stage_in]],
|
|
#else
|
|
const OsdVertexBufferSet patchInput,
|
|
#endif
|
|
float2 position_in_patch [[position_in_patch]],
|
|
uint patch_id [[patch_id]]
|
|
#if USE_DISPLACEMENT_RESOURCES
|
|
,texture2d_array<float, access::sample> textureDisplace_Data [[texture(DISPLACEMENT_TEXTURE_INDEX)]]
|
|
,device ushort* textureDisplace_Packing [[buffer(DISPLACEMENT_BUFFER_INDEX)]]
|
|
#endif
|
|
)
|
|
{
|
|
FragmentInput out;
|
|
|
|
#if USE_STAGE_IN
|
|
int3 patchParam = patchInput.patchParam;
|
|
#else
|
|
int3 patchParam = patchInput.patchParamBuffer[patch_id];
|
|
#endif
|
|
|
|
int refinementLevel = OsdGetPatchRefinementLevel(patchParam);
|
|
float tessLevel = min(frameConsts.TessLevel, (float)OSD_MAX_TESS_LEVEL) /
|
|
exp2((float)refinementLevel - 1);
|
|
|
|
auto patchVertex = OsdComputePatch(tessLevel, position_in_patch, patch_id, patchInput);
|
|
|
|
|
|
#if USE_DISPLACEMENT
|
|
float3 position = displacement(patchVertex.position,
|
|
patchVertex.normal,
|
|
patchVertex.patchCoord,
|
|
config.mipmapBias,
|
|
config.displacementScale
|
|
#if USE_DISPLACEMENT_RESOURCES
|
|
,textureDisplace_Data, textureDisplace_Packing
|
|
#endif
|
|
);
|
|
#else
|
|
float3 position = patchVertex.position;
|
|
#endif
|
|
|
|
|
|
out.positionOut = mul(frameConsts.ModelViewProjectionMatrix, float4(position, 1));
|
|
out.position = mul(frameConsts.ModelViewMatrix, float4(position,1)).xyz;
|
|
out.normal = mul(frameConsts.ModelViewMatrix,float4(patchVertex.normal, 0)).xyz;
|
|
out.tangent = mul(frameConsts.ModelViewMatrix,float4(patchVertex.tangent,0)).xyz;
|
|
out.bitangent = mul(frameConsts.ModelViewMatrix,float4(patchVertex.bitangent,0)).xyz;
|
|
out.patchCoord = patchVertex.patchCoord;
|
|
#if COLOR_PATCHTYPE
|
|
out.patchColor = getAdaptivePatchColor(patchParam, OsdGetPatchSharpness(patchParam));
|
|
#endif
|
|
#if OSD_COMPUTE_NORMAL_DERIVATIVES
|
|
out.Nu = mul(frameConsts.ModelViewMatrix, float4(patchVertex.Nu, 0)).xyz;
|
|
out.Nv = mul(frameConsts.ModelViewMatrix, float4(patchVertex.Nv, 0)).xyz;
|
|
#endif
|
|
return out;
|
|
}
|
|
#endif
|
|
|
|
const constant float VIEWPORT_SCALE = 1024.0; // XXXdyu
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Lighting
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#define NUM_LIGHTS 1
|
|
|
|
struct LightSource {
|
|
float4 position;
|
|
float4 ambient;
|
|
float4 diffuse;
|
|
float4 specular;
|
|
};
|
|
|
|
float4
|
|
lighting(float4 texColor, float3 Peye, float3 Neye, float occ, const constant LightSource (&lightSource)[NUM_LIGHTS])
|
|
{
|
|
float4 color = float4(0.0, 0.0, 0.0, 0.0);
|
|
float3 n = Neye;
|
|
|
|
for (int i = 0; i < NUM_LIGHTS; ++i) {
|
|
|
|
float4 Plight = lightSource[i].position;
|
|
float3 l = (Plight.w == 0.0)
|
|
? normalize(Plight.xyz) : normalize(Plight.xyz - Peye);
|
|
|
|
float3 h = normalize(l + float3(0,0,1)); // directional viewer
|
|
|
|
float d = max(0.0, dot(n, l));
|
|
float s = pow(max(0.0, dot(n, h)), 64.0f);
|
|
|
|
color += (1.0 - occ) * ((lightSource[i].ambient +
|
|
d * lightSource[i].diffuse) * texColor +
|
|
s * lightSource[i].specular);
|
|
}
|
|
|
|
color.a = 1.0;
|
|
return color;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Pixel Shader
|
|
// ---------------------------------------------------------------------------
|
|
|
|
float4
|
|
edgeColor(float4 Cfill, float4 edgeDistance)
|
|
{
|
|
#if defined(GEOMETRY_OUT_WIRE) || defined(GEOMETRY_OUT_LINE)
|
|
#ifdef PRIM_TRI
|
|
float d =
|
|
min(edgeDistance[0], min(edgeDistance[1], edgeDistance[2]));
|
|
#endif
|
|
#ifdef PRIM_QUAD
|
|
float d =
|
|
min(min(edgeDistance[0], edgeDistance[1]),
|
|
min(edgeDistance[2], edgeDistance[3]));
|
|
#endif
|
|
float4 Cedge = float4(1.0, 1.0, 0.0, 1.0);
|
|
float p = exp2(-2 * d * d);
|
|
|
|
#if defined(GEOMETRY_OUT_WIRE)
|
|
if (p < 0.25) discard;
|
|
#endif
|
|
|
|
Cfill.rgb = lerp(Cfill.rgb, Cedge.rgb, p);
|
|
#endif
|
|
return Cfill;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Pixel Shader
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
#if COLOR_PTEX_NEAREST || \
|
|
COLOR_PTEX_HW_BILINEAR || \
|
|
COLOR_PTEX_BILINEAR || \
|
|
COLOR_PTEX_BIQUADRATIC
|
|
#define USE_IMAGE_RESOURCES 1
|
|
#endif
|
|
|
|
#if USE_PTEX_OCCLUSION
|
|
#define USE_OCCLUSION_RESOURCES 1
|
|
#endif
|
|
|
|
#if USE_PTEX_SPECULAR
|
|
#define USE_SPECULAR_RESOURCES 1
|
|
#endif
|
|
|
|
fragment float4 fragment_main(
|
|
FragmentInput input [[stage_in]]
|
|
#if USE_DISPLACEMENT_RESOURCES
|
|
,texture2d_array<float, access::sample> textureDisplace_Data [[texture(DISPLACEMENT_TEXTURE_INDEX)]]
|
|
,device ushort* textureDisplace_Packing [[buffer(DISPLACEMENT_BUFFER_INDEX)]]
|
|
#endif
|
|
#if USE_IMAGE_RESOURCES
|
|
,texture2d_array<float, access::sample> textureImage_Data [[texture(IMAGE_TEXTURE_INDEX)]]
|
|
,device ushort* textureImage_Packing [[buffer(IMAGE_BUFFER_INDEX)]]
|
|
#endif
|
|
#if USE_OCCLUSION_RESOURCES
|
|
,texture2d_array<float, access::sample> textureOcclusion_Data [[texture(OCCLUSION_TEXTURE_INDEX)]]
|
|
,device ushort* textureOcclusion_Packing [[buffer(OCCLUSION_BUFFER_INDEX)]]
|
|
#endif
|
|
#if USE_SPECULAR_RESOURCES
|
|
,texture2d_array<float, acess::read> textureSpecular_Data [[texture(SPECULAR_TEXTURE_INDEX)]]
|
|
,device ushort* textureSpecular_Packing [[buffer(SPECULAR_BUFFER_INDEX)]]
|
|
#endif
|
|
,const constant LightSource (&lightSource [[buffer(0)]]) [NUM_LIGHTS]
|
|
,const constant Config& config [[buffer(1)]]
|
|
,const constant float4& shade [[buffer(2)]]
|
|
)
|
|
{
|
|
const auto displacementScale = config.displacementScale;
|
|
const auto mipmapBias = config.mipmapBias;
|
|
float4 outColor;
|
|
// ------------ normal ---------------
|
|
#if NORMAL_HW_SCREENSPACE || NORMAL_SCREENSPACE
|
|
float3 normal = perturbNormalFromDisplacement(input.position.xyz,
|
|
input.normal,
|
|
input.patchCoord,
|
|
mipmapBias,
|
|
textureDisplace_Data,
|
|
textureDisplace_Packing,
|
|
displacementScale);
|
|
#elif NORMAL_BIQUADRATIC || NORMAL_BIQUADRATIC_WG
|
|
float4 du, dv;
|
|
float4 disp = PtexMipmapLookupQuadratic(du, dv, input.patchCoord,
|
|
mipmapBias,
|
|
textureDisplace_Data,
|
|
textureDisplace_Packing);
|
|
|
|
disp *= displacementScale;
|
|
du *= displacementScale;
|
|
dv *= displacementScale;
|
|
|
|
float3 n = normalize(cross(input.tangent, input.bitangent));
|
|
float3 tangent = input.tangent + n * du.x;
|
|
float3 bitangent = input.bitangent + n * dv.x;
|
|
|
|
#if NORMAL_BIQUADRATIC_WG
|
|
tangent += input.Nu * disp.x;
|
|
bitangent += input.Nv * disp.x;
|
|
#endif
|
|
|
|
float3 normal = normalize(cross(tangent, bitangent));
|
|
#else
|
|
float3 normal = input.normal;
|
|
#endif
|
|
|
|
// ------------ color ---------------
|
|
#if COLOR_PTEX_NEAREST
|
|
float4 texColor = PtexLookupNearest(input.patchCoord,
|
|
textureImage_Data,
|
|
textureImage_Packing);
|
|
#elif COLOR_PTEX_HW_BILINEAR
|
|
float4 texColor = PtexLookupFast(input.patchCoord,
|
|
textureImage_Data,
|
|
textureImage_Packing);
|
|
#elif COLOR_PTEX_BILINEAR
|
|
float4 texColor = PtexMipmapLookup(input.patchCoord, mipmapBias,
|
|
textureImage_Data,
|
|
textureImage_Packing);
|
|
#elif COLOR_PTEX_BIQUADRATIC
|
|
float4 texColor = PtexMipmapLookupQuadratic(input.patchCoord, mipmapBias,
|
|
textureImage_Data,
|
|
textureImage_Packing);
|
|
#elif COLOR_PATCHTYPE
|
|
float4 texColor = lighting(float4(input.patchColor), input.position.xyz, normal, 0, lightSource);
|
|
outColor = max(texColor, shade);
|
|
return outColor;
|
|
#elif COLOR_PATCHCOORD
|
|
float4 texColor = lighting(input.patchCoord, input.position.xyz, normal, 0, lightSource);
|
|
outColor = max(texColor, shade);
|
|
return outColor;
|
|
#elif COLOR_NORMAL
|
|
float4 texColor = float4(normal.x, normal.y, normal.z, 1);
|
|
outColor = max(texColor, shade);
|
|
return outColor;
|
|
#else // COLOR_NONE
|
|
float4 texColor = float4(0.5, 0.5, 0.5, 1);
|
|
#endif
|
|
|
|
// ------------ occlusion ---------------
|
|
|
|
#if USE_PTEX_OCCLUSION
|
|
float occ = PtexMipmapLookup(input.patchCoord, mipmapBias,
|
|
textureOcclusion_Data,
|
|
textureOcclusion_Packing).x;
|
|
#else
|
|
float occ = 0.0;
|
|
#endif
|
|
|
|
// ------------ specular ---------------
|
|
|
|
#if USE_PTEX_SPECULAR
|
|
float specular = PtexMipmapLookup(input.patchCoord, mipmapBias,
|
|
textureSpecular_Data,
|
|
textureSpecular_Packing).x;
|
|
#else
|
|
float specular = 1.0;
|
|
#endif
|
|
// ------------ lighting ---------------
|
|
float4 Cf = lighting(texColor, input.position.xyz, normal, occ, lightSource);
|
|
|
|
// ------------ wireframe ---------------
|
|
outColor = max(Cf, shade);
|
|
return outColor;
|
|
}
|