Skip to content

Commit

Permalink
Per pixel lighting option in Metal
Browse files Browse the repository at this point in the history
  • Loading branch information
colincornaby committed Jun 2, 2024
1 parent f46ad9f commit 315ef75
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ enum plUVWSrcModifiers: uint32_t

using namespace metal;

constant const bool perPixelLighting [[ function_constant(FunctionConstantPerPixelLighting) ]];
constant const bool perVertexLighting = !perPixelLighting;

constant const uint8_t sourceType1 [[ function_constant(FunctionConstantSources + 0) ]];
constant const uint8_t sourceType2 [[ function_constant(FunctionConstantSources + 1) ]];
constant const uint8_t sourceType3 [[ function_constant(FunctionConstantSources + 2) ]];
Expand Down Expand Up @@ -153,16 +156,18 @@ struct FragmentShaderArguments

typedef struct
{
float4 position [[position]];
float3 texCoord1 [[function_constant(hasLayer1)]];
float3 texCoord2 [[function_constant(hasLayer2)]];
float3 texCoord3 [[function_constant(hasLayer3)]];
float3 texCoord4 [[function_constant(hasLayer4)]];
float3 texCoord5 [[function_constant(hasLayer5)]];
float3 texCoord6 [[function_constant(hasLayer6)]];
float3 texCoord7 [[function_constant(hasLayer7)]];
float3 texCoord8 [[function_constant(hasLayer8)]];
half4 vtxColor [[ centroid_perspective ]];
float4 position [[ position ]];
float4 worldPos [[ function_constant(perPixelLighting) ]];
float3 normal [[ function_constant(perPixelLighting) ]];
float3 texCoord1 [[ function_constant(hasLayer1) ]];
float3 texCoord2 [[ function_constant(hasLayer2) ]];
float3 texCoord3 [[ function_constant(hasLayer3) ]];
float3 texCoord4 [[ function_constant(hasLayer4) ]];
float3 texCoord5 [[ function_constant(hasLayer5) ]];
float3 texCoord6 [[ function_constant(hasLayer6) ]];
float3 texCoord7 [[ function_constant(hasLayer7) ]];
float3 texCoord8 [[ function_constant(hasLayer8) ]];
half4 vtxColor [[ centroid_perspective ]];
half4 fogColor;
} ColorInOut;

Expand All @@ -174,10 +179,10 @@ typedef struct
} ShadowCasterInOut;

half4 calcLitMaterialColor(constant plMetalLights & lights,
const half4 materialColor,
constant plMaterialLightingDescriptor & materialLighting,
const float4 position,
const float3 normal)
const half4 materialColor,
constant plMaterialLightingDescriptor & materialLighting,
const float4 position,
const float3 normal)
{
half3 LAmbient = half3(0.h, 0.h, 0.h);
half3 LDiffuse = half3(0.h, 0.h, 0.h);
Expand Down Expand Up @@ -226,13 +231,13 @@ half4 calcLitMaterialColor(constant plMetalLights & lights,

const half3 ambient = (MAmbient.rgb) * clamp(materialLighting.globalAmb.rgb + LAmbient.rgb, 0.h, 1.h);
const half3 diffuse = clamp(LDiffuse.rgb, 0.h, 1.h);
return clamp(half4(ambient + diffuse + MEmissive.rgb, MDiffuse.a), 0.h, 1.h);
return clamp(half4(ambient + diffuse + MEmissive.rgb, abs(materialLighting.invertAlpha - MDiffuse.a)), 0.h, 1.h);
}

vertex ColorInOut pipelineVertexShader(Vertex in [[stage_in]],
constant VertexUniforms & uniforms [[ buffer( VertexShaderArgumentFixedFunctionUniforms) ]],
constant plMaterialLightingDescriptor & materialLighting [[ buffer( VertexShaderArgumentMaterialLighting) ]],
constant plMetalLights & lights [[ buffer(VertexShaderArgumentLights) ]],
constant VertexUniforms & uniforms [[ buffer(VertexShaderArgumentFixedFunctionUniforms) ]],
constant plMaterialLightingDescriptor & materialLighting [[ buffer(VertexShaderArgumentMaterialLighting), function_constant(perVertexLighting) ]],
constant plMetalLights & lights [[ buffer(VertexShaderArgumentLights), function_constant(perVertexLighting) ]],
constant float4x4 & blendMatrix1 [[ buffer(VertexShaderArgumentBlendMatrix1), function_constant(temp_hasOnlyWeight1) ]])
{
ColorInOut out;
Expand All @@ -245,9 +250,20 @@ vertex ColorInOut pipelineVertexShader(Vertex in [[stage_in]],
const float4 position2 = blendMatrix1 * float4(in.position, 1.f);
position = (in.weight1 * position) + ((1.f - in.weight1) * position2);
}

out.vtxColor = calcLitMaterialColor(lights, inColor, materialLighting, position, Ndirection);
out.vtxColor.a = abs(uniforms.invVtxAlpha - out.vtxColor.a);

if (perPixelLighting)
{
// send the world pos on to the pixel shader for lighting
out.worldPos = position;
out.normal = Ndirection;
}

if (perPixelLighting)
{
out.vtxColor = inColor;
} else {
out.vtxColor = calcLitMaterialColor(lights, inColor, materialLighting, position, Ndirection);
}

const float4 vCamPosition = position * uniforms.worldToCameraMatrix;

Expand Down Expand Up @@ -423,9 +439,12 @@ half4 FragmentShaderArguments::sampleLayer(const size_t index, const half4 verte
}

fragment half4 pipelineFragmentShader(ColorInOut in [[stage_in]],
const FragmentShaderArguments fragmentShaderArgs)
const FragmentShaderArguments fragmentShaderArgs,
constant plMetalLights & lights [[ buffer(FragmentShaderArgumentLights), function_constant(perPixelLighting) ]],
constant plMaterialLightingDescriptor & materialLighting [[ buffer(FragmentShaderArgumentMaterialLighting), function_constant(perPixelLighting) ]])
{
half4 currentColor = in.vtxColor;
const half4 lightingContributionColor = perPixelLighting ? calcLitMaterialColor(lights, in.vtxColor, materialLighting, in.worldPos, in.normal) : in.vtxColor;
half4 currentColor = lightingContributionColor;

/*
SPECIAL PLASMA RULE:
Expand Down Expand Up @@ -453,7 +472,7 @@ fragment half4 pipelineFragmentShader(ColorInOut in [[stage_in]],
}
}

currentColor = half4(in.vtxColor.rgb, 1.0h) * currentColor;
currentColor = lightingContributionColor * currentColor;
}

currentColor.rgb = mix(in.fogColor.rgb, currentColor.rgb, (float)clamp(in.fogColor.a, 0.0h, 1.0h));
Expand Down
21 changes: 12 additions & 9 deletions Sources/Plasma/FeatureLib/pfMetalPipeline/ShaderSrc/ShaderTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ typedef __attribute__((__ext_vector_type__(3))) half half3;
typedef __attribute__((__ext_vector_type__(4))) half half4;
#endif

enum plMetalVertexShaderArgument
enum plMetalShaderArgument
{
/// Material State
VertexShaderArgumentFixedFunctionUniforms = 2,
Expand All @@ -67,19 +67,20 @@ enum plMetalVertexShaderArgument
/// Blend matrix for GPU side animation blending
VertexShaderArgumentBlendMatrix1 = 6,
/// Describes the state of a shadow caster for shadow cast shader
VertexShaderArgumentShadowState = 9
};

enum plMetalFragmentShaderArgumentIndex
{
VertexShaderArgumentShadowState = 9,

/// Texture is a legacy argument for the simpler plate shader
FragmentShaderArgumentTexture = 1,
/// Fragment uniforms
FragmentShaderArgumentShadowCastUniforms = 4,
/// Legacy argument buffer
FragmentShaderArgumentUniforms = 5,
/// Layer index of alpha for shadow fragment shader
FragmentShaderArgumentShadowCastAlphaSrc = 8
FragmentShaderArgumentShadowCastAlphaSrc = 8,
/// Light Table
FragmentShaderArgumentLights = 10,
/// Material properties for vertex lighting
FragmentShaderArgumentMaterialLighting = 11
};

enum plMetalVertexAttribute
Expand Down Expand Up @@ -112,6 +113,8 @@ enum plMetalFunctionConstant
FunctionConstantLayerFlags = 18,
/// Numbrer of weights in the FVF vertex layout.
FunctionConstantNumWeights = 26,
/// Per pixel lighting enable flag
FunctionConstantPerPixelLighting = 27,
};

enum plMetalLayerPassType: uint8_t
Expand Down Expand Up @@ -181,6 +184,8 @@ struct plMaterialLightingDescriptor
uint8_t emissiveSrc;
half3 specularCol;
uint8_t specularSrc;

bool invertAlpha;
};

struct VertexUniforms
Expand All @@ -191,8 +196,6 @@ struct VertexUniforms
matrix_float4x4 cameraToWorldMatrix;
matrix_float4x4 worldToCameraMatrix;

bool invVtxAlpha;

uint8_t fogExponential;
simd::float2 fogValues;
half3 fogColor;
Expand Down
16 changes: 13 additions & 3 deletions Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,22 @@ bool plRenderTriListFunc::RenderPrims() const

size_t uniformsSize = offsetof(VertexUniforms, uvTransforms) + sizeof(UVOutDescriptor) * fDevice->fPipeline->fCurrNumLayers;
fDevice->CurrentRenderCommandEncoder()->setVertexBytes(fDevice->fPipeline->fCurrentRenderPassUniforms, sizeof(VertexUniforms), VertexShaderArgumentFixedFunctionUniforms);

fDevice->CurrentRenderCommandEncoder()->setVertexBytes(&fDevice->fPipeline->fCurrentRenderPassMaterialLighting, sizeof(plMaterialLightingDescriptor), VertexShaderArgumentMaterialLighting);
if (PLASMA_PER_PIXEL_LIGHTING)
{
fDevice->CurrentRenderCommandEncoder()->setFragmentBytes(&fDevice->fPipeline->fCurrentRenderPassMaterialLighting, sizeof(plMaterialLightingDescriptor), FragmentShaderArgumentMaterialLighting);
}

plMetalLights* lights = &fDevice->fPipeline->fLights;
size_t lightSize = offsetof(plMetalLights, lampSources) + (sizeof(plMetalShaderLightSource) * lights->count);

fDevice->CurrentRenderCommandEncoder()->setVertexBytes(lights, sizeof(plMetalLights), VertexShaderArgumentLights);
if (PLASMA_PER_PIXEL_LIGHTING)
{
fDevice->CurrentRenderCommandEncoder()->setFragmentBytes(lights, sizeof(plMetalLights), FragmentShaderArgumentLights);
} else {
fDevice->CurrentRenderCommandEncoder()->setVertexBytes(lights, sizeof(plMetalLights), VertexShaderArgumentLights);
}
fDevice->CurrentRenderCommandEncoder()->drawIndexedPrimitives(MTL::PrimitiveTypeTriangle, fNumTris * 3, MTL::IndexTypeUInt16, fDevice->fCurrentIndexBuffer, (sizeof(uint16_t) * fIStart));
}

Expand Down Expand Up @@ -1618,9 +1628,9 @@ bool plMetalPipeline::IHandleMaterialPass(hsGMaterial* material, uint32_t pass,
}

if (s.fBlendFlags & hsGMatState::kBlendInvertVtxAlpha)
fCurrentRenderPassUniforms->invVtxAlpha = true;
fCurrentRenderPassMaterialLighting.invertAlpha = true;
else
fCurrentRenderPassUniforms->invVtxAlpha = false;
fCurrentRenderPassMaterialLighting.invertAlpha = false;

std::vector<plLightInfo*>& spanLights = currSpan->GetLightList(false);

Expand Down
26 changes: 13 additions & 13 deletions Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ void plMetalMaterialPassPipelineState::GetFunctionConstants(MTL::FunctionConstan
constants->setConstantValues(&fFragmentShaderDescription.fPassTypes, MTL::DataTypeUChar, NS::Range(FunctionConstantSources, 8));
constants->setConstantValues(&fFragmentShaderDescription.fBlendModes, MTL::DataTypeUInt, NS::Range(FunctionConstantBlendModes, 8));
constants->setConstantValues(&fFragmentShaderDescription.fMiscFlags, MTL::DataTypeUInt, NS::Range(FunctionConstantLayerFlags, 8));
bool perPixelLighting = PLASMA_PER_PIXEL_LIGHTING;
constants->setConstantValue(&perPixelLighting, MTL::DataTypeBool, FunctionConstantPerPixelLighting);
}

size_t plMetalMaterialPassPipelineState::GetHash() const
Expand Down Expand Up @@ -267,23 +269,21 @@ void plMetalRenderSpanPipelineState::ConfigureBlendMode(const uint32_t blendMode
MTL::Function* plMetalMaterialPassPipelineState::GetVertexFunction(MTL::Library* library)
{
NS::Error* error = nullptr;
MTL::FunctionConstantValues* constants = MTL::FunctionConstantValues::alloc()->init()->autorelease();
GetFunctionConstants(constants);
MTL::Function* function = library->newFunction(
NS::String::string("pipelineVertexShader", NS::ASCIIStringEncoding),
MakeFunctionConstants(),
&error)
->autorelease();
return function;
MTL::Function* function = library->newFunction(NS::String::string("pipelineVertexShader", NS::ASCIIStringEncoding),
MakeFunctionConstants(),
&error);
assert(!error);
return function->autorelease();
}

MTL::Function* plMetalMaterialPassPipelineState::GetFragmentFunction(MTL::Library* library)
{
return library->newFunction(
NS::String::string("pipelineFragmentShader", NS::ASCIIStringEncoding),
MakeFunctionConstants(),
(NS::Error**)nullptr)
->autorelease();
NS::Error* error = nullptr;
MTL::Function* function = library->newFunction(NS::String::string("pipelineFragmentShader", NS::ASCIIStringEncoding),
MakeFunctionConstants(),
&error);
assert(!error);
return function->autorelease();
}

plMetalMaterialPassPipelineState::~plMetalMaterialPassPipelineState()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ You can contact Cyan Worlds, Inc. by email legal@cyan.com
#include "plMetalDevice.h"
#include "plSurface/plShaderTable.h"

#ifndef PLASMA_PER_PIXEL_LIGHTING
#define PLASMA_PER_PIXEL_LIGHTING 0
#endif

enum plMetalPipelineType
{
// Unknown is for abstract types, don't use it
Expand Down

0 comments on commit 315ef75

Please sign in to comment.