Replies: 17 comments 13 replies
-
@Crydsch thank you very much for writting down the issue... it requires some further thinking... |
Beta Was this translation helpful? Give feedback.
-
No worries, take your time. |
Beta Was this translation helpful? Give feedback.
-
Hey, it's been two weeks now, i really don't want to pressure you, but have you had time to think about it? If you think a bigger API change would be too disruptive now, I can start to implement the internals only and leave the API as is. Is this acceptable? |
Beta Was this translation helpful? Give feedback.
-
I have a question and suggestion. Can you make the changes you want in include file(s) separate from raylib that map what you want over raylib/raygui ? That way you can build with those procedures, confirm operation, and satisfy yourself. Then, depending on how Ramon is satisfied, you can remove the extension once they are part of raylib/raygui for direct use and/or cope with naming differences. And you don't need some sort of lock-step coordination that depends on changes to raylib before you can advance your work. This should let you also deal with an expanded DLL and bindngs you want from other languages. |
Beta Was this translation helpful? Give feedback.
-
I've just looked at my camera code in a long term project I'm doing. As I wanted a free fly camera that can toggle between fly and using the mouse with a 2d GUI, I had a number of challenges! I basically had to abstract (and then mostly rewrite) the camera first person mode (camera update isn't called during gui mode). Swapping camera modes (gui mode and back) meant I needed to access private members like camera angle x,y and also had to allow for mouse input rather than directly using GetMousePosition, not to mention the view bobbing that cannot be customised presently... I'd strongly recommend getters and setters to most if not all the private CAMERA variable struct, to maximise flexibility This will make "custom" camera modes actually possible. Not coupling to raylib / raymath is needless (no one is realistically going to use rcamera.h outside raylib) and hardcoding copies of raymath functions its a perfect opportunity to introduce bugs/inconsistencies with the math, that had be puzzled for a short while.... |
Beta Was this translation helpful? Give feedback.
-
Hi @Crydsch, excuse my late response, I'm a bit busy lately. Provided low-level function look nice to me, some review: // Camera inputs state must be set every frame, it could be called by a higher-level function like UpdateCamera() in raylib core module
void SetCameraInputs(int *currentKeysDown, int keyCount, Vector2 currentMousePos, int *currentGamepadButtonsDown, int gamepadButtonCount, Vector2 currentGamepadAxisValue);
void CameraMoveForward(Camera3D *camera, float distance);
void CameraYaw(Camera3D *camera, float deg);
void CameraPitch(Camera3D *camera, float deg);
void CameraRoll(Camera3D *camera, float deg);
Matrix GetCameraViewMatrix()
Matrix GetCameraProjectionMatrix() To decouple inputs from camera, a function to receive input state every frame should be available. Input state could also be managed internally by the camera (current/previous states...). To start with, we can use raylib provided data types: To start with, we can use Current camera module abuses of lots of defines, some of them confusing, it will be nice to move some of those configuration values to variables accesible to the user for runtime configuration. Side note: Current camera module was originally implemented in 2014 by a maths student, I redesigned-reviewed it several times but the core Euler maths used are still there. |
Beta Was this translation helpful? Give feedback.
-
@orcmid Thank you for the suggestion, but that will not work as I want to change internals and not just add onto them. @chriscamacho Some valid points! Anyway, getters and setters should always be available in raylib as you can just access the structs yourself. I imagine you start out with a base mode such as FREE or FP to determining how the camera should handle rotations (ie allow roll or not) and then it is up to you to call move and turn functions. Regarding the coupling with raymath: @raysan5 Thank you for your response. With that i feel confident starting with it :) I have only one question regarding the suggested enum {
MoveForwardKey,
MoveBackwardKey,
MoveRightKey,
MoveLeftKey,
...
} That way we can pass just an array (int pointer) and the user can define their own key mapping. Is this what you had in mind? |
Beta Was this translation helpful? Give feedback.
-
@Crydsch Actually I don't know what's the best way to allow custom inputs mapping, complexity for that option could scalate quickly! For example, in case we consider gamepad/touch inputs for the camera. In any case, it would be a great addition. 3d camera support for touch devices has been on my TODO list forever! :D Like the other parts, we can start with a simple approach and scalate it later on. Defining an |
Beta Was this translation helpful? Give feedback.
-
@Crydsch the gui is 2d, but you need the mouse for it, which is in use during mouse look mode... accounting for the mouse and swapping "modes" with the current camera update is problematic for a number of reasons, hence the need for my own update camera function... a number the the variables needed for a custom camera are not accessible as they are inside a static struct inside rcamera.h Do take care with Quats and don't assume they are the miracle cure for gimbal lock as even with quats if implemented wrong, you can still come unstuck. Attempting a one solution fits all solution, leads to inflexibility and what we have today with rcamera.h (hence its persistence too) I think it would be better to leave the user with MatrixLookAt and the camera public struct with reduced members, basically just what BeginMode3D needs, leave UpdateCamera in as deprecated with a warning message to the console just shown the first time UpdateCamera is run (but make it an obvious multi line warning!) A few simple examples for first person on a plane (Eulers), 3d fly mode (full YPR rotations with quats) and maybe one or two others - will have a minimal amount of code for their camera update, and as the end user is doing it for themselves, a novice from an example, or a more seasoned coder from their own experience, then there will be far more flexibility and a much more robust camera system. Another benefit of this is that it will help people learn about just what is going on with the 3d maths rather than glossing over it with some magic black box function... |
Beta Was this translation helpful? Give feedback.
-
Camera math is surprisingly complex. In case it's of use as reference, I have fully worked and mature camera math at the link below, as well as interactive camera controllers that are independent of the input system. It has all the usual "editor" camera modes, "cinema" modes, and the usual modes, like look at. https://github.com/meshula/LabCamera (Not suggesting you use it, but if you're looking for a how do I do X reference, it's all there :) ) |
Beta Was this translation helpful? Give feedback.
-
@Crydsch please understand me. This is a way to stage and confirm API changes by first building atop the existing APIs, then reverting to the updated original API where it has been updated to match. I assure you that I have done this in a software project as part of getting from a 1.0 API to a 2.0 API and it worked just great. It also let developers start using the 1.0-bis API addition early without getting blocked waiting for the stable 2.0 to use. You are not obligated to try this of course. However, you are relying on an open-source project and you cannot assert schedule dependencies :). Don't break your own heart. |
Beta Was this translation helpful? Give feedback.
-
I honestly do not see camera maths as somehow "complex" yes the current updateCamera seems complex until you isolate the modes, and replace the manually implemented matrix code with calls to raymath... I really do not see it too burdensome for the end user to do the updating they want (or should there be a player controller with fixed complex mash up of modes too?) |
Beta Was this translation helpful? Give feedback.
-
Camera speed and FrameTimeAny game that should run on a different machine than the on it was developt on, This is true for camera systems as well, especially in conjunction with camera movement. I do not think we should hide some magic value in a define. This should be user configurable. My current solution would look like this: For raylib internally, we could then prepare everything in Still I am not entirely sure where/how to save/allow user defined camera speeds.. What do you think about this problem? |
Beta Was this translation helpful? Give feedback.
-
well you have to put it somewhere, better to make it accessible than hide it away, and as its only a one off (or at most 3-4 cameras) it really doesn't matter the size, so what if its 2kb or even 20kb.... |
Beta Was this translation helpful? Give feedback.
-
New Input System ?From the beginning on of this redesign we talked about a new input system for various reasons. The new system should handle (engine agnostic!) inputs and manipulate the camera accordingly. In general we have 2 kinds of inputs:
Both kinds need frame time compensation. Take 1: handle input statesWe could get all kinds of input states directly and handle which buttons are currently pressed and resolve deltas internally. Also these kinds of input handling is typically already available in every engine. => From now on I assume we get the delta values passed directly. Take 2: camera actionsWe could implement engine agnostic discrete inputs with an enum of camera actions. Still we would need to get any continuous inputs as floats directly. Then we want to support all other kinds of inputs. And we want frame time compensation, which is engine specific, so it needs to be passed too. This is very complex and not usable. You were right when you said it would escalate quickly ;) Note that we just combined all discrete inputs into one array of actions. Now that the user is providing the inputs contiuously anyway, we dont need the actions anymore.
=> This looks awfully similar to the low-level API! Take 3: a step backWe wanted this new input system to be engine agnostic and we want to provide ease of use from within raylib. In raylib we only make use of the SolutionAt this point I am not sure if we really need new input system on top of the low-level API.
We can also apply frame time compensation here as well. If a raylib user wants access to the low-level API they just have to Any additional system in between, will just complicate things. As you said "Keep it Simple, Avoid Overengineering, Less is More". Maybe I am missing something, or am seeing this wrong somewhere. |
Beta Was this translation helpful? Give feedback.
-
One thing you didn't mention but probably already have been thinking about it is the heavy use of static variables when some of them could be placed inside the camera struct. I have spent a long time investigating an issue with my multiple camera setup and camera switching only to realize it stems from the CameraData being a static variable instead of being inside the Camera3D. I will probably modify my local copy of raylib and "fix" this but spending some time on this probably wouldn't hurt overall. |
Beta Was this translation helpful? Give feedback.
-
@Crydsch @Pirolye This PR already looks very good and it's ready for merging but it's a big/breaking change in current camera system and I'm just waiting for next release approach and some further review. |
Beta Was this translation helpful? Give feedback.
-
The current implementation of the camera module has some issues.
It uses raylib-dependant input detection and is overall quite complex.
I also noticed that the CAMERA_FREE mode uses a "standard 3d-content-creation scheme" and does not actually
behave like a free camera one would expect in a space game or flight simulator.
To improve the camera module I talked to @raysan5 about a quaternion-based redesign I would like to work on.
By utilizing quaternions we naturally avoid gimbal-lock, and can simplify the camera code.
It also reduces the memory footprint.
Requirements
Also,
UpdateCamera()
should not perform it's own input detection, but rather get the current input state passed by the caller.Redesign
After some prototyping I came up with the following design:
Camera Modes
I found out that the four camera modes are related to each other, which allows great simplification.
CAMERA_FREE
is completely unrestricted.CAMERA_FIRST_PERSON
is aCAMERA_FREE
without roll and locked on the up-axis (to prevent over rotation when looking up/down).CAMERA_THIRD_PERSON
is aCAMERA_FIRST_PERSON
focused on a target. (And potentially further locked to prevent looking up).CAMERA_ORBITAL
is aCAMERA_THIRD_PERSON
with a locked target. (And potentially auto-rotation).Note: The new
CAMERA_FREE
is different from the old one. If a panning camera mode similar to the old free mode is wanted, it can simply be added as another mode. Even though I think a (non auto-rotating) orbital camera is even better in that respect.API
To ease the usability we provide functions, such as:
(Naming WIP)
MoveCamera(Camera3D *camera, Vector3 offset)
TurnCameraYaw(Camera3D *camera, float rad)
TurnCameraPitch(Camera3D *camera, float rad)
TurnCameraRoll(Camera3D *camera, float rad)
...
With such functions we are independent from any input system and one can easily create a custom camera mode.
To be fully engine-agnostic the camera may also provide functions to get the camera matrices:
GetCameraViewMatrix()
GetCameraProjectionMatrix()
With the former functions in place, raylib/the user could manipulate the camera based on input and allow custom manipulation.
This would probably make an
UpdateCamera()
function obsolete.Alternatively we could pass input information in an engine-agnostic way (enums?) to
UpdateCamera()
and handle the necessary calls internally. (This actually seems more complicated to me).
Feedback
Please let me know what you think about this design.
I have some prototyping code ready and can start preparing a PR.
Beta Was this translation helpful? Give feedback.
All reactions