MMK_033 Posted November 8, 2017 Share Posted November 8, 2017 Good day, here's my problem. I used to export objects with "NOR" option enabled in Kam's DFF IO, it makes them influenced from external light sources. That is, they might be illuminated by sun (with mods), by vehicle lights and street lights, just like peds and cars. I noticed a detail that the objects exported via Kam's DFF IO are considered by the game as "dynamic" objects - they depend from AMB_OBJ timecycle color, not from AMB. Probably illuminability originates from the same cause. But when I add the NVC section in DFF file through RWAnalyze, the night-time colors appear, but that external illumination feature is getting lack (and object becomes "static"). The same conflict happens when I use NVCMerge. According to some comparsions with NVCMerge's DFF, the data could be exported to the NVC section and the result could be visible in-game after first 12 bytes of the header is deleted. But either way leads to the same thing - NVC appears, but illumination dependence disappears. Is there any way to add NVC and preserve dependence on external light sources? In the game it looks like this. DK22Pac 1 Link to comment Share on other sites More sharing options...
DK22Pac Posted November 8, 2017 Share Posted November 8, 2017 (edited) Well, from your experiments you can clearly see that it's not possible to combine dynamic lighting with NVC in original game. There's a special flag that is used to determ if an object (building/road etc.) can be affected by 'dynamic' lights (vehicle lights, lampposts etc.). https://github.com/DK22Pac/plugin-sdk/blob/master/plugin_sa/game_sa/CEntity.h#L59 You can see how it works @0x553DC0 // 0x553DC0 1.0US, virtual CEntity method ; not overloaded for CBuildingbool CEntity::SetupLighting() { if (!m_nFlags.bLightObject) return false; ActivateDirectional(); SetLightColoursForPedsCarsAndObjects( CPointLights::GenerateLightsAffectingObject(GetPosition(), nullptr, this) * 0.5f); return true;}And to understand how this flag is set we should look @0x533EB7 // 0x533EB7 1.0US, CEntity::CreateRwObject +0x187if (!CCustomBuildingRenderer::IsCBPCPipelineAttached(m_pRwAtomic)) m_nFlags.bLightObject = true; // set by default to false in CEntity constructor // 0x5D7F40 1.0US, static methodbool CCustomBuildingRenderer::IsCBPCPipelineAttached(RpAtomic *atomic) { int pipelineId = GetPipelineID(atomic); return pipelineId == 0x53F2009C // custom (default building) rendering pipeline || pipelineId == 0x53F20098 // or custom (day&night lighting) rendering pipeline || CCustomBuildingDNPipeline::GetExtraVertColourPtr(atomic->geometry) // or has NVC && atomic->geometry->preLitLum); // and has prelit} Edited November 8, 2017 by DK22Pac MMK_033 1 Link to comment Share on other sites More sharing options...
MMK_033 Posted November 8, 2017 Author Share Posted November 8, 2017 (edited) I may ask stupid question, but did I get this right if all those return conditions after getting pipeline ID (at 0x5D7F40) return "true" (that is, they don't fit the condition under which the dynamic lighting flag should work)? I'm asking purely for understanding. Edited November 8, 2017 by MMK_033 Link to comment Share on other sites More sharing options...
DK22Pac Posted November 8, 2017 Share Posted November 8, 2017 I may ask stupid question, but did I get this right if all those return conditions after getting pipeline ID (at 0x5D7F40) return "true" (that is, they don't fit the condition under which the dynamic lighting flag should work)?Yes. In general, IsCBPCPipelineAttached (I guess 'CBPC' means 'Custom Building PC') returns true if an atomic (RenderWare graphics object) uses static day or day/night lighting.However, it doesn't check for a case when there's day static lighting only and no pipeline ID attached to atomic. So that could be a way to combine day-only lighting with dynamic lights. MMK_033 1 Link to comment Share on other sites More sharing options...
MMK_033 Posted November 8, 2017 Author Share Posted November 8, 2017 (edited) Alright, thanks for the explanation. Although using NVC for a single model appears to be more compact than making an additional night timed object for a main object, and gradual change of brightness of glowing windows seems to be more realistic in comparsion to timed objects which go off instantly, it's still kinda hard for me to choose what is preferable between external dynamic lighting and NVC. Although as an option, I can use timed objects from 20 to 7 (when the transition to/from NVC only begins) or use vertex color for windows in such a way that during the day it would be not very noticeable. Edited November 8, 2017 by MMK_033 Link to comment Share on other sites More sharing options...
DK22Pac Posted November 8, 2017 Share Posted November 8, 2017 In case if you want to test 'how it would look if', check my example #include "plugin.h"#include "common.h"#include "CPointLights.h"using namespace plugin;class TestDynamicLightingWithNVC {public: TestDynamicLightingWithNVC() { // Remove IsCBPCPipelineAttached() check and set flag 'bLightObject' to 'true' in any case patch::Nop(0x533EB7, 13); // Generate normals for all loaded models static bool bDoINeedToGenerateNormals = false; // Check if this model has normals and enable them RpGeometry *(*createGeometryCheckNormals)(int, int, unsigned int) = [](int numVerts, int numTriangles, unsigned int format) { if (format & rpGEOMETRYNORMALS) bDoINeedToGenerateNormals = false; else bDoINeedToGenerateNormals = true; return RpGeometryCreate(numVerts, numTriangles, format|rpGEOMETRYNORMALS); }; // Generate normals (if needed) static CdeclEvent<AddressList<0x74D5A8, H_CALL>, PRIORITY_AFTER, ArgPickN<RpGeometry *, 0>, void*(RpGeometry*)> onGeometryLoaded; onGeometryLoaded.before += [](RpGeometry *geometry) { // this is called before geometry unlocked, so we don't need to lock it if (bDoINeedToGenerateNormals) { // should we generate normals or model already has normals? // Use a simple method to generate normals for (int i = 0; i < geometry->numMorphTargets; i++) { if (geometry->morphTarget[i].normals) { memset(geometry->morphTarget[i].normals, 0, geometry->numVertices * 12); for (int tri = 0; tri < geometry->numTriangles; tri++) { CVector verts[3], normals[3]; for (int v = 0; v < 3; v++) { verts[v].FromRwV3d(geometry->morphTarget[i].verts[geometry->triangles[tri].vertIndex[v]]); normals[v].FromRwV3d(geometry->morphTarget[i].normals[geometry->triangles[tri].vertIndex[v]]); } CVector normal; normal.Cross(verts[0] - verts[1], verts[0] - verts[2]); if (normal.NormaliseAndMag() != 0.0f) { for (int n = 0; n < 3; n++) { normals[n] += normal; geometry->morphTarget[i].normals[geometry->triangles[tri].vertIndex[n]] = normals[n].ToRwV3d(); } } } } } } }; patch::RedirectCall(0x74D234, createGeometryCheckNormals); Events::gameProcessEvent += [] { CPed *playa = FindPlayerPed(0); if (playa) { // Create a green POINT light at player position when 'G' key pressed if (KeyPressed('G')) CPointLights::AddLight(0, FindPlayerCoors(0), CVector(0.0f, 0.0f, 0.0f), 50.0f, 0, 255, 0, 0, false, nullptr); // Create a red DIRECT light at player position when 'R' key pressed else if (KeyPressed('R')) { CPointLights::AddLight(1, FindPlayerCoors(0), playa->TransformFromObjectSpace(CVector(0.0f, 1.0f, 0.0f)) - playa->TransformFromObjectSpace(CVector(0.0f, 0.0f, 0.0f)), 50.0f, 255, 0, 0, 0, false, nullptr); } } }; }} testDynamicLightingWithNVC;Compiled version: Link MMK_033 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now