Faux Vertex Lighting
This is a novel attempt at lighting that is identical to the real thing with a couple of added benefits for lazy people like me. I made it a couple of years ago for a project that I don’t have time for, so I’m publishing it as-is in case someone would find it useful.
Here are some features:
- Utilizes scene lights
- Simulates subdivided surfaces for more detailed lighting without the need for more vertices
- Subdivisions are not constrained to triangle boundaries, so they aren’t strictly accurate
- Removing this would result in an authentic implementation for better or for worse
This is not at all parameterized, readable, or well-optimized. I would need to rewrite it to alleviate those issues, but I feel it’s better to publish what I have for now in case I can’t.
Shader code
shader_type spatial;
render_mode skip_vertex_transform;
varying vec3 sfcPosVS;
varying vec3 sfcPosLS;
varying vec3 sfcNmlLS;
varying vec3 sfcRtLS;
varying vec3 sfcUpLS;
vec3 cvtSpcPos(vec3 v, mat4 m) {
return (m * vec4(v, 1.)).xyz;
}
vec3 cvtSpcDir(vec3 v, mat4 m) {
return normalize((m * vec4(v, 0.0)).xyz);
}
void vertex() {
sfcPosLS = VERTEX;
sfcNmlLS = NORMAL;
sfcRtLS = TANGENT;
sfcUpLS = -cross(NORMAL,TANGENT);
VERTEX = cvtSpcPos(VERTEX,MODELVIEW_MATRIX);
NORMAL = cvtSpcDir(NORMAL,MODELVIEW_MATRIX);
sfcPosVS = VERTEX;
}
void fragment() {
//
}
void light() {
vec3 lgtPosVS = (LIGHT / ATTENUATION) + sfcPosVS;
vec3 lgtPosWS = cvtSpcPos(lgtPosVS,INV_VIEW_MATRIX);
vec3 uv = vec3(
dot(sfcPosLS,sfcRtLS),
dot(sfcPosLS,-sfcUpLS),
dot(sfcPosLS,sfcNmlLS)
);
vec3 uvQtz = vec3(
floor(dot(sfcPosLS,sfcRtLS)),
floor(dot(sfcPosLS,-sfcUpLS)),
dot(sfcPosLS,sfcNmlLS)
);
vec3 tstPosLS = cvtSpcPos(lgtPosWS,inverse(MODEL_MATRIX));
vec3 tstPos2D = vec3(
dot(tstPosLS,sfcRtLS),
dot(tstPosLS,-sfcUpLS),
dot(tstPosLS,sfcNmlLS)
);
vec3 prjPosUV = tstPos2D;
float dst00 = clamp(
distance(prjPosUV,uvQtz) * .33,
0., 1.);
float dst01 = clamp(
distance(prjPosUV,uvQtz + vec3(0.,1.,0.)) * .33,
0., 1.);
float dst10 = clamp(
distance(prjPosUV,uvQtz + vec3(1.,0.,0.)) * .33,
0., 1.);
float dst11 = clamp(
distance(prjPosUV,uvQtz + vec3(1.,1.,0.)) * .33,
0., 1.);
vec3 uvFrc = fract(uv);
float finalf;
if (uvFrc.x > uvFrc.y) {
finalf =
(1. - uvFrc.x) * dst00 +
(uvFrc.x - uvFrc.y) * dst10 +
uvFrc.y * dst11; }
else {
finalf =
(1. - uvFrc.y) * dst00 +
(uvFrc.y - uvFrc.x) * dst01 +
uvFrc.x * dst11;
}
float sfcAngMlt = clamp(dot(LIGHT,NORMAL),0.,1.);
float atnMod = clamp(round(2. * ATTENUATION),0.,1.);
DIFFUSE_LIGHT += atnMod * LIGHT_COLOR * clamp(1. - finalf,0.,1.) * sfcAngMlt;
}
is this 4.3 friendly?
Just tried it; yes.
alright but does it still apply the per-vertex lighting look?
I can’t quite figure out how to apply it? It doesn’t take in any texture so I’m assuming that you use multiple passes or am I missing something?