shape.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * DoRayMe - a quick and dirty Raytracer
  3. * Object implementation
  4. *
  5. * Created by Manoël Trapier
  6. * Copyright (c) 2020 986-Studio.
  7. *
  8. */
  9. #include <ray.h>
  10. #include <shape.h>
  11. #include <matrix.h>
  12. #include <tuple.h>
  13. #include <intersect.h>
  14. Shape::Shape(ShapeType type)
  15. {
  16. this->objectId = Shape::newObjectId();
  17. this->locked = false;
  18. this->parent = nullptr;
  19. this->dropShadow = true;
  20. this->type = type;
  21. this->localTransformMatrix = Matrix4().identity();
  22. this->materialSet = false;
  23. this->updateTransform();
  24. }
  25. uint64_t Shape::newObjectId()
  26. {
  27. static uint64_t id = 0;
  28. uint64_t ret;
  29. ret = id++;
  30. return ret;
  31. }
  32. Tuple Shape::normalToWorld(Tuple normalVector)
  33. {
  34. Tuple world_normal = this->transposedInverseTransform * normalVector;
  35. /* W may get wrong, so hack it. This is perfectly normal as we are using a 4x4 matrix instead of a 3x3 */
  36. world_normal.w = 0;
  37. return world_normal.normalise();
  38. };
  39. Tuple Shape::normalAt(Tuple point, Intersection *hit)
  40. {
  41. Tuple local_point = this->worldToObject(point);
  42. Tuple local_normal = this->localNormalAt(local_point, hit);
  43. Tuple world_normal = this->normalToWorld(local_normal);
  44. return world_normal;
  45. }
  46. void Shape::updateTransform()
  47. {
  48. if (this->locked) return;
  49. this->transformMatrix = this->localTransformMatrix;
  50. if (this->parent != nullptr)
  51. {
  52. this->transformMatrix = this->parent->transformMatrix * this->transformMatrix;
  53. }
  54. this->inverseTransform = this->transformMatrix.inverse();
  55. this->transposedInverseTransform = this->inverseTransform.transpose();
  56. }
  57. void Shape::setTransform(Matrix transform)
  58. {
  59. if (this->locked) return;
  60. this->localTransformMatrix = transform;
  61. this->updateTransform();
  62. }
  63. BoundingBox Shape::getLocalBounds()
  64. {
  65. return BoundingBox(Point(-1, -1, -1), Point(1,1,1));
  66. }
  67. BoundingBox Shape::getBounds()
  68. {
  69. BoundingBox ret;
  70. BoundingBox me = this->getLocalBounds();
  71. ret | this->objectToWorld(Point(me.min.x, me.min.y, me.min.z));
  72. ret | this->objectToWorld(Point(me.min.x, me.min.y, me.max.z));
  73. ret | this->objectToWorld(Point(me.min.x, me.max.y, me.min.z));
  74. ret | this->objectToWorld(Point(me.max.x, me.min.y, me.min.z));
  75. ret | this->objectToWorld(Point(me.max.x, me.max.y, me.min.z));
  76. ret | this->objectToWorld(Point(me.max.x, me.min.y, me.max.z));
  77. ret | this->objectToWorld(Point(me.min.x, me.max.y, me.max.z));
  78. ret | this->objectToWorld(Point(me.max.x, me.max.y, me.max.z));
  79. return ret;
  80. }
  81. Material *Shape::getMaterial()
  82. {
  83. Shape *s = this;
  84. while((!s->materialSet) && (s->parent != nullptr))
  85. {
  86. s = s->parent;
  87. }
  88. return &s->material;
  89. }
  90. void Shape::dumpMe(FILE *fp)
  91. {
  92. if (this->materialSet)
  93. {
  94. fprintf(fp, "\"Material\": {\n");
  95. this->material.dumpMe(fp);
  96. fprintf(fp, "},\n");
  97. }
  98. fprintf(fp, "\"DropShadow\": %d,\n", this->dropShadow);
  99. fprintf(fp, "\"Locked\": %d,\n", this->locked);
  100. fprintf(fp, "\"MaterialSet\": %d,\n", this->materialSet);
  101. if (this->haveFiniteBounds())
  102. {
  103. fprintf(fp, "\"BoundingBox\": {\n");
  104. this->getBounds().dumpMe(fp);
  105. fprintf(fp, "},\n");
  106. }
  107. fprintf(fp, "\"id\": %ld,\n", this->getObjectId());
  108. if (this->parent)
  109. {
  110. fprintf(fp, "\"parentId\": %ld,\n", this->parent->getObjectId());
  111. }
  112. }