mirror of
https://github.com/pret/pokeplatinum.git
synced 2026-04-25 07:29:01 -05:00
3d rendering docs
This commit is contained in:
parent
e25c7d3fd8
commit
f3aee91155
123
docs/3d_rendering.md
Normal file
123
docs/3d_rendering.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
## 3D Rendering
|
||||
The following is a brief overview and introduction to the 3D rendering system in Pokemon Platinum and how to use it.
|
||||
|
||||
## Abstraction Layers
|
||||
The lowest level 3D is interacting directly with the hardware via NitroSDK. NitroSystem provides a slight abstraction over this with `G3D`.
|
||||
|
||||
The game has 2 additional layers of abstraction over this:
|
||||
### 1 - Easy3D
|
||||
The first layer of abstraction is the Easy3D System (`easy3d.h`). Which provides basic functionality for:
|
||||
- Loading Models and Textures
|
||||
- Binding textures to models
|
||||
- Drawing models with any transform
|
||||
- Setting up and releasing a 3D graphics state
|
||||
|
||||
To elaborate on the last point: Before using any 3D graphics, a "3D Graphics State" must be initialized. The struct for this is currently called `GenericPointerData`. The Easy3D system provides an easy method to set up a simple gfx state via `Easy3D_Init` (With `Easy3D_Shutdown` as its counterpart), which works for most scenarios.
|
||||
|
||||
### 2 - Easy3DObject
|
||||
The second layer of abstraction is `Easy3DObject` (`easy3d_object.h`). This API provides a streamlined interface for:
|
||||
- Loading models, textures, and animations
|
||||
- Binding a texture to a model
|
||||
- Binding one or more animations to a model (both bone animations and texture animations)
|
||||
- Updating the objects transform (the object itself keeps track of that)
|
||||
- Updating animation state
|
||||
- Drawing objects
|
||||
- Cleanup
|
||||
|
||||
One thing to keep in mind is that this system by itself does not establish a 3D GFX State.
|
||||
This system is also not used everywhere. In a lot of places Easy3D is used directly instead of this object oriented interface.
|
||||
|
||||
## Example
|
||||
The following is an example for using the `Easy3DObject` API for:
|
||||
1. Loading a model with textures, animation, and texture animation
|
||||
2. Binding them all together
|
||||
3. Updating the animations
|
||||
4. Drawing the model
|
||||
|
||||
I will be using the Giratina model from the title screen for this.
|
||||
|
||||
### Loading the data
|
||||
The first thing needed is some static storage to hold our data:
|
||||
```c
|
||||
Easy3DObject giratinaObj;
|
||||
Easy3DModel giratinaModel;
|
||||
Easy3DAnim giratinaAnim; // Model Animation
|
||||
Easy3DAnim giratinaTexAnim; // Texture Animation
|
||||
NNSFndAllocator allocator; // Needed for Animations
|
||||
```
|
||||
Next we load all of the data:
|
||||
```c
|
||||
// Open the title NARC
|
||||
NARC *narc = NARC_ctor(NARC_INDEX_DEMO__TITLE__TITLEDEMO, HEAP_ID_FIELD);
|
||||
|
||||
// Load the model from the title screen NARC. Member index 1 is the model data.
|
||||
// There is also Easy3DModel_Load which takes a NARC index and a member index.
|
||||
Easy3DModel_LoadFrom(&giratinaModel, narc, 1, HEAP_ID_FIELD);
|
||||
Easy3DObject_Init(&giratinaObj, &giratinaModel);
|
||||
|
||||
// Initialize the Allocator used by the animations
|
||||
Heap_FndInitAllocatorForExpHeap(&allocator, HEAP_ID_FIELD, 4);
|
||||
|
||||
// Load the model animation with member index 2.
|
||||
Easy3DAnim_LoadFrom(&giratinaModelAnim, &giratinaModel, narc, 2, HEAP_ID_FIELD, &allocator);
|
||||
// Bind the animation to the object
|
||||
Easy3DObject_AddAnim(&giratinaObj, &giratinaModelAnim);
|
||||
|
||||
// Do the same for the texture animation
|
||||
Easy3DAnim_LoadFrom(&giratinaTexAnim, &giratinaModel, narc, 0, HEAP_ID_FIELD, &allocator);
|
||||
Easy3DObject_AddAnim(&giratinaObj, &giratinaTexAnim);
|
||||
|
||||
NARC_dtor(narc);
|
||||
```
|
||||
This is all that needs to be done in terms of setup, now the model is ready to draw (provided a 3D GFX State has been set up).
|
||||
|
||||
### Drawing the Model
|
||||
Before drawing there's a few things that should be configured on the object, one of them being the position of the model obviously. For simplicity's sake I will just set the models position to the player's position.
|
||||
```c
|
||||
const VecFx32 *pos = PlayerAvatar_PosVector(fieldSystem->playerAvatar);
|
||||
Easy3DObject_SetPosition(&giratinaObj, pos->x, pos->y, pos->z);
|
||||
|
||||
// Make sure the model actually gets rendered
|
||||
Easy3DObject_SetVisibility(&giratinaObj, TRUE);
|
||||
|
||||
// The model is pretty big so scale it to half its size
|
||||
Easy3DObject_SetScale(&giratinaObj, FX32_CONST(0.5), FX32_CONST(0.5), FX32_CONST(0.5));
|
||||
```
|
||||
Now we can actually render the model:
|
||||
```c
|
||||
// Update the animations
|
||||
// Here we advance the animation by one frame.
|
||||
// There is also Easy3DAnim_Update which does not loop the animation
|
||||
Easy3DAnim_UpdateLooped(&giratinaModelAnim, FX32_ONE);
|
||||
Easy3DAnim_UpdateLooped(&giratinaTexAnim, FX32_ONE);
|
||||
|
||||
// Draw the model
|
||||
Easy3DObject_Draw(&giratinaObj);
|
||||
```
|
||||
All of that results in the following:
|
||||
|
||||
https://github.com/pret/pokeplatinum/assets/60443001/ba162c62-e64a-4cd6-850f-414774f19bfd
|
||||
|
||||
Obviously the rotation and resizing is not outlined above. The code for this is the following:
|
||||
```c
|
||||
u16 angle = Easy3DObject_GetRotation(&giratinaObj, ROTATION_AXIS_Y);
|
||||
angle = (angle + 100) % 0xFFFF;
|
||||
Easy3DObject_SetRotation(&giratinaObj, angle, ROTATION_AXIS_Y);
|
||||
|
||||
// Resize using L and R
|
||||
if (gCoreSys.heldKeys & PAD_BUTTON_R) {
|
||||
VecFx32 scale;
|
||||
Easy3DObject_GetScale(&giratinaObj, &scale.x, &scale.y, &scale.z);
|
||||
scale.x = FX_Mul(scale.x, FX32_CONST(1.01));
|
||||
scale.y = FX_Mul(scale.y, FX32_CONST(1.01));
|
||||
scale.z = FX_Mul(scale.z, FX32_CONST(1.01));
|
||||
Easy3DObject_SetScale(&giratinaObj, scale.x, scale.y, scale.z);
|
||||
} else if (gCoreSys.heldKeys & PAD_BUTTON_L) {
|
||||
VecFx32 scale;
|
||||
Easy3DObject_GetScale(&giratinaObj, &scale.x, &scale.y, &scale.z);
|
||||
scale.x = FX_Mul(scale.x, FX32_CONST(0.99));
|
||||
scale.y = FX_Mul(scale.y, FX32_CONST(0.99));
|
||||
scale.z = FX_Mul(scale.z, FX32_CONST(0.99));
|
||||
Easy3DObject_SetScale(&giratinaObj, scale.x, scale.y, scale.z);
|
||||
}
|
||||
```
|
||||
Loading…
Reference in New Issue
Block a user