Select Git revision
lens.cpp 14.10 KiB
//------------------------------------------------------------------------------
// Project Phoenix
//
// Copyright (c) 2017-2018 RWTH Aachen University, Germany,
// Virtual Reality & Immersive Visualization Group.
//------------------------------------------------------------------------------
// License
//
// Licensed under the 3-Clause BSD License (the "License");
// you may not use this file except in compliance with the License.
// See the file LICENSE for the full text.
// You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//------------------------------------------------------------------------------
#include "lens.hpp"
#include <optix.h>
#include "object_manager.hpp"
#include "optix_context_manager.hpp"
#include "phx/rendering/components/transform.hpp"
#include "selection_mark_handler.hpp"
#include "selector.hpp"
#include "phx/rendering/components/material_handle.hpp"
#include "phx/resources/resource_pointer.hpp"
#include "phx/resources/resource_utils.hpp"
#include "phx/resources/types/material.hpp"
#include "phx/resources/types/model.hpp"
#include "phx/suppress_warnings.hpp"
SUPPRESS_WARNINGS_BEGIN
#include "glm/glm.hpp"
#include "glm/gtx/rotate_vector.hpp"
#include "glm/gtx/string_cast.hpp"
SUPPRESS_WARNINGS_END
Lens::Lens(phx::Engine* engine, phx::Scene* scene, OptixContextManager* manager,
LensSideType type1, LensSideType type2, optix::float3 frontCenter,
float lensradius, float thickness, float radius, float radius2) {
manager_ = manager;
scene_ = scene;
CreateGlassMaterialInstance();
geometry_ = manager->GetContext()->createGeometryInstance(
manager->GetLensGeometry(), &glass_material_, &glass_material_ + 1);
geometry_["center"]->setFloat(0, 0, 0);
geometry_["radius"]->setFloat(radius);
geometry_["radius2"]->setFloat(radius2);
geometry_["orientation"]->setFloat(optix::make_float3(0.f, 0.f, -1.f));
geometry_["lensRadius"]->setFloat(lensradius);
geometry_["side1Type"]->setInt(type1);
geometry_["side2Type"]->setInt(type2);
type_1_ = type1;
type_2_ = type2;
float cylinderLength = GetCylinderLength(thickness);
geometry_["halfCylinderLength"]->setFloat(cylinderLength / 2);
transform_ = manager->GetContext()->createTransform();
transform_->setMatrix(false, &glm::mat4()[0][0], &glm::mat4()[0][0]);
// Add the lens to the scene
geometry_group_ = manager->GetContext()->createGeometryGroup();
geometry_group_->addChild(geometry_);
acceleration_structure_ = manager->GetContext()->createAcceleration("Trbvh");
acceleration_structure_->setProperty("refit", "1");
geometry_group_->setAcceleration(acceleration_structure_);
transform_->setChild<optix::GeometryGroup>(geometry_group_);
manager->GetTopObject()->addChild(transform_);
// Attach handles
entity_ = scene->CreateEntity();
auto center =
frontCenter - optix::make_float3(0.f, 0.f, -1.f) * thickness / 2;
entity_->AddComponent<phx::Transform>()->Translate(
glm::vec3(center.x, center.y, center.z));
selector_ = entity_->AddComponent<phx::Selector>(nullptr, true);
support_rod_ = new SupportRod(scene, selector_, false);
auto obj_m = engine->GetSystem<ObjectManager>();
// Set Moving
selector_->SetMove([this, obj_m](phx::Transform* t, glm::mat4 r) {
auto pos = glm::vec3((t->GetGlobalMatrix() * r)[3]);
auto pos_proj =
glm::dot(pos - obj_m->GetCenterAxisPos(), glm::vec3(0, 0, 1)) *
glm::vec3(0, 0, 1) +
obj_m->GetCenterAxisPos();
// close enough? Then snap!
if (glm::length(pos - pos_proj) <= obj_m->GetSnapDistance()) pos = pos_proj;
entity_->GetFirstComponent<phx::Transform>()->SetGlobalTranslation(pos);
glm::mat4 trans =
entity_->GetFirstComponent<phx::Transform>()->GetGlobalMatrix();
transform_->setMatrix(true, &(trans[0][0]), &(inverse(trans)[0][0]));
support_rod_->Moved();
acceleration_structure_->markDirty();
manager_->TopAccelerationMarkDirty();
});
selector_->SetExternalUpdate([this]() {
glm::mat4 trans =
entity_->GetFirstComponent<phx::Transform>()->GetGlobalMatrix();
transform_->setMatrix(true, &(trans[0][0]), &(inverse(trans)[0][0]));
support_rod_->Moved();
acceleration_structure_->markDirty();
manager_->TopAccelerationMarkDirty();
});
// Store if grabbed
selector_->SetGrab([this](phx::Transform*, glm::mat4) { grabbed_ = true; });
selector_->SetRelease([this]() { grabbed_ = false; });
RecalculateBoundingBox();
acceleration_structure_->markDirty();
manager_->TopAccelerationMarkDirty();
}
Lens::~Lens() {
manager_->GetTopObject()->removeChild(transform_);
glass_material_->destroy();
geometry_->destroy();
geometry_group_->destroy();
transform_->destroy();
acceleration_structure_->destroy();
scene_->RemoveEntity(entity_);
delete support_rod_;
manager_->TopAccelerationMarkDirty();
}
void Lens::NextLensSideType1() {
auto s1 = geometry_["side1Type"]->getInt();
auto s2 = geometry_["side2Type"]->getInt();
s1 = (((s1 + 1) + 1) % 3) - 1;
SetLensSideTypes(static_cast<LensSideType>(s1),
static_cast<LensSideType>(s2));
}
void Lens::PreviousLensSideType1() {
auto s1 = geometry_["side1Type"]->getInt();
auto s2 = geometry_["side2Type"]->getInt();
s1 = (((s1 - 1 + 3) + 1) % 3) - 1;
SetLensSideTypes(static_cast<LensSideType>(s1),
static_cast<LensSideType>(s2));
}
void Lens::NextLensSideType2() {
auto s1 = geometry_["side1Type"]->getInt();
auto s2 = geometry_["side2Type"]->getInt();
s2 = (((s2 + 1) + 1) % 3) - 1;
SetLensSideTypes(static_cast<LensSideType>(s1),
static_cast<LensSideType>(s2));
}
void Lens::PreviousLensSideType2() {
auto s1 = geometry_["side1Type"]->getInt();
auto s2 = geometry_["side2Type"]->getInt();
s2 = (((s2 - 1 + 3) + 1) % 3) - 1;
SetLensSideTypes(static_cast<LensSideType>(s1),
static_cast<LensSideType>(s2));
}
void Lens::NextGlassType() {
glass_type_ = static_cast<GlassType>((glass_type_ + 1) % 5);
ChangedWaveLength(current_wavelength_nm_);
}
void Lens::PreviousGlassType() {
glass_type_ = static_cast<GlassType>((glass_type_ - 1 + 5) % 5);
ChangedWaveLength(current_wavelength_nm_);
}
std::string Lens::GetLensTypeName1() {
return GetTypeString(
static_cast<LensSideType>(geometry_["side1Type"]->getInt()));
}
std::string Lens::GetLensTypeName2() {
return GetTypeString(
static_cast<LensSideType>(geometry_["side2Type"]->getInt()));
}
std::string Lens::GetGlassTypeName() {
switch (glass_type_) {
case BK7:
return "BK7";
case SF5:
return "SF5";
case SF11:
return "SF11";
case FUSED_SILICA:
return "Fus.Sil.";
case SK16:
return "SK16";
case F2:
return "F2";
}
return "Unknown";
}
void Lens::Translate(glm::vec3 pos) {
GetEntity()->GetFirstComponent<phx::Transform>()->SetGlobalTranslation(pos);
selector_->ExternalUpdate();
}
void Lens::SetSelected(bool s) { support_rod_->SetMarked(s); }
void Lens::ChangedWaveLength(float wavelength_nm) {
double wl2 = glm::pow(wavelength_nm / 1000.0, 2);
float index = (float)sqrt(1 +
(glass_definitions[glass_type_][0].x * wl2) /
(wl2 - glass_definitions[glass_type_][1].x) +
(glass_definitions[glass_type_][0].y * wl2) /
(wl2 - glass_definitions[glass_type_][1].y) +
(glass_definitions[glass_type_][0].z * wl2) /
(wl2 - glass_definitions[glass_type_][1].z));
glass_material_["refraction_index"]->setFloat(index);
current_wavelength_nm_ = wavelength_nm;
}
std::array<glm::vec3, 2u> Lens::ComputeAABBFromCylinder(glm::vec3 orientation,
float halfLength1,
float halfLength2,
float radius) {
auto res = std::array<glm::vec3, 2u>();
glm::vec3 sideVector =
normalize(cross(orientation, glm::vec3(0.0f, 1.0f, 0.0f)));
glm::vec3 newUp = normalize(cross(sideVector, orientation));
sideVector = sideVector * radius;
newUp = newUp * radius;
glm::vec3 depthVector = normalize(orientation);
res[0] = glm::vec3(INFINITY);
res[1] = glm::vec3(-INFINITY);
glm::vec3 testVector = glm::vec3(0.0f);
testVector = depthVector * halfLength1 + sideVector + newUp;
res[1] = glm::max(res[1], testVector);
res[0] = glm::min(res[0], testVector);
testVector = depthVector * halfLength1 + sideVector - newUp;
res[1] = glm::max(res[1], testVector);
res[0] = glm::min(res[0], testVector);
testVector = depthVector * halfLength1 - sideVector + newUp;
res[1] = glm::max(res[1], testVector);
res[0] = glm::min(res[0], testVector);
testVector = depthVector * halfLength1 - sideVector - newUp;
res[1] = glm::max(res[1], testVector);
res[0] = glm::min(res[0], testVector);
testVector = -depthVector * halfLength2 + sideVector + newUp;
res[1] = glm::max(res[1], testVector);
res[0] = glm::min(res[0], testVector);
testVector = -depthVector * halfLength2 + sideVector - newUp;
res[1] = glm::max(res[1], testVector);
res[0] = glm::min(res[0], testVector);
testVector = -depthVector * halfLength2 - sideVector + newUp;
res[1] = glm::max(res[1], testVector);
res[0] = glm::min(res[0], testVector);
testVector = -depthVector * halfLength2 - sideVector - newUp;
res[1] = glm::max(res[1], testVector);
res[0] = glm::min(res[0], testVector);
return res;
}
glm::vec3 Lens::GetFrontCenter() {
return entity_->GetFirstComponent<phx::Transform>()->GetGlobalTranslation() +
glm::mat3(
entity_->GetFirstComponent<phx::Transform>()->GetGlobalMatrix()) *
glm::vec3(0.f, 0.f, -1.f) * GetThickness() / 2.0f;
}
glm::vec2 Lens::GetRotation() {
auto mat = entity_->GetFirstComponent<phx::Transform>()->GetGlobalMatrix();
glm::vec3 up = normalize(glm::mat3(mat) * glm::vec3(0, 1, 0));
glm::vec3 right = normalize(glm::mat3(mat) * glm::vec3(1, 0, 0));
float angle_horizontal = -glm::atan(right.z, right.x);
auto position_YZ = glm::rotateY(up, -angle_horizontal);
float angle_vertical =
-glm::atan(position_YZ.y, position_YZ.z) + glm::pi<float>() / 2;
return glm::vec2(angle_horizontal, angle_vertical);
}
float Lens::GetCylinderLength(float thickness) {
float lr = geometry_["lensRadius"]->getFloat();
float r1 = geometry_["radius"]->getFloat();
float r2 = geometry_["radius2"]->getFloat();
// thickness of the halfspheres
float halfThickness1 = r1 - sqrtf(-lr * lr + r1 * r1);
if (type_1_ == CONCAVE) halfThickness1 *= -1;
if (type_1_ == PLANE) halfThickness1 = 0;
float halfThickness2 = r2 - sqrtf(-lr * lr + r2 * r2);
if (type_2_ == CONCAVE) halfThickness2 *= -1;
if (type_2_ == PLANE) halfThickness2 = 0;
return thickness - halfThickness1 - halfThickness2;
}
float Lens::GetThickness(float cylinder_length) {
float lr = geometry_["lensRadius"]->getFloat();
float r1 = geometry_["radius"]->getFloat();
float r2 = geometry_["radius2"]->getFloat();
// thickness of the halfspheres
float halfThickness1 = r1 - sqrtf(-lr * lr + r1 * r1);
if (type_1_ == CONCAVE) halfThickness1 *= -1;
if (type_1_ == PLANE) halfThickness1 = 0;
float halfThickness2 = r2 - sqrtf(-lr * lr + r2 * r2);
if (type_2_ == CONCAVE) halfThickness2 *= -1;
if (type_2_ == PLANE) halfThickness2 = 0;
return cylinder_length + halfThickness1 + halfThickness2;
}
void Lens::SetLensSideTypes(LensSideType type1, LensSideType type2) {
float thickness =
GetThickness(geometry_["halfCylinderLength"]->getFloat() * 2);
geometry_["side1Type"]->setInt(type1);
geometry_["side2Type"]->setInt(type2);
type_1_ = type1;
type_2_ = type2;
geometry_["halfCylinderLength"]->setFloat(GetCylinderLength(thickness) / 2);
MarkDirty();
}
void Lens::RecalculateBoundingBox() {
auto o = geometry_["orientation"]->getFloat3();
float hc = geometry_["halfCylinderLength"]->getFloat();
float lr = geometry_["lensRadius"]->getFloat();
float r1 = geometry_["radius"]->getFloat();
float r2 = geometry_["radius2"]->getFloat();
// thickness of the halfspheres
float halfThickness1 = r1 - sqrtf(-lr * lr + r1 * r1);
if (type_1_ == PLANE || type_1_ == CONCAVE) halfThickness1 = 0;
float halfThickness2 = r2 - sqrtf(-lr * lr + r2 * r2);
if (type_2_ == PLANE || type_2_ == CONCAVE) halfThickness2 = 0;
auto bb = ComputeAABBFromCylinder(
glm::vec3(o.x, o.y, o.z), hc + halfThickness1, hc + halfThickness2, lr);
selector_->SetCollider(bb[0], bb[1]);
selector_->ExternalUpdate();
}
std::string Lens::GetTypeString(LensSideType t) {
switch (t) {
case CONCAVE:
return "Concave";
case CONVEX:
return "Convex";
case PLANE:
return "Plane";
}
return "Unknown";
}
void Lens::CreateGlassMaterialInstance() {
glass_material_ = manager_->GetContext()->createMaterial();
glass_material_->setClosestHitProgram(0,
manager_->GetGlassProgramPerspective());
glass_material_->setClosestHitProgram(1,
manager_->GetGlassProgramIterative());
glass_material_["importance_cutoff"]->setFloat(1e-2f);
glass_material_["cutoff_color"]->setFloat(0.035f, 0.102f, 0.169f);
glass_material_["fresnel_exponent"]->setFloat(3.0f);
glass_material_["fresnel_minimum"]->setFloat(0.1f);
glass_material_["fresnel_maximum"]->setFloat(1.0f);
glass_material_["refraction_index"]->setFloat(1.4f);
glass_material_["refraction_color"]->setFloat(1.0f, 1.0f, 1.0f);
glass_material_["reflection_color"]->setFloat(1.0f, 1.0f, 1.0f);
glass_material_["refraction_maxdepth"]->setInt(10);
glass_material_["reflection_maxdepth"]->setInt(5);
glass_material_["extinction_constant"]->setFloat(log(0.83f), log(0.83f),
log(0.83f));
}