-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Per pixel lighting support in Metal #1551
base: master
Are you sure you want to change the base?
Conversation
@@ -445,7 +472,7 @@ fragment half4 pipelineFragmentShader(ColorInOut in [[stage_in]], | |||
} | |||
} | |||
|
|||
currentColor = half4(in.vtxColor.rgb, 1.0h) * currentColor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be a good time to ask about this one. After blending the layers - the shader again multiplies by the vertex +lighting color. This was carried over from the original GL shaders. I know if this isn't here the output is wrong. But I'm not sure why.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Skimming through the code, my guess is this:
currentColor
starts out set to the lighting colour with no material values, but then on the first layer is overwritten to the layer colours of the first layer (in blendFirst
) with subsequent layers blending into that. Since we've lost the lighting colours at that point, we need to multiply them back in.
8ce854b
to
9f88aea
Compare
9f88aea
to
315ef75
Compare
I brought this branch up to date with master - and now it's acting strangely. For example - it's hitting asserts while trying to load the server.ini. I'll dig a bit and see whats going on. I'm pretty sure this behavior is newly unique to this branch. Last time I was in here it was working. |
The issue I was befuddled by is addressed in #1591. |
FWIW I'm pretty sure OpenGL is also doing per-vertex lighting to match DirectX. I might have been doing that in the fragment shader at one point while I was getting it set up, but it's in the vertex shader in the current version of the GL branch. |
Re-stating discussions elsewhere here for the status on this branch.
Relative to this PR:
We'll want to move ahead with this PR to get normal mapping into Metal. |
@dpogue - Checking back in to see if you have any thoughts here. We'll need this for bump mapping (even if we don't turn it on for everything.) Not high priority, just didn't want it to get lost. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I think this is okay. Admittedly I only skimmed the actual shader code implementation details.
I think we should do the work now to refactor this a bit so that it can be turned on/off dynamically per mesh, even if we don't actually hook up the dynamic choice yet.
Otherwise, just a few code style issues.
if (PLASMA_PER_PIXEL_LIGHTING) | ||
{ | ||
fDevice->CurrentRenderCommandEncoder()->setFragmentBytes(&fDevice->fPipeline->fCurrentRenderPassMaterialLighting, sizeof(plMaterialLightingDescriptor), FragmentShaderArgumentMaterialLighting); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't match our coding style, but we probably also want to make this controlled by a pipeline value rather than a define (even if we just hardcode that pipeline value to the value of the define for now)
if (PLASMA_PER_PIXEL_LIGHTING) | ||
{ | ||
fDevice->CurrentRenderCommandEncoder()->setFragmentBytes(lights, sizeof(plMetalLights), FragmentShaderArgumentLights); | ||
} else { | ||
fDevice->CurrentRenderCommandEncoder()->setVertexBytes(lights, sizeof(plMetalLights), VertexShaderArgumentLights); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't match our coding style, but we probably also want to make this controlled by a pipeline value rather than a define (even if we just hardcode that pipeline value to the value of the define for now)
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); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know how strict our coding style has been within Metal shaders, but the opening brace should be on the same line as the if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because Metal Shaders are C++ - I'm assuming we should apply the same coding style.
bool perPixelLighting = PLASMA_PER_PIXEL_LIGHTING; | ||
constants->setConstantValue(&perPixelLighting, MTL::DataTypeBool, FunctionConstantPerPixelLighting); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: move the calculation of this to the pipeline so that it can (later) be dynamic per mesh
315ef75
to
5ca8e69
Compare
0be27a0
to
36c1fb8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs code style cleanups
Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.cpp
Outdated
Show resolved
Hide resolved
Sources/Plasma/FeatureLib/pfMetalPipeline/plMetalPipelineState.cpp
Outdated
Show resolved
Hide resolved
Also cleaning up some redundant state binding
With the latest changes I added some better detection of redundant bindings. I can see the redundant bindings in the Metal debugger, and it's been on my list of things to address. Unnecessary draw commands create a larger buffer to send to the GPU - so they should be avoided. However - right now I'm using memcmp to compare struct values. I'd rather use a bool that marks when something is dirty and needs to be sent to the GPU. I've left notes behind in the code and will continue improving this in the future. |
This PR adds Metal per pixel lighting support to the shaders - controlled by a preprocessor flag. Per pixel lighting defaults to off in since it's an alternative rendering mode that does not match the original engine. While per pixel lighting seems correct - it should be regarded as experimental. Per pixel shading enables a shader variant for the "fixed" pipeline shader. This shader variant is controlled by a shader compile time flag. However - this flag is a function constant which means evaluation of it can be deferred to when the shader is compiled from Metal byte code into vender specific assembly. I.E. - Metal can wait to apply the flag until the final runtime shader compilation.
Metal was originally ported from the OpenGL fork which used per pixel lighting. Metal switched back to per vertex for several reasons:
Please look over this closely - I want to make sure the per vertex path has remained unchanged. Not in a rush to get this in.