new default setting to rotate to ground on paste
This commit is contained in:
@@ -390,25 +390,11 @@ void World::rotate_selected_models_randomly(float minX, float maxX, float minY,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::rotate_model_to_ground_normal(SceneObject* obj, bool smoothNormals)
|
||||||
void World::rotate_selected_models_to_ground_normal(bool smoothNormals)
|
|
||||||
{
|
{
|
||||||
ZoneScoped;
|
|
||||||
if (!_selected_model_count)
|
|
||||||
return;
|
|
||||||
selection_updated = true;
|
|
||||||
for (auto& entry : _current_selection)
|
|
||||||
{
|
|
||||||
auto type = entry.index();
|
|
||||||
if (type == eEntry_MapChunk)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& obj = std::get<selected_object_type>(entry);
|
|
||||||
NOGGIT_CUR_ACTION->registerObjectTransformed(obj);
|
NOGGIT_CUR_ACTION->registerObjectTransformed(obj);
|
||||||
|
|
||||||
updateTilesEntry(entry, model_update::remove);
|
updateTilesEntry(obj, model_update::remove);
|
||||||
|
|
||||||
glm::vec3 rayPos = obj->pos;
|
glm::vec3 rayPos = obj->pos;
|
||||||
math::degrees::vec3& dir = obj->dir;
|
math::degrees::vec3& dir = obj->dir;
|
||||||
@@ -416,43 +402,43 @@ void World::rotate_selected_models_to_ground_normal(bool smoothNormals)
|
|||||||
|
|
||||||
selection_result results;
|
selection_result results;
|
||||||
for_chunk_at(rayPos, [&](MapChunk* chunk)
|
for_chunk_at(rayPos, [&](MapChunk* chunk)
|
||||||
{
|
|
||||||
{
|
{
|
||||||
math::ray intersect_ray(rayPos, glm::vec3(0.f, -1.f, 0.f));
|
{
|
||||||
chunk->intersect(intersect_ray, &results);
|
math::ray intersect_ray(rayPos, glm::vec3(0.f, -1.f, 0.f));
|
||||||
}
|
chunk->intersect(intersect_ray, &results);
|
||||||
// object is below ground
|
}
|
||||||
if (results.empty())
|
// object is below ground
|
||||||
{
|
if (results.empty())
|
||||||
math::ray intersect_ray(rayPos, glm::vec3(0.f, 1.f, 0.f));
|
{
|
||||||
chunk->intersect(intersect_ray, &results);
|
math::ray intersect_ray(rayPos, glm::vec3(0.f, 1.f, 0.f));
|
||||||
}
|
chunk->intersect(intersect_ray, &results);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// !\ todo We shouldn't end up with empty ever (but we do, on completely flat ground)
|
// !\ todo We shouldn't end up with empty ever (but we do, on completely flat ground)
|
||||||
if (results.empty())
|
if (results.empty())
|
||||||
{
|
{
|
||||||
// just to avoid models disappearing when this happens
|
// just to avoid models disappearing when this happens
|
||||||
updateTilesEntry(entry, model_update::add);
|
updateTilesEntry(obj, model_update::add);
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// We hit the terrain, now we take the normal of this position and use it to get the rotation we want.
|
// We hit the terrain, now we take the normal of this position and use it to get the rotation we want.
|
||||||
auto const& hitChunkInfo = std::get<selected_chunk_type>(results.front().second);
|
auto const& hitChunkInfo = std::get<selected_chunk_type>(results.front().second);
|
||||||
|
|
||||||
glm::quat q;
|
glm::quat q;
|
||||||
glm::vec3 varnormal;
|
glm::vec3 varnormal;
|
||||||
|
|
||||||
// Surface Normal
|
// Surface Normal
|
||||||
auto &p0 = hitChunkInfo.chunk->mVertices[std::get<0>(hitChunkInfo.triangle)];
|
auto& p0 = hitChunkInfo.chunk->mVertices[std::get<0>(hitChunkInfo.triangle)];
|
||||||
auto &p1 = hitChunkInfo.chunk->mVertices[std::get<1>(hitChunkInfo.triangle)];
|
auto& p1 = hitChunkInfo.chunk->mVertices[std::get<1>(hitChunkInfo.triangle)];
|
||||||
auto &p2 = hitChunkInfo.chunk->mVertices[std::get<2>(hitChunkInfo.triangle)];
|
auto& p2 = hitChunkInfo.chunk->mVertices[std::get<2>(hitChunkInfo.triangle)];
|
||||||
|
|
||||||
glm::vec3 v1 = p1 - p0;
|
glm::vec3 v1 = p1 - p0;
|
||||||
glm::vec3 v2 = p2 - p0;
|
glm::vec3 v2 = p2 - p0;
|
||||||
|
|
||||||
auto tmpVec = glm::cross(v2 ,v1);
|
auto tmpVec = glm::cross(v2, v1);
|
||||||
varnormal.x = tmpVec.z;
|
varnormal.x = tmpVec.z;
|
||||||
varnormal.y = tmpVec.y;
|
varnormal.y = tmpVec.y;
|
||||||
varnormal.z = tmpVec.x;
|
varnormal.z = tmpVec.x;
|
||||||
@@ -460,34 +446,34 @@ void World::rotate_selected_models_to_ground_normal(bool smoothNormals)
|
|||||||
// Smooth option, gradient the normal towards closest vertex
|
// Smooth option, gradient the normal towards closest vertex
|
||||||
if (smoothNormals) // Vertex Normal
|
if (smoothNormals) // Vertex Normal
|
||||||
{
|
{
|
||||||
auto normalWeights = getBarycentricCoordinatesAt(p0, p1, p2, hitChunkInfo.position, varnormal);
|
auto normalWeights = getBarycentricCoordinatesAt(p0, p1, p2, hitChunkInfo.position, varnormal);
|
||||||
|
|
||||||
auto& tile_buffer = hitChunkInfo.chunk->mt->getChunkHeightmapBuffer();
|
auto& tile_buffer = hitChunkInfo.chunk->mt->getChunkHeightmapBuffer();
|
||||||
int chunk_start = (hitChunkInfo.chunk->px * 16 + hitChunkInfo.chunk->py) * mapbufsize * 4;
|
int chunk_start = (hitChunkInfo.chunk->px * 16 + hitChunkInfo.chunk->py) * mapbufsize * 4;
|
||||||
|
|
||||||
const auto& vNormal0 = *reinterpret_cast<glm::vec3*>(&tile_buffer[chunk_start + std::get<0>(hitChunkInfo.triangle) * 4]);
|
const auto& vNormal0 = *reinterpret_cast<glm::vec3*>(&tile_buffer[chunk_start + std::get<0>(hitChunkInfo.triangle) * 4]);
|
||||||
const auto& vNormal1 = *reinterpret_cast<glm::vec3*>(&tile_buffer[chunk_start + std::get<1>(hitChunkInfo.triangle) * 4]);
|
const auto& vNormal1 = *reinterpret_cast<glm::vec3*>(&tile_buffer[chunk_start + std::get<1>(hitChunkInfo.triangle) * 4]);
|
||||||
const auto& vNormal2 = *reinterpret_cast<glm::vec3*>(&tile_buffer[chunk_start + std::get<2>(hitChunkInfo.triangle) * 4]);
|
const auto& vNormal2 = *reinterpret_cast<glm::vec3*>(&tile_buffer[chunk_start + std::get<2>(hitChunkInfo.triangle) * 4]);
|
||||||
|
|
||||||
varnormal.x =
|
varnormal.x =
|
||||||
vNormal0.x * normalWeights.x +
|
vNormal0.x * normalWeights.x +
|
||||||
vNormal1.x * normalWeights.y +
|
vNormal1.x * normalWeights.y +
|
||||||
vNormal2.x * normalWeights.z;
|
vNormal2.x * normalWeights.z;
|
||||||
|
|
||||||
varnormal.y =
|
varnormal.y =
|
||||||
vNormal0.y * normalWeights.x +
|
vNormal0.y * normalWeights.x +
|
||||||
vNormal1.y * normalWeights.y +
|
vNormal1.y * normalWeights.y +
|
||||||
vNormal2.y * normalWeights.z;
|
vNormal2.y * normalWeights.z;
|
||||||
|
|
||||||
varnormal.z =
|
varnormal.z =
|
||||||
vNormal0.z * normalWeights.x +
|
vNormal0.z * normalWeights.x +
|
||||||
vNormal1.z * normalWeights.y +
|
vNormal1.z * normalWeights.y +
|
||||||
vNormal2.z * normalWeights.z;
|
vNormal2.z * normalWeights.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
glm::vec3 worldUp = glm::vec3(0, 1, 0);
|
glm::vec3 worldUp = glm::vec3(0, 1, 0);
|
||||||
glm::vec3 a =glm::cross(worldUp ,varnormal);
|
glm::vec3 a = glm::cross(worldUp, varnormal);
|
||||||
|
|
||||||
q.x = a.x;
|
q.x = a.x;
|
||||||
q.y = a.y;
|
q.y = a.y;
|
||||||
@@ -527,12 +513,31 @@ void World::rotate_selected_models_to_ground_normal(bool smoothNormals)
|
|||||||
dir.y = math::degrees(math::radians(eulerAngles.x))._; //Pitch
|
dir.y = math::degrees(math::radians(eulerAngles.x))._; //Pitch
|
||||||
dir.z = math::degrees(math::radians(eulerAngles.y))._; //Yaw
|
dir.z = math::degrees(math::radians(eulerAngles.y))._; //Yaw
|
||||||
|
|
||||||
std::get<selected_object_type>(entry)->recalcExtents();
|
obj->recalcExtents();
|
||||||
|
|
||||||
// yaw (z-axis rotation)
|
// yaw (z-axis rotation)
|
||||||
double siny_cosp = 2 * (q.w * q.z + q.x * q.y);
|
double siny_cosp = 2 * (q.w * q.z + q.x * q.y);
|
||||||
double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
|
double cosy_cosp = 1 - 2 * (q.y * q.y + q.z * q.z);
|
||||||
updateTilesEntry(entry, model_update::add);
|
updateTilesEntry(obj, model_update::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::rotate_selected_models_to_ground_normal(bool smoothNormals)
|
||||||
|
{
|
||||||
|
ZoneScoped;
|
||||||
|
if (!_selected_model_count)
|
||||||
|
return;
|
||||||
|
selection_updated = true;
|
||||||
|
for (auto& entry : _current_selection)
|
||||||
|
{
|
||||||
|
auto type = entry.index();
|
||||||
|
if (type == eEntry_MapChunk)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& obj = std::get<selected_object_type>(entry);
|
||||||
|
|
||||||
|
rotate_model_to_ground_normal(obj, smoothNormals);
|
||||||
}
|
}
|
||||||
update_selected_model_groups();
|
update_selected_model_groups();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ public:
|
|||||||
|
|
||||||
// Checks the normal of the terrain on model origin and rotates to that spot.
|
// Checks the normal of the terrain on model origin and rotates to that spot.
|
||||||
void rotate_selected_models_to_ground_normal(bool smoothNormals);
|
void rotate_selected_models_to_ground_normal(bool smoothNormals);
|
||||||
|
void rotate_model_to_ground_normal(SceneObject* obj, bool smoothNormals);
|
||||||
|
|
||||||
bool GetVertex(float x, float z, glm::vec3 *V) const;
|
bool GetVertex(float x, float z, glm::vec3 *V) const;
|
||||||
|
|
||||||
|
|||||||
@@ -203,6 +203,8 @@ namespace Noggit
|
|||||||
QRadioButton *selectionButton = new QRadioButton("Selection");
|
QRadioButton *selectionButton = new QRadioButton("Selection");
|
||||||
QRadioButton *cameraButton = new QRadioButton("Camera");
|
QRadioButton *cameraButton = new QRadioButton("Camera");
|
||||||
|
|
||||||
|
QCheckBox* paste_override_rotate_cb = new QCheckBox("Rotate to Terrain", this);
|
||||||
|
|
||||||
pasteModeGroup = new QButtonGroup(this);
|
pasteModeGroup = new QButtonGroup(this);
|
||||||
pasteModeGroup->addButton(terrainButton, 0);
|
pasteModeGroup->addButton(terrainButton, 0);
|
||||||
pasteModeGroup->addButton(selectionButton, 1);
|
pasteModeGroup->addButton(selectionButton, 1);
|
||||||
@@ -212,6 +214,8 @@ namespace Noggit
|
|||||||
paste_layout->addWidget(selectionButton, 0, 1);
|
paste_layout->addWidget(selectionButton, 0, 1);
|
||||||
paste_layout->addWidget(cameraButton, 1, 0);
|
paste_layout->addWidget(cameraButton, 1, 0);
|
||||||
|
|
||||||
|
paste_layout->addWidget(paste_override_rotate_cb, 2, 0);
|
||||||
|
|
||||||
pasteBox->addPage(pasteBox_content);
|
pasteBox->addPage(pasteBox_content);
|
||||||
|
|
||||||
auto object_movement_box (new QGroupBox("Single Selection Movement", this));
|
auto object_movement_box (new QGroupBox("Single Selection Movement", this));
|
||||||
@@ -469,6 +473,12 @@ namespace Noggit
|
|||||||
_use_median_pivot_point = b;
|
_use_median_pivot_point = b;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
paste_override_rotate_cb->setChecked(paste_params->rotate_on_terrain);
|
||||||
|
connect(paste_override_rotate_cb, &QCheckBox::stateChanged, [=](int s)
|
||||||
|
{
|
||||||
|
paste_params->rotate_on_terrain = s;
|
||||||
|
});
|
||||||
|
|
||||||
connect ( pasteModeGroup, qOverload<int> (&QButtonGroup::idClicked)
|
connect ( pasteModeGroup, qOverload<int> (&QButtonGroup::idClicked)
|
||||||
, [&] (int id)
|
, [&] (int id)
|
||||||
{
|
{
|
||||||
@@ -658,6 +668,12 @@ namespace Noggit
|
|||||||
new_obj->model->waitForChildrenLoaded();
|
new_obj->model->waitForChildrenLoaded();
|
||||||
new_obj->recalcExtents();
|
new_obj->recalcExtents();
|
||||||
|
|
||||||
|
if (paste_params->rotate_on_terrain)
|
||||||
|
{
|
||||||
|
// new_obj->pos.y = world->get_ground_height(new_obj->pos).y;// in multi select, objects aren't on the ground
|
||||||
|
world->rotate_model_to_ground_normal(new_obj, true); // always smooth?
|
||||||
|
}
|
||||||
|
|
||||||
// check if pos is valid (not in an interior) wmo group
|
// check if pos is valid (not in an interior) wmo group
|
||||||
// bool is_indoor = world->isInIndoorWmoGroup(new_obj->extents, new_obj->transformMatrix());
|
// bool is_indoor = world->isInIndoorWmoGroup(new_obj->extents, new_obj->transformMatrix());
|
||||||
bool is_indoor = false; // TODO Disabled the indoor check until non axis aligned boxes check is implemented
|
bool is_indoor = false; // TODO Disabled the indoor check until non axis aligned boxes check is implemented
|
||||||
@@ -685,6 +701,11 @@ namespace Noggit
|
|||||||
new_obj->wmo->wait_until_loaded();
|
new_obj->wmo->wait_until_loaded();
|
||||||
new_obj->wmo->waitForChildrenLoaded();
|
new_obj->wmo->waitForChildrenLoaded();
|
||||||
new_obj->recalcExtents();
|
new_obj->recalcExtents();
|
||||||
|
|
||||||
|
if (paste_params->rotate_on_terrain)
|
||||||
|
{
|
||||||
|
world->rotate_model_to_ground_normal(new_obj, true); // always smooth?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace Noggit
|
|||||||
float maxTilt = 5.f;
|
float maxTilt = 5.f;
|
||||||
float minScale = 0.9f;
|
float minScale = 0.9f;
|
||||||
float maxScale = 1.1f;
|
float maxScale = 1.1f;
|
||||||
|
bool rotate_on_terrain = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Ui
|
namespace Ui
|
||||||
|
|||||||
Reference in New Issue
Block a user