webgpu-app/src/camera.cpp

152 lines
3.7 KiB
C++

#include "directxmath/DirectXMath.h"
#include "camera.h"
struct CameraState {
XMFLOAT3 eye;
XMFLOAT3 look;
XMFLOAT3 up;
float yaw;
float pitch;
float fov;
XMFLOAT3 light_position;
};
struct ViewState {
XMFLOAT4X4 viewProj;
XMFLOAT4X4 lightViewProj;
XMFLOAT4 lightPosition;
XMFLOAT4 eyePosition;
};
static inline XMMATRIX camera_view(CameraState const * state)
{
XMMATRIX view = XMMatrixLookToRH(XMLoadFloat3(&state->eye),
XMLoadFloat3(&state->look),
XMLoadFloat3(&state->up));
return view;
}
static inline XMMATRIX camera_projection(CameraState const * state, float aspect)
{
float near_z = 0.01;
float far_z = 1000.0;
XMMATRIX projection = XMMatrixPerspectiveFovRH(state->fov,
aspect,
near_z,
far_z);
return projection;
};
extern "C" void log(float x);
static inline float min(float a, float b)
{
return a < b ? a : b;
}
static inline float max(float a, float b)
{
return a > b ? a : b;
}
static inline float fract(float a)
{
return a - __builtin_floorf(a);
}
void camera_move(CameraState * state,
int lu, int ll, int ld, int lr,
int lal, int lar,
int ru, int rl, int rd, int rr)
{
const float linearSpeed = 0.3;
const float rotationalSpeed = 0.025;
XMFLOAT3 move = {0, 0, 0};
if (ll)
move.x -= 1.0;
if (lr)
move.x += 1.0;
if (lu)
move.z -= 1.0;
if (ld)
move.z += 1.0;
if (lal)
move.y += 1.0;
if (lar)
move.y -= 1.0;
//XMStoreFloat3(&move, XMVector3Normalize(XMLoadFloat3(&move)));
if (rl)
state->yaw += rotationalSpeed;
if (rr)
state->yaw -= rotationalSpeed;
if (ru)
state->pitch += rotationalSpeed;
if (rd)
state->pitch -= rotationalSpeed;
state->pitch = min(state->pitch, XM_PIDIV2 * 0.9);
state->pitch = max(state->pitch, -XM_PIDIV2 * 0.9);
state->yaw = fract(state->yaw * (1.0f / XM_2PI)) * XM_2PI;
float sinyaw;
float cosyaw;
XMScalarSinCos(&sinyaw, &cosyaw, state->yaw);
// eye
float x = move.x * -cosyaw - move.z * sinyaw;
float y = move.y;
float z = move.x * sinyaw - move.z * cosyaw;
state->eye.x += x * linearSpeed;
state->eye.y += y * linearSpeed;
state->eye.z += z * linearSpeed;
// look
float sinpitch;
float cospitch;
XMScalarSinCos(&sinpitch, &cospitch, state->pitch);
state->look.x = cospitch * sinyaw;
state->look.y = sinpitch;
state->look.z = cospitch * cosyaw;
}
void camera_init(CameraState * camera_state)
{
camera_state->fov = XMConvertToRadians(45 * 1.5);
camera_state->yaw = XM_PI;
camera_state->pitch = 0.0f;
camera_state->up = {0, 1, 0};
camera_state->look = {0, 0, -1};
camera_state->eye = {0, 0, 5};
camera_state->light_position = {10, 10, 10};
}
void camera_view_projection(CameraState * camera_state,
ViewState * view_state,
float aspect)
{
XMVECTOR light_position = XMLoadFloat3(&camera_state->light_position);
light_position = XMVector3Transform(light_position, XMMatrixRotationY(0.025));
XMStoreFloat3(&camera_state->light_position, light_position);
XMMATRIX view = camera_view(camera_state);
XMMATRIX projection = camera_projection(camera_state, aspect);
XMMATRIX view_projection = view * projection;
XMMATRIX light_world = XMMatrixTranslationFromVector(light_position);
XMStoreFloat4x4(&view_state->viewProj, view_projection);
XMStoreFloat4x4(&view_state->lightViewProj, light_world * view_projection);
XMStoreFloat4(&view_state->lightPosition, light_position);
XMStoreFloat4(&view_state->eyePosition, XMLoadFloat3(&camera_state->eye));
}