Objects are too bright
While the worldmesh looks correct now, objects are just fullbright.

In the original game, an object does a raycast downwards from somewhere in the bounding box to the worldmesh to see how bright the vertex lighting is on that spot. It then uses that brightness value for the whole object.
An example of that can be found in the old REGoth repository:
https://github.com/REGoth-project/REGoth/blob/b3c483747c869524e679b90f8d86ef5160b4c0bf/src/engine/World.cpp#L457-L475
To actually display the brightness, a Color-variable of type float4 should be added to shader World.bsl which should then be multiplied with the diffuse color of the object or whatever works.
Casting the ray and accessing the material can be done by the VisualStaticMesh-component for now, but we will need that functionality for other components as well, so we might as well create a very basic Visual-component to serve as a base class to VisualSkeletalAnimation, VisualStaticMesh and the others.
Another issue is that the original applied some static directional lighting to the objects (not the world-mesh!) so we might need to make shader variants supporting that to make it look right.
For which game objects do we need to perform the raycasting? Only vobs?
Technically, all objects are Vobs in the original game so every object can do the raycast. But I'm not sure whether the Vob-class itself does the cast or whether that's a function of the Visual.
If I remember correctly, the raycast is done whenever an object is moved. This includes:
- Static- and Morph-Mesh Decoration
- Interactive objects
- Characters
For everything that uses skeletal animation the objects attached to the skeleton-nodes have to get the brightness value of the parent object.
That functionality would make a good component. Also, it could be useful to create a Visual-class which serves as a base for all other visuals. That Visual-class could get a setter for the brightness value so it does not need to do the raycast (remember node attachments) or you can have the Visual search in the Scene-Object for the raycast-component. If it cannot find one, it checks the parent, and so on. That might even be the cleaner solution...
That's a good starting point. I first assumed that the raycasting is only done upon world construction but it makes sense to perform it whenever an object moves, especially for characters.
I haven't yet thought about when and where to perform it but first implemented the shadow sampling method independently (and transferred the stuff from my fork to a branch in this repo). I now wanted to ensure that the sampling logic itself works and from there think about integrating it.
If repeated sampling is necessary it would probably be the best to make my ShadowSampler class a component which is attached to the GameWorld scene object. We could then use a Visual base class (maybe implementing NeedsGameWorld) to access the world's ShadowSampler and obtain the shadow value for its scene object.
If repeated sampling is necessary it would probably be the best to make my ShadowSampler class a component which is attached to the GameWorld scene object. We could then use a Visual base class (maybe implementing NeedsGameWorld) to access the world's ShadowSampler and obtain the shadow value for its scene object.
Why attach it to the GameWorld? IMHO it would make a lot more sense to equip every object which needs shadow sampling with a component. This would make hierarchies of scene objects work much easier and we wouldn't require the visuals to find a GameWorld. You can also hook the sampling process directly onto the onMoved-callback from the component.
The ShadowSampler class in my branch encapsulates the world's mesh and mesh collider and can obtain the shadow value for different query objects. I mean you can also equip each object with such an instance but that would be a waste of space as it precomputes the vertex brightness on construction.
Think of it as an object which you can query to get the shadow value for a scene object.
Ah, I took a quick look over your code now I understand the problem. You really need to do quite a lot of pre-processing which we obviously do not want to do for every object.
However, I still like the idea of having a component on each object to mark it as "This object does the shadow trace for itself and all children".
How about this: Create a class or component which holds the pre-processed data from ShadowSampler and is attached to or a member of GameWorld.
Then create a component, which needs access to the game world to access the pre-processed data but does the actual tracing by itself.
We then have split the pre-processing from the functionality of shadow-tracing. The Visual would then still not depend on NeedsGameWorld, which would be quite nice.
By the way, if your objects are standing in an indoor-location, you will need access to the lightmap at the spot you hit (So UV-coords are needed as well). This might be good to know, but you don't have to implement that yet. Old REGoth didn't even have proper lightmap support (although I hacked it in on a branch some time :smile:).
What we could also do (which aims in the same direction) is making the ShadowSampler itself a member of the game world and attach to each object a component referencing the sampler. The component is then just a proxy that delegates to the actual ShadowSampler.
This way the sampler is still one object encapsulating pre-processing and tracing logic but the Visual does not depend on the GameWorld.
About the lightmap: That should be a not so difficult to implement once the basic structure is in place. But it's a nice to know nonetheless and we should keep that in mind :)
What we could also do (which aims in the same direction) is making the ShadowSampler itself a member of the game world and attach to each object a component referencing the sampler. The component is then just a proxy that delegates to the actual ShadowSampler.
That would only make sense if there may be more than one shadow samplers per world. Both ways have pros and cons:
- Component finds
GameWorldandShadowSamplerby itself - Component now has dependency of GameWorld. Only oneShadowSamplerallowed. - Pass
ShadowSamplerto Component - Creator of the component needs access to the game world and needs to know there is aShadowSamplerin there.
That would only make sense if there may be more than one shadow samplers per world.
The component being a proxy to the actual sampler would not only make sense if there are more than one (which gives maximum flexibility) but the component also wouldn't have to bother with the samplers internals like the pre-processed data etc. This way we could also easily inject a dummy sampler that returns a constant value or whatever is possibly needed for testing.
Pass ShadowSampler to Component - Creator of the component needs access to the game world and needs to know there is a ShadowSampler in there.
Since instantiating objects is always (?) done from some method in the GameWorld component we would always have this required access.
You see, I am a big fan of keeping the (pre-processed) data and tracing logic strongly coupled :smile:
EDIT: Oh I see, you are mainly discussing if the component should find the sampler itself. But like I said: Since the component will most likely be constructed from somewhere in GameWorld, we could just as easily inject the sampler.
I'm already sold on the proxy-component. It could also hold the last value for the child-objects to query.
Since instantiating objects is always (?) done from some method in the GameWorld component we would always have this required access.
Probably yes. However, by doing that you take away the possibility to construct an object without access to the game world like we have now. This does not have to be a bad thing, since you can then be sure to have objects being constructed by the GameWorld only. We should still be careful as this is a huge architectural decision.
If we go that route, we should also get rid of the NeedsGameWorld-component and always pass whatever the component needs via the constructor so it's consistent.
I think I misunderstood the point a bit (hence my EDIT after EDIT in the reply). We are discussing how the component finds the ShadowSampler right? So either by itself or by getting handed one in the constructor. If so, although I would favor the passing in the constructor we could also go the canonical way. I don't have a strong opinion on that, as long as it somehow can perform the tracing :smile:
I'm already sold on the proxy-component. It could also hold the last value for the child-objects to query.
EDIT: Oh yeah, now I see...
I think I misunderstood the point a bit (hence my EDIT after EDIT in the reply). We are discussing how the component finds the ShadowSampler right?
Yes, exactly! It's really more a general architectural question. Though, letting the components not find the game world by themselves and only passing what they need seems cleaner to me now. We should absolutely refactor that. You could test it in your branch with your component and we roll your solution out to the rest in an other PR.
Just a small update. Slowly but surely everything comes together:
Looking forward to have this merged :smile: