new default setting to rotate to ground on paste

This commit is contained in:
T1ti
2024-04-26 01:48:25 +02:00
parent c9ed5891a6
commit b1511fb669
4 changed files with 84 additions and 56 deletions

View File

@@ -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();
} }

View File

@@ -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;

View File

@@ -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?
}
} }
} }
} }

View File

@@ -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