Size: 4183 bytes.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// cs/renderer/linalg/transform.cc
// Much of this file is based on:
// https://pbr-book.org/3ed-2018/Geometry_and_Transformations/Transformations

#include "cs/renderer/linalg/transform.hh"

#include "cs/renderer/geo/cross.hh"
#include "cs/renderer/geo/vector3.h"
#include "cs/renderer/linalg/matrix4x4.hh"

using m4x4 = ::cs::renderer::linalg::Matrix4x4;
using v3 = ::cs::renderer::geo::Vector3;
using ::cs::renderer::geo::cross;

namespace cs::renderer::linalg::transforms {

Transform Translate(v3 delta) {
  // clang-format off
  m4x4 m(
    1,0,0,delta.x,
    0,1,0,delta.y,
    0,0,1,delta.z,
    0,0,0,1);
  m4x4 m_inv(
    1,0,0,-delta.x,
    0,1,0,-delta.y,
    0,0,1,-delta.z,
    0,0,0,1);
  // clang-format on
  return Transform(m, m_inv);
}

Transform Scale(float x, float y, float z) {
  // clang-format off
  m4x4 m(
    x,0,0,0,
    0,y,0,0,
    0,0,z,0,
    0,0,0,1);
  m4x4 m_inv(
    1/x, 0,   0,   0,
    0,   1/y, 0,   0,
    0,   0,   1/z, 0,
    0,   0,   0,   1);
  // clang-format on
  return Transform(m, m_inv);
}

Transform RotateX(float theta_rad) {
  float sinTheta = std::sin(theta_rad);
  float cosTheta = std::cos(theta_rad);
  // clang-format off
  Matrix4x4 m(1,        0,         0, 0, 
              0, cosTheta, -sinTheta, 0,
              0, sinTheta,  cosTheta, 0,
              0,        0,         0, 1);
  // clang-format on
  return Transform(m, m.transpose());
}

Transform RotateY(float theta_rad) {
  float sinTheta = std::sin(theta_rad);
  float cosTheta = std::cos(theta_rad);
  // clang-format off
  Matrix4x4 m(
    cosTheta,   0,  sinTheta, 0, 
    0,          1,  0,        0,
    -sinTheta,  0,  cosTheta, 0,
    0,          0,  0,        1);
  // clang-format on
  return Transform(m, m.transpose());
}

Transform RotateZ(float theta_rad) {
  float sinTheta = std::sin(theta_rad);
  float cosTheta = std::cos(theta_rad);
  // clang-format off
  Matrix4x4 m(
    cosTheta, -sinTheta,  0, 0, 
    sinTheta, cosTheta,   0, 0,
    0,        0,          1, 0,
    0,        0,          0, 1);
  // clang-format on
  return Transform(m, m.transpose());
}

Transform Rotate(float theta_rad, const v3 &axis) {
  v3 a = axis.normalized();
  float sinTheta = std::sin(theta_rad);
  float cosTheta = std::cos(theta_rad);
  Matrix4x4 m;
  // Compute rotation of first basis vector
  m.data_[0][0] = a.x * a.x + (1 - a.x * a.x) * cosTheta;
  m.data_[0][1] =
      a.x * a.y * (1 - cosTheta) - a.z * sinTheta;
  m.data_[0][2] =
      a.x * a.z * (1 - cosTheta) + a.y * sinTheta;
  m.data_[0][3] = 0;

  // Compute rotations of second and third basis vectors
  m.data_[1][0] =
      a.x * a.y * (1 - cosTheta) + a.z * sinTheta;
  m.data_[1][1] = a.y * a.y + (1 - a.y * a.y) * cosTheta;
  m.data_[1][2] =
      a.y * a.z * (1 - cosTheta) - a.x * sinTheta;
  m.data_[1][3] = 0;

  m.data_[2][0] =
      a.x * a.z * (1 - cosTheta) - a.y * sinTheta;
  m.data_[2][1] =
      a.y * a.z * (1 - cosTheta) + a.x * sinTheta;
  m.data_[2][2] = a.z * a.z + (1 - a.z * a.z) * cosTheta;
  m.data_[2][3] = 0;
  return Transform(m, m.transpose());
}

Transform LookAt(p3 pos, p3 look, v3 up) {
  m4x4 cameraToWorld;
  // <<Initialize fourth column of viewing matrix>>
  cameraToWorld.data_[0][3] = pos.x;
  cameraToWorld.data_[1][3] = pos.y;
  cameraToWorld.data_[2][3] = pos.z;
  cameraToWorld.data_[3][3] = 1;
  // <<Initialize first three columns of viewing matrix>>
  v3 dir = v3(look - pos).normalized();
  v3 right = cs::renderer::geo::cross(up.normalized(), dir)
                 .normalized();
  v3 newUp =
      cs::renderer::geo::cross(dir, right).normalized();
  cameraToWorld.data_[0][0] = right.x;
  cameraToWorld.data_[1][0] = right.y;
  cameraToWorld.data_[2][0] = right.z;
  cameraToWorld.data_[3][0] = 0.;
  cameraToWorld.data_[0][1] = newUp.x;
  cameraToWorld.data_[1][1] = newUp.y;
  cameraToWorld.data_[2][1] = newUp.z;
  cameraToWorld.data_[3][1] = 0.;
  cameraToWorld.data_[0][2] = dir.x;
  cameraToWorld.data_[1][2] = dir.y;
  cameraToWorld.data_[2][2] = dir.z;
  cameraToWorld.data_[3][2] = 0.;
  return Transform(cameraToWorld.inverse().value(),
                   cameraToWorld);
}

}  // namespace cs::renderer::linalg::transforms
v0 (commit) © 2025 @p13i.io | Load balancer proxied to: cs-code-viewer-3:8080 in 4ms.