Fresnel Lighting from F3DEX3 (#941)
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows-opengl (push) Waiting to run
Build coop / build-windows-directx (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run

* Fresnel part1

* Fresnel part2

* vmacu
This commit is contained in:
ManIsCat2 2025-09-13 14:10:38 +03:30 committed by GitHub
parent 2c332d4db6
commit 6524e709a3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 96 additions and 11 deletions

View file

@ -405,6 +405,8 @@ s64 DynOS_Gfx_ParseGfxConstants(const String& _Arg, bool* found) {
gfx_constant(G_LIGHT_MAP_EXT);
gfx_constant(G_LIGHTING_ENGINE_EXT);
gfx_constant(G_PACKED_NORMALS_EXT);
gfx_constant(G_FRESNEL_COLOR_EXT);
gfx_constant(G_FRESNEL_ALPHA_EXT);
gfx_constant(G_COL_PRIM);
gfx_constant(G_COL_ENV);

View file

@ -7,6 +7,8 @@
#define G_LIGHT_MAP_EXT 0x00000800
#define G_LIGHTING_ENGINE_EXT 0x00004000
#define G_PACKED_NORMALS_EXT 0x00000080
#define G_FRESNEL_COLOR_EXT 0x00000040
#define G_FRESNEL_ALPHA_EXT 0x00400000
//////////
// DJUI //
@ -118,3 +120,50 @@
(_SHIFTL(G_PPARTTOCOLOR, 24, 8)) | (_SHIFTL(color, 16, 8)), \
((2 * ((part) + 1)) + 1 + offset) \
}}
////////////////////
//// G_MOVEWORD ////
////////////////////
#define G_MW_FX 0x00 /* replaces G_MW_MATRIX which is no longer supported */
#define G_MWO_FRESNEL 0x0C
/**
* Fresnel - Feature suggested by thecozies
* Enabled with the G_FRESNEL bit in geometry mode.
* The dot product between a vertex normal and the vector from the vertex to the
* camera is computed. The offset and scale here convert this to a shade alpha
* value. This is useful for making surfaces fade between transparent when
* viewed straight-on and opaque when viewed at a large angle, or for applying a
* fake "outline" around the border of meshes.
*
* If using Fresnel, you need to set the camera world position whenever you set
* the VP matrix, viewport, etc. See SPCameraWorld.
*
* The RSP does:
* s16 dotProduct = dot(vertex normal, camera pos - vertex pos);
* dotProduct = abs(dotProduct); // 0 = points to side, 7FFF = points at or away
* s32 factor = ((scale * dotProduct) >> 15) + offset;
* s16 result = clamp(factor << 8, 0, 7FFF);
* color_or_alpha = result >> 7;
*
* At dotMax, color_or_alpha = FF, result = 7F80, factor = 7F
* At dotMin, color_or_alpha = 00, result = 0, factor = 0
* 7F = ((scale * dotMax) >> 15) + offset
* 00 = ((scale * dotMin) >> 15) + offset
* Subtract: 7F = (scale * (dotMax - dotMin)) >> 15
* 3F8000 = scale * (dotMax - dotMin)
* scale = 3F8000 / (dotMax - dotMin) <--
* offset = -(((3F8000 / (dotMax - dotMin)) * dotMin) >> 15)
* offset = -((7F * dotMin) / (dotMax - dotMin)) <--
*
* To convert in the opposite direction:
* ((7F - offset) << 15) / scale = dotMax
* ((00 - offset) << 15) / scale = dotMin
*/
#define gSPFresnel(pkt, scale, offset) \
gMoveWd(pkt, G_MW_FX, G_MWO_FRESNEL, \
(_SHIFTL((scale), 16, 16) | _SHIFTL((offset), 0, 16)))
#define gsSPFresnel(scale, offset) \
gsMoveWd(G_MW_FX, G_MWO_FRESNEL, \
(_SHIFTL((scale), 16, 16) | _SHIFTL((offset), 0, 16)))

View file

@ -56,6 +56,7 @@ define_gfx_symbol(gsMoveWd, 3, false, GFX_PARAM_TYPE_INT, GFX_PARAM_TYPE_INT, GF
define_gfx_symbol(gsSPLoadGeometryMode, 1, false, GFX_PARAM_TYPE_INT);
define_gfx_symbol(gsSPVertexNonGlobal, 3, true, GFX_PARAM_TYPE_VTX, GFX_PARAM_TYPE_INT, GFX_PARAM_TYPE_INT);
define_gfx_symbol(gsSPCopyPlayerPartToColor, 3, false, GFX_PARAM_TYPE_INT, GFX_PARAM_TYPE_INT, GFX_PARAM_TYPE_INT);
define_gfx_symbol(gsSPFresnel, 2, false, GFX_PARAM_TYPE_INT, GFX_PARAM_TYPE_INT);
define_gfx_symbol_manual(gsSPTexture, 5, false, GFX_PARAM_TYPE_INT, GFX_PARAM_TYPE_INT, GFX_PARAM_TYPE_INT, GFX_PARAM_TYPE_INT, GFX_PARAM_TYPE_INT);
define_gfx_symbol_manual(gsSPSetGeometryMode, 1, false, GFX_PARAM_TYPE_INT);

View file

@ -718,14 +718,12 @@ static void geo_process_camera(struct GraphNodeCamera *node) {
mtxf_copy(gCamera->mtx, gMatStack[gMatStackIndex]);
}
// compute inverse matrix for lighting engine
if (le_is_enabled()) {
Mat4 invCameraMatrix;
if (mtxf_inverse_non_affine(invCameraMatrix, gCamera->mtx)) {
Mtx *invMtx = alloc_display_list(sizeof(Mtx));
mtxf_to_mtx(invMtx, invCameraMatrix);
gSPMatrix(gDisplayListHead++, invMtx, G_MTX_INVERSE_CAMERA_EXT);
}
// compute inverse matrix for lighting engine and fresnel
Mat4 invCameraMatrix;
if (mtxf_inverse_non_affine(invCameraMatrix, gCamera->mtx)) {
Mtx *invMtx = alloc_display_list(sizeof(Mtx));
mtxf_to_mtx(invMtx, invCameraMatrix);
gSPMatrix(gDisplayListHead++, invMtx, G_MTX_INVERSE_CAMERA_EXT);
}
if (node->fnNode.node.children != 0) {

View file

@ -61,6 +61,7 @@ static struct RSP {
uint32_t geometry_mode;
int16_t fog_mul, fog_offset;
int16_t fresnel_scale, fresnel_offset;
struct {
// U0.16
@ -850,6 +851,33 @@ static void OPTIMIZE_O3 gfx_sp_vertex(size_t n_vertices, size_t dest_index, cons
d->color.b *= vtxB;
}
if (rsp.geometry_mode & (G_FRESNEL_COLOR_EXT | G_FRESNEL_ALPHA_EXT)) {
Vec3f vpos = { v->ob[0], v->ob[1], v->ob[2] };
Vec3f vnormal = { nx / 255.0f, ny / 255.0f, nz / 255.0f };
// transform vpos and vnormal to world space
gfx_local_to_world_space(vpos, vnormal);
Vec3f viewDir = {
sInverseCameraMatrix[3][0] - vpos[0],
sInverseCameraMatrix[3][1] - vpos[1],
sInverseCameraMatrix[3][2] - vpos[2]
};
vec3f_normalize(viewDir);
vec3f_normalize(vnormal);
int32_t dot = (int32_t) (fabsf(vec3f_dot(vnormal, viewDir)) * 32767.0f);
int32_t factor = ((rsp.fresnel_scale * dot) >> 15) + rsp.fresnel_offset;
int32_t fresnel = clamp(factor << 8, 0, 0x7FFF);
uint8_t result = (uint8_t) (fresnel >> 7);
if (rsp.geometry_mode & G_FRESNEL_COLOR_EXT) {
d->color.r = d->color.g = d->color.b = result;
}
if (rsp.geometry_mode & G_FRESNEL_ALPHA_EXT) {
d->color.a = result;
}
}
if (rsp.geometry_mode & G_TEXTURE_GEN) {
float dotx = 0, doty = 0;
dotx += nx * rsp.current_lookat_coeffs[0][0];
@ -970,8 +998,9 @@ static void OPTIMIZE_O3 gfx_sp_vertex(size_t n_vertices, size_t dest_index, cons
if (fog_z > 255) fog_z = 255;
d->fog_z = fog_z;
}
d->color.a = v->cn[3];
if (!(rsp.geometry_mode & G_FRESNEL_ALPHA_EXT)) {
d->color.a = v->cn[3];
}
}
}
@ -1297,7 +1326,7 @@ static void gfx_sp_copymem(uint8_t idx, uint16_t dstofs, uint16_t srcofs, UNUSED
}
#endif
static void gfx_sp_moveword(uint8_t index, UNUSED uint16_t offset, uint32_t data) {
static void gfx_sp_moveword(uint8_t index, uint16_t offset, uint32_t data) {
switch (index) {
case G_MW_NUMLIGHT:
#ifdef F3DEX_GBI_2
@ -1318,6 +1347,12 @@ static void gfx_sp_moveword(uint8_t index, UNUSED uint16_t offset, uint32_t data
sDepthZMult = (gProjectionVanillaFarValue - gProjectionMaxNearValue) / (gProjectionVanillaFarValue - gProjectionVanillaNearValue);
sDepthZSub = gProjectionVanillaNearValue;
break;
case G_MW_FX:
if (offset == G_MWO_FRESNEL) {
rsp.fresnel_scale = (int16_t)(data >> 16);
rsp.fresnel_offset = (int16_t)data;
}
break;
}
}