mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-29 18:42:55 +02:00
Merge pull request #6621 from samcake/controllers
Fixing the Collision Geometry display
This commit is contained in:
commit
ff49ed7a65
11 changed files with 443 additions and 190 deletions
|
@ -106,6 +106,7 @@ public:
|
||||||
bool setAttribute(Slot slot, Frequency frequency = PER_VERTEX);
|
bool setAttribute(Slot slot, Frequency frequency = PER_VERTEX);
|
||||||
bool setAttribute(Slot slot, Slot channel, Frequency frequency = PER_VERTEX);
|
bool setAttribute(Slot slot, Slot channel, Frequency frequency = PER_VERTEX);
|
||||||
|
|
||||||
|
bool hasAttribute(Slot slot) const { return (_attributes.find(slot) != _attributes.end()); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AttributeMap _attributes;
|
AttributeMap _attributes;
|
||||||
|
|
|
@ -92,7 +92,7 @@ void Mesh::setPartBuffer(const BufferView& buffer) {
|
||||||
_partBuffer = buffer;
|
_partBuffer = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Box Mesh::evalPartBound(int partNum) const {
|
Box Mesh::evalPartBound(int partNum) const {
|
||||||
Box box;
|
Box box;
|
||||||
if (partNum < _partBuffer.getNum<Part>()) {
|
if (partNum < _partBuffer.getNum<Part>()) {
|
||||||
const Part& part = _partBuffer.get<Part>(partNum);
|
const Part& part = _partBuffer.get<Part>(partNum);
|
||||||
|
@ -111,7 +111,7 @@ const Box Mesh::evalPartBound(int partNum) const {
|
||||||
return box;
|
return box;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const {
|
Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const {
|
||||||
Box totalBound;
|
Box totalBound;
|
||||||
auto part = _partBuffer.cbegin<Part>() + partStart;
|
auto part = _partBuffer.cbegin<Part>() + partStart;
|
||||||
auto partItEnd = _partBuffer.cbegin<Part>() + partEnd;
|
auto partItEnd = _partBuffer.cbegin<Part>() + partEnd;
|
||||||
|
|
|
@ -107,10 +107,10 @@ public:
|
||||||
uint getNumParts() const { return _partBuffer.getNumElements(); }
|
uint getNumParts() const { return _partBuffer.getNumElements(); }
|
||||||
|
|
||||||
// evaluate the bounding box of A part
|
// evaluate the bounding box of A part
|
||||||
const Box evalPartBound(int partNum) const;
|
Box evalPartBound(int partNum) const;
|
||||||
// evaluate the bounding boxes of the parts in the range [start, end[ and fill the bounds parameter
|
// evaluate the bounding boxes of the parts in the range [start, end[ and fill the bounds parameter
|
||||||
// the returned box is the bounding box of ALL the evaluated part bounds.
|
// the returned box is the bounding box of ALL the evaluated part bounds.
|
||||||
const Box evalPartBounds(int partStart, int partEnd, Boxes& bounds) const;
|
Box evalPartBounds(int partStart, int partEnd, Boxes& bounds) const;
|
||||||
|
|
||||||
static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast<gpu::Primitive>(topo); }
|
static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast<gpu::Primitive>(topo); }
|
||||||
|
|
||||||
|
|
|
@ -39,55 +39,40 @@ namespace render {
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex,
|
MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) {
|
||||||
glm::vec3 position, glm::quat orientation) :
|
|
||||||
model(model),
|
updateMeshPart(mesh, partIndex);
|
||||||
meshIndex(meshIndex),
|
updateMaterial(material);
|
||||||
partIndex(partIndex),
|
updateTransform(transform, offsetTransform);
|
||||||
_shapeID(shapeIndex),
|
|
||||||
_modelPosition(position),
|
|
||||||
_modelOrientation(orientation) {
|
|
||||||
initCache();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::initCache() {
|
void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) {
|
||||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
|
_drawMesh = drawMesh;
|
||||||
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
|
if (_drawMesh) {
|
||||||
_drawMesh = networkMesh._mesh;
|
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||||
|
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||||
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
|
|
||||||
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
|
||||||
_hasColorAttrib = !mesh.colors.isEmpty();
|
|
||||||
_isBlendShaped = !mesh.blendshapes.isEmpty();
|
|
||||||
_isSkinned = !mesh.clusterIndices.isEmpty();
|
|
||||||
|
|
||||||
|
|
||||||
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||||
|
|
||||||
auto networkMaterial = model->_geometry->getShapeMaterial(_shapeID);
|
_localBound = _drawMesh->evalPartBound(partIndex);
|
||||||
if (networkMaterial) {
|
}
|
||||||
_drawMaterial = networkMaterial->_material;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::updateModelLocation(glm::vec3 position, glm::quat orientation) {
|
void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) {
|
||||||
_modelPosition = position;
|
_transform = transform;
|
||||||
_modelOrientation = orientation;
|
_offsetTransform = offsetTransform;
|
||||||
|
Transform::mult(_drawTransform, _transform, _offsetTransform);
|
||||||
|
_worldBound = _localBound;
|
||||||
|
_worldBound.transform(_drawTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) {
|
||||||
|
_drawMaterial = drawMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
render::ItemKey MeshPartPayload::getKey() const {
|
render::ItemKey MeshPartPayload::getKey() const {
|
||||||
ItemKey::Builder builder;
|
ItemKey::Builder builder;
|
||||||
builder.withTypeShape();
|
builder.withTypeShape();
|
||||||
|
|
||||||
if (!model->isVisible()) {
|
|
||||||
builder.withInvisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_isBlendShaped || _isSkinned) {
|
|
||||||
builder.withDeformed();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_drawMaterial) {
|
if (_drawMaterial) {
|
||||||
auto matKey = _drawMaterial->getKey();
|
auto matKey = _drawMaterial->getKey();
|
||||||
if (matKey.isTransparent() || matKey.isTransparentMap()) {
|
if (matKey.isTransparent() || matKey.isTransparentMap()) {
|
||||||
|
@ -99,9 +84,7 @@ render::ItemKey MeshPartPayload::getKey() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
render::Item::Bound MeshPartPayload::getBound() const {
|
render::Item::Bound MeshPartPayload::getBound() const {
|
||||||
// NOTE: we can't cache this bounds because we need to handle the case of a moving
|
return _worldBound;
|
||||||
// entity or mesh part.
|
|
||||||
return model->getPartBounds(meshIndex, partIndex, _modelPosition, _modelOrientation);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
||||||
|
@ -109,21 +92,11 @@ void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||||
if (!_isBlendShaped) {
|
|
||||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||||
|
|
||||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||||
|
|
||||||
batch.setInputStream(0, _drawMesh->getVertexStream());
|
batch.setInputStream(0, _drawMesh->getVertexStream());
|
||||||
} else {
|
|
||||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
|
||||||
|
|
||||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
|
||||||
|
|
||||||
batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
|
|
||||||
batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
|
|
||||||
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Get rid of that extra call
|
// TODO: Get rid of that extra call
|
||||||
if (!_hasColorAttrib) {
|
if (!_hasColorAttrib) {
|
||||||
|
@ -215,31 +188,208 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
||||||
// Still relying on the raw data from the model
|
batch.setModelTransform(_drawTransform);
|
||||||
const Model::MeshState& state = model->_meshStates.at(meshIndex);
|
|
||||||
|
|
||||||
Transform transform;
|
|
||||||
if (state.clusterBuffer) {
|
|
||||||
if (model->_cauterizeBones) {
|
|
||||||
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.cauterizedClusterBuffer);
|
|
||||||
} else {
|
|
||||||
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (model->_cauterizeBones) {
|
|
||||||
transform = Transform(state.cauterizedClusterMatrices[0]);
|
|
||||||
} else {
|
|
||||||
transform = Transform(state.clusterMatrices[0]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transform.preTranslate(_modelPosition);
|
|
||||||
batch.setModelTransform(transform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void MeshPartPayload::render(RenderArgs* args) const {
|
void MeshPartPayload::render(RenderArgs* args) const {
|
||||||
PerformanceTimer perfTimer("MeshPartPayload::render");
|
PerformanceTimer perfTimer("MeshPartPayload::render");
|
||||||
if (!model->_readyWhenAdded || !model->_isVisible) {
|
|
||||||
|
|
||||||
|
gpu::Batch& batch = *(args->_batch);
|
||||||
|
auto mode = args->_renderMode;
|
||||||
|
|
||||||
|
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
||||||
|
|
||||||
|
model::MaterialKey drawMaterialKey;
|
||||||
|
if (_drawMaterial) {
|
||||||
|
drawMaterialKey = _drawMaterial->getKey();
|
||||||
|
}
|
||||||
|
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
|
||||||
|
|
||||||
|
bool hasTangents = drawMaterialKey.isNormalMap();
|
||||||
|
bool hasSpecular = drawMaterialKey.isGlossMap();
|
||||||
|
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
||||||
|
bool isSkinned = false;
|
||||||
|
bool wireframe = false;
|
||||||
|
if (wireframe) {
|
||||||
|
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelRender::Locations* locations = nullptr;
|
||||||
|
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||||
|
args, locations);
|
||||||
|
|
||||||
|
|
||||||
|
// Bind the model transform and the skinCLusterMatrices if needed
|
||||||
|
bindTransform(batch, locations);
|
||||||
|
|
||||||
|
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||||
|
bindMesh(batch);
|
||||||
|
|
||||||
|
// apply material properties
|
||||||
|
bindMaterial(batch, locations);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: We should be able to do that just in the renderTransparentJob
|
||||||
|
if (translucentMesh && locations->lightBufferUnit >= 0) {
|
||||||
|
PerformanceTimer perfTimer("DLE->setupTransparent()");
|
||||||
|
|
||||||
|
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
|
||||||
|
}
|
||||||
|
if (args) {
|
||||||
|
args->_details._materialSwitches++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw!
|
||||||
|
{
|
||||||
|
PerformanceTimer perfTimer("batch.drawIndexed()");
|
||||||
|
drawCall(batch);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args) {
|
||||||
|
const int INDICES_PER_TRIANGLE = 3;
|
||||||
|
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) {
|
||||||
|
if (payload) {
|
||||||
|
return payload->getKey();
|
||||||
|
}
|
||||||
|
// Return opaque for lack of a better idea
|
||||||
|
return ItemKey::Builder::opaqueShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) {
|
||||||
|
if (payload) {
|
||||||
|
return payload->getBound();
|
||||||
|
}
|
||||||
|
return render::Item::Bound();
|
||||||
|
}
|
||||||
|
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
|
||||||
|
return payload->render(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
|
||||||
|
_model(model),
|
||||||
|
_meshIndex(_meshIndex),
|
||||||
|
_shapeID(shapeIndex) {
|
||||||
|
auto& modelMesh = _model->_geometry->getMeshes().at(_meshIndex)->_mesh;
|
||||||
|
updateMeshPart(modelMesh, partIndex);
|
||||||
|
|
||||||
|
updateTransform(transform, offsetTransform);
|
||||||
|
initCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelMeshPartPayload::initCache() {
|
||||||
|
if (_drawMesh) {
|
||||||
|
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||||
|
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||||
|
_isSkinned = vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX);
|
||||||
|
|
||||||
|
|
||||||
|
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
|
||||||
|
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
|
||||||
|
_isBlendShaped = !mesh.blendshapes.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto networkMaterial = _model->_geometry->getShapeMaterial(_shapeID);
|
||||||
|
if (networkMaterial) {
|
||||||
|
_drawMaterial = networkMaterial->_material;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ModelMeshPartPayload::notifyLocationChanged() {
|
||||||
|
_model->_needsUpdateClusterMatrices = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
render::ItemKey ModelMeshPartPayload::getKey() const {
|
||||||
|
ItemKey::Builder builder;
|
||||||
|
builder.withTypeShape();
|
||||||
|
|
||||||
|
if (!_model->isVisible()) {
|
||||||
|
builder.withInvisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isBlendShaped || _isSkinned) {
|
||||||
|
builder.withDeformed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_drawMaterial) {
|
||||||
|
auto matKey = _drawMaterial->getKey();
|
||||||
|
if (matKey.isTransparent() || matKey.isTransparentMap()) {
|
||||||
|
builder.withTransparent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
render::Item::Bound ModelMeshPartPayload::getBound() const {
|
||||||
|
// NOTE: we can't cache this bounds because we need to handle the case of a moving
|
||||||
|
// entity or mesh part.
|
||||||
|
return _model->getPartBounds(_meshIndex, _partIndex, _transform.getTranslation(), _transform.getRotation());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||||
|
if (!_isBlendShaped) {
|
||||||
|
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||||
|
|
||||||
|
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||||
|
|
||||||
|
batch.setInputStream(0, _drawMesh->getVertexStream());
|
||||||
|
} else {
|
||||||
|
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||||
|
|
||||||
|
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||||
|
|
||||||
|
batch.setInputBuffer(0, _model->_blendedVertexBuffers[_meshIndex], 0, sizeof(glm::vec3));
|
||||||
|
batch.setInputBuffer(1, _model->_blendedVertexBuffers[_meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
|
||||||
|
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Get rid of that extra call
|
||||||
|
if (!_hasColorAttrib) {
|
||||||
|
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
||||||
|
// Still relying on the raw data from the model
|
||||||
|
const Model::MeshState& state = _model->_meshStates.at(_meshIndex);
|
||||||
|
|
||||||
|
Transform transform;
|
||||||
|
if (state.clusterBuffer) {
|
||||||
|
if (_model->_cauterizeBones) {
|
||||||
|
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.cauterizedClusterBuffer);
|
||||||
|
} else {
|
||||||
|
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (_model->_cauterizeBones) {
|
||||||
|
transform = Transform(state.cauterizedClusterMatrices[0]);
|
||||||
|
} else {
|
||||||
|
transform = Transform(state.clusterMatrices[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// transform.preTranslate(_modelPosition);
|
||||||
|
transform.preTranslate(_transform.getTranslation());
|
||||||
|
batch.setModelTransform(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
|
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
|
||||||
|
if (!_model->_readyWhenAdded || !_model->_isVisible) {
|
||||||
return; // bail asap
|
return; // bail asap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,25 +398,25 @@ void MeshPartPayload::render(RenderArgs* args) const {
|
||||||
|
|
||||||
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
||||||
|
|
||||||
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
|
||||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
|
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
|
||||||
|
|
||||||
// guard against partially loaded meshes
|
// guard against partially loaded meshes
|
||||||
if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)model->_meshStates.size() ) {
|
if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Back to model to update the cluster matrices right now
|
// Back to model to update the cluster matrices right now
|
||||||
model->updateClusterMatrices(_modelPosition, _modelOrientation);
|
_model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation());
|
||||||
|
|
||||||
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
|
||||||
|
|
||||||
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
|
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
|
||||||
// to false to rebuild out mesh groups.
|
// to false to rebuild out mesh groups.
|
||||||
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) {
|
if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) {
|
||||||
model->_meshGroupsKnown = false; // regenerate these lists next time around.
|
_model->_meshGroupsKnown = false; // regenerate these lists next time around.
|
||||||
model->_readyWhenAdded = false; // in case any of our users are using scenes
|
_model->_readyWhenAdded = false; // in case any of our users are using scenes
|
||||||
model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
|
_model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
|
||||||
return; // FIXME!
|
return; // FIXME!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,12 +427,6 @@ void MeshPartPayload::render(RenderArgs* args) const {
|
||||||
return; // FIXME!
|
return; // FIXME!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// guard against partially loaded meshes
|
|
||||||
if (partIndex >= mesh.parts.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
model::MaterialKey drawMaterialKey;
|
model::MaterialKey drawMaterialKey;
|
||||||
if (_drawMaterial) {
|
if (_drawMaterial) {
|
||||||
drawMaterialKey = _drawMaterial->getKey();
|
drawMaterialKey = _drawMaterial->getKey();
|
||||||
|
@ -293,12 +437,12 @@ void MeshPartPayload::render(RenderArgs* args) const {
|
||||||
bool hasSpecular = drawMaterialKey.isGlossMap();
|
bool hasSpecular = drawMaterialKey.isGlossMap();
|
||||||
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
||||||
bool isSkinned = _isSkinned;
|
bool isSkinned = _isSkinned;
|
||||||
bool wireframe = model->isWireframe();
|
bool wireframe = _model->isWireframe();
|
||||||
|
|
||||||
// render the part bounding box
|
// render the part bounding box
|
||||||
#ifdef DEBUG_BOUNDING_PARTS
|
#ifdef DEBUG_BOUNDING_PARTS
|
||||||
{
|
{
|
||||||
AABox partBounds = getPartBounds(meshIndex, partIndex);
|
AABox partBounds = getPartBounds(_meshIndex, partIndex);
|
||||||
bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE;
|
bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE;
|
||||||
|
|
||||||
glm::vec4 cubeColor;
|
glm::vec4 cubeColor;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// MeshPartPayload.h
|
// ModelMeshPartPayload.h
|
||||||
// interface/src/renderer
|
// interface/src/renderer
|
||||||
//
|
//
|
||||||
// Created by Sam Gateau on 10/3/15.
|
// Created by Sam Gateau on 10/3/15.
|
||||||
|
@ -24,41 +24,44 @@ class Model;
|
||||||
|
|
||||||
class MeshPartPayload {
|
class MeshPartPayload {
|
||||||
public:
|
public:
|
||||||
MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, glm::vec3 position, glm::quat orientation);
|
MeshPartPayload() {}
|
||||||
|
MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform);
|
||||||
|
|
||||||
typedef render::Payload<MeshPartPayload> Payload;
|
typedef render::Payload<MeshPartPayload> Payload;
|
||||||
typedef Payload::DataPointer Pointer;
|
typedef Payload::DataPointer Pointer;
|
||||||
|
|
||||||
Model* model;
|
virtual void updateMeshPart(model::MeshPointer drawMesh, int partIndex);
|
||||||
int meshIndex;
|
|
||||||
int partIndex;
|
|
||||||
int _shapeID;
|
|
||||||
glm::vec3 _modelPosition;
|
|
||||||
glm::quat _modelOrientation;
|
|
||||||
|
|
||||||
void updateModelLocation(glm::vec3 position, glm::quat orientation);
|
virtual void notifyLocationChanged() {}
|
||||||
|
virtual void updateTransform(const Transform& transform, const Transform& offsetTransform);
|
||||||
|
|
||||||
|
virtual void updateMaterial(model::MaterialPointer drawMaterial);
|
||||||
|
|
||||||
// Render Item interface
|
// Render Item interface
|
||||||
render::ItemKey getKey() const;
|
virtual render::ItemKey getKey() const;
|
||||||
render::Item::Bound getBound() const;
|
virtual render::Item::Bound getBound() const;
|
||||||
void render(RenderArgs* args) const;
|
virtual void render(RenderArgs* args) const;
|
||||||
|
|
||||||
// MeshPartPayload functions to perform render
|
// ModelMeshPartPayload functions to perform render
|
||||||
void drawCall(gpu::Batch& batch) const;
|
void drawCall(gpu::Batch& batch) const;
|
||||||
void bindMesh(gpu::Batch& batch) const;
|
virtual void bindMesh(gpu::Batch& batch) const;
|
||||||
void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
virtual void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
||||||
void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
virtual void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
||||||
|
|
||||||
|
|
||||||
void initCache();
|
|
||||||
|
|
||||||
// Payload resource cached values
|
// Payload resource cached values
|
||||||
model::MeshPointer _drawMesh;
|
model::MeshPointer _drawMesh;
|
||||||
|
int _partIndex = 0;
|
||||||
model::Mesh::Part _drawPart;
|
model::Mesh::Part _drawPart;
|
||||||
|
|
||||||
model::MaterialPointer _drawMaterial;
|
model::MaterialPointer _drawMaterial;
|
||||||
|
|
||||||
|
model::Box _localBound;
|
||||||
|
Transform _drawTransform;
|
||||||
|
Transform _transform;
|
||||||
|
Transform _offsetTransform;
|
||||||
|
mutable model::Box _worldBound;
|
||||||
|
|
||||||
bool _hasColorAttrib = false;
|
bool _hasColorAttrib = false;
|
||||||
bool _isSkinned = false;
|
|
||||||
bool _isBlendShaped = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
@ -67,4 +70,32 @@ namespace render {
|
||||||
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
|
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ModelMeshPartPayload : public MeshPartPayload {
|
||||||
|
public:
|
||||||
|
ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
||||||
|
|
||||||
|
typedef render::Payload<ModelMeshPartPayload> Payload;
|
||||||
|
typedef Payload::DataPointer Pointer;
|
||||||
|
|
||||||
|
void notifyLocationChanged() override;
|
||||||
|
|
||||||
|
// Render Item interface
|
||||||
|
render::ItemKey getKey() const override;
|
||||||
|
render::Item::Bound getBound() const override;
|
||||||
|
void render(RenderArgs* args) const override;
|
||||||
|
|
||||||
|
// ModelMeshPartPayload functions to perform render
|
||||||
|
void bindMesh(gpu::Batch& batch) const override;
|
||||||
|
void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const override;
|
||||||
|
|
||||||
|
|
||||||
|
void initCache();
|
||||||
|
Model* _model;
|
||||||
|
int _meshIndex;
|
||||||
|
int _shapeID;
|
||||||
|
bool _isSkinned = false;
|
||||||
|
bool _isBlendShaped = false;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // hifi_MeshPartPayload_h
|
#endif // hifi_MeshPartPayload_h
|
||||||
|
|
|
@ -110,11 +110,19 @@ void Model::setOffset(const glm::vec3& offset) {
|
||||||
void Model::enqueueLocationChange() {
|
void Model::enqueueLocationChange() {
|
||||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
|
|
||||||
|
Transform transform;
|
||||||
|
transform.setTranslation(_translation);
|
||||||
|
transform.setRotation(_rotation);
|
||||||
|
|
||||||
|
Transform offset;
|
||||||
|
offset.setScale(_scale);
|
||||||
|
offset.postTranslate(_offset);
|
||||||
|
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
foreach (auto itemID, _renderItems.keys()) {
|
foreach (auto itemID, _renderItems.keys()) {
|
||||||
pendingChanges.updateItem<MeshPartPayload>(itemID, [=](MeshPartPayload& data) {
|
pendingChanges.updateItem<MeshPartPayload>(itemID, [=](MeshPartPayload& data) {
|
||||||
data.updateModelLocation(_translation, _rotation);
|
data.updateTransform(transform, offset);
|
||||||
data.model->_needsUpdateClusterMatrices = true;
|
data.notifyLocationChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,11 +503,10 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChan
|
||||||
|
|
||||||
foreach (auto renderItem, _renderItemsSet) {
|
foreach (auto renderItem, _renderItemsSet) {
|
||||||
auto item = scene->allocateID();
|
auto item = scene->allocateID();
|
||||||
auto renderData = MeshPartPayload::Pointer(renderItem);
|
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderData);
|
|
||||||
pendingChanges.resetItem(item, renderPayload);
|
pendingChanges.resetItem(item, renderPayload);
|
||||||
pendingChanges.updateItem<MeshPartPayload>(item, [&](MeshPartPayload& data) {
|
pendingChanges.updateItem<MeshPartPayload>(item, [&](MeshPartPayload& data) {
|
||||||
data.model->_needsUpdateClusterMatrices = true;
|
data.notifyLocationChanged();
|
||||||
});
|
});
|
||||||
_renderItems.insert(item, renderPayload);
|
_renderItems.insert(item, renderPayload);
|
||||||
somethingAdded = true;
|
somethingAdded = true;
|
||||||
|
@ -523,12 +530,11 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
||||||
|
|
||||||
foreach (auto renderItem, _renderItemsSet) {
|
foreach (auto renderItem, _renderItemsSet) {
|
||||||
auto item = scene->allocateID();
|
auto item = scene->allocateID();
|
||||||
auto renderData = MeshPartPayload::Pointer(renderItem);
|
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderData);
|
|
||||||
renderPayload->addStatusGetters(statusGetters);
|
renderPayload->addStatusGetters(statusGetters);
|
||||||
pendingChanges.resetItem(item, renderPayload);
|
pendingChanges.resetItem(item, renderPayload);
|
||||||
pendingChanges.updateItem<MeshPartPayload>(item, [&](MeshPartPayload& data) {
|
pendingChanges.updateItem<MeshPartPayload>(item, [&](MeshPartPayload& data) {
|
||||||
data.model->_needsUpdateClusterMatrices = true;
|
data.notifyLocationChanged();
|
||||||
});
|
});
|
||||||
_renderItems.insert(item, renderPayload);
|
_renderItems.insert(item, renderPayload);
|
||||||
somethingAdded = true;
|
somethingAdded = true;
|
||||||
|
@ -1127,8 +1133,14 @@ AABox Model::getPartBounds(int meshIndex, int partIndex, glm::vec3 modelPosition
|
||||||
|
|
||||||
void Model::segregateMeshGroups() {
|
void Model::segregateMeshGroups() {
|
||||||
QSharedPointer<NetworkGeometry> networkGeometry;
|
QSharedPointer<NetworkGeometry> networkGeometry;
|
||||||
if (_showCollisionHull && _collisionGeometry && _collisionGeometry->isLoaded()) {
|
bool showingCollisionHull = false;
|
||||||
|
if (_showCollisionHull && _collisionGeometry) {
|
||||||
|
if (_collisionGeometry->isLoaded()) {
|
||||||
networkGeometry = _collisionGeometry;
|
networkGeometry = _collisionGeometry;
|
||||||
|
showingCollisionHull = true;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
networkGeometry = _geometry;
|
networkGeometry = _geometry;
|
||||||
}
|
}
|
||||||
|
@ -1136,8 +1148,10 @@ void Model::segregateMeshGroups() {
|
||||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = networkGeometry->getMeshes();
|
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = networkGeometry->getMeshes();
|
||||||
|
|
||||||
// all of our mesh vectors must match in size
|
// all of our mesh vectors must match in size
|
||||||
if ((int)networkMeshes.size() != geometry.meshes.size() ||
|
auto geoMeshesSize = geometry.meshes.size();
|
||||||
geometry.meshes.size() != _meshStates.size()) {
|
if ((int)networkMeshes.size() != geoMeshesSize ||
|
||||||
|
// geometry.meshes.size() != _meshStates.size()) {
|
||||||
|
geoMeshesSize > _meshStates.size()) {
|
||||||
qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
|
qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1147,15 +1161,30 @@ void Model::segregateMeshGroups() {
|
||||||
|
|
||||||
_renderItemsSet.clear();
|
_renderItemsSet.clear();
|
||||||
|
|
||||||
|
Transform transform;
|
||||||
|
transform.setTranslation(_translation);
|
||||||
|
transform.setRotation(_rotation);
|
||||||
|
|
||||||
|
Transform offset;
|
||||||
|
offset.setScale(_scale);
|
||||||
|
offset.postTranslate(_offset);
|
||||||
|
|
||||||
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
// Run through all of the meshes, and place them into their segregated, but unsorted buckets
|
||||||
int shapeID = 0;
|
int shapeID = 0;
|
||||||
for (int i = 0; i < (int)networkMeshes.size(); i++) {
|
for (int i = 0; i < (int)networkMeshes.size(); i++) {
|
||||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||||
|
const NetworkMesh& networkMesh = *(networkMeshes.at(i).get());
|
||||||
|
|
||||||
// Create the render payloads
|
// Create the render payloads
|
||||||
int totalParts = mesh.parts.size();
|
int totalParts = mesh.parts.size();
|
||||||
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
|
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
|
||||||
_renderItemsSet << std::make_shared<MeshPartPayload>(this, i, partIndex, shapeID, _translation, _rotation);
|
if (showingCollisionHull) {
|
||||||
|
_renderItemsSet << std::make_shared<MeshPartPayload>(networkMesh._mesh, partIndex, ModelRender::getCollisionHullMaterial(), transform, offset);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
_renderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
|
||||||
|
}
|
||||||
|
|
||||||
shapeID++;
|
shapeID++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1168,15 +1197,22 @@ bool Model::initWhenReady(render::ScenePointer scene) {
|
||||||
|
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
|
|
||||||
|
Transform transform;
|
||||||
|
transform.setTranslation(_translation);
|
||||||
|
transform.setRotation(_rotation);
|
||||||
|
|
||||||
|
Transform offset;
|
||||||
|
offset.setScale(_scale);
|
||||||
|
offset.postTranslate(_offset);
|
||||||
|
|
||||||
foreach (auto renderItem, _renderItemsSet) {
|
foreach (auto renderItem, _renderItemsSet) {
|
||||||
auto item = scene->allocateID();
|
auto item = scene->allocateID();
|
||||||
auto renderData = MeshPartPayload::Pointer(renderItem);
|
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderData);
|
|
||||||
_renderItems.insert(item, renderPayload);
|
_renderItems.insert(item, renderPayload);
|
||||||
pendingChanges.resetItem(item, renderPayload);
|
pendingChanges.resetItem(item, renderPayload);
|
||||||
pendingChanges.updateItem<MeshPartPayload>(item, [&](MeshPartPayload& data) {
|
pendingChanges.updateItem<MeshPartPayload>(item, [&](MeshPartPayload& data) {
|
||||||
data.updateModelLocation(_translation, _rotation);
|
data.updateTransform(transform, offset);
|
||||||
data.model->_needsUpdateClusterMatrices = true;
|
data.notifyLocationChanged();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
|
|
@ -366,7 +366,7 @@ private:
|
||||||
bool _needsUpdateClusterMatrices = true;
|
bool _needsUpdateClusterMatrices = true;
|
||||||
bool _showCollisionHull = false;
|
bool _showCollisionHull = false;
|
||||||
|
|
||||||
friend class MeshPartPayload;
|
friend class ModelMeshPartPayload;
|
||||||
protected:
|
protected:
|
||||||
RigPointer _rig;
|
RigPointer _rig;
|
||||||
};
|
};
|
||||||
|
|
|
@ -280,3 +280,16 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b
|
||||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model::MaterialPointer ModelRender::_collisionHullMaterial;
|
||||||
|
|
||||||
|
model::MaterialPointer ModelRender::getCollisionHullMaterial() {
|
||||||
|
if (!_collisionHullMaterial) {
|
||||||
|
_collisionHullMaterial = std::make_shared<model::Material>();
|
||||||
|
_collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f));
|
||||||
|
_collisionHullMaterial->setMetallic(0.02f);
|
||||||
|
_collisionHullMaterial->setGloss(1.0f);
|
||||||
|
}
|
||||||
|
return _collisionHullMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,11 @@ public:
|
||||||
|
|
||||||
static const RenderPipelineLib& getRenderPipelineLib();
|
static const RenderPipelineLib& getRenderPipelineLib();
|
||||||
|
|
||||||
|
// Collision hull Material
|
||||||
|
static model::MaterialPointer _collisionHullMaterial;
|
||||||
|
|
||||||
|
static model::MaterialPointer getCollisionHullMaterial();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_ModelRender_h
|
#endif // hifi_ModelRender_h
|
|
@ -12,6 +12,7 @@
|
||||||
#include "AABox.h"
|
#include "AABox.h"
|
||||||
|
|
||||||
#include "AACube.h"
|
#include "AACube.h"
|
||||||
|
#include "Transform.h"
|
||||||
#include "Extents.h"
|
#include "Extents.h"
|
||||||
#include "GeometryUtil.h"
|
#include "GeometryUtil.h"
|
||||||
#include "NumericalConstants.h"
|
#include "NumericalConstants.h"
|
||||||
|
@ -42,50 +43,6 @@ glm::vec3 AABox::calcCenter() const {
|
||||||
return center;
|
return center;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AABox::rotate(const glm::quat& rotation) {
|
|
||||||
auto minimum = _corner;
|
|
||||||
auto maximum = _corner + _scale;
|
|
||||||
|
|
||||||
glm::vec3 bottomLeftNear(minimum.x, minimum.y, minimum.z);
|
|
||||||
glm::vec3 bottomRightNear(maximum.x, minimum.y, minimum.z);
|
|
||||||
glm::vec3 bottomLeftFar(minimum.x, minimum.y, maximum.z);
|
|
||||||
glm::vec3 bottomRightFar(maximum.x, minimum.y, maximum.z);
|
|
||||||
glm::vec3 topLeftNear(minimum.x, maximum.y, minimum.z);
|
|
||||||
glm::vec3 topRightNear(maximum.x, maximum.y, minimum.z);
|
|
||||||
glm::vec3 topLeftFar(minimum.x, maximum.y, maximum.z);
|
|
||||||
glm::vec3 topRightFar(maximum.x, maximum.y, maximum.z);
|
|
||||||
|
|
||||||
glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear;
|
|
||||||
glm::vec3 bottomRightNearRotated = rotation * bottomRightNear;
|
|
||||||
glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar;
|
|
||||||
glm::vec3 bottomRightFarRotated = rotation * bottomRightFar;
|
|
||||||
glm::vec3 topLeftNearRotated = rotation * topLeftNear;
|
|
||||||
glm::vec3 topRightNearRotated = rotation * topRightNear;
|
|
||||||
glm::vec3 topLeftFarRotated = rotation * topLeftFar;
|
|
||||||
glm::vec3 topRightFarRotated = rotation * topRightFar;
|
|
||||||
|
|
||||||
minimum = glm::min(bottomLeftNearRotated,
|
|
||||||
glm::min(bottomRightNearRotated,
|
|
||||||
glm::min(bottomLeftFarRotated,
|
|
||||||
glm::min(bottomRightFarRotated,
|
|
||||||
glm::min(topLeftNearRotated,
|
|
||||||
glm::min(topRightNearRotated,
|
|
||||||
glm::min(topLeftFarRotated,
|
|
||||||
topRightFarRotated)))))));
|
|
||||||
|
|
||||||
maximum = glm::max(bottomLeftNearRotated,
|
|
||||||
glm::max(bottomRightNearRotated,
|
|
||||||
glm::max(bottomLeftFarRotated,
|
|
||||||
glm::max(bottomRightFarRotated,
|
|
||||||
glm::max(topLeftNearRotated,
|
|
||||||
glm::max(topRightNearRotated,
|
|
||||||
glm::max(topLeftFarRotated,
|
|
||||||
topRightFarRotated)))))));
|
|
||||||
|
|
||||||
_corner = minimum;
|
|
||||||
_scale = maximum - minimum;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 AABox::getVertex(BoxVertex vertex) const {
|
glm::vec3 AABox::getVertex(BoxVertex vertex) const {
|
||||||
switch (vertex) {
|
switch (vertex) {
|
||||||
case BOTTOM_LEFT_NEAR:
|
case BOTTOM_LEFT_NEAR:
|
||||||
|
@ -525,3 +482,59 @@ AABox& AABox::operator += (const AABox& box) {
|
||||||
}
|
}
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AABox::scale(const glm::vec3& scale) {
|
||||||
|
_corner *= scale;
|
||||||
|
_scale *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AABox::rotate(const glm::quat& rotation) {
|
||||||
|
auto minimum = _corner;
|
||||||
|
auto maximum = _corner + _scale;
|
||||||
|
|
||||||
|
glm::vec3 bottomLeftNear(minimum.x, minimum.y, minimum.z);
|
||||||
|
glm::vec3 bottomRightNear(maximum.x, minimum.y, minimum.z);
|
||||||
|
glm::vec3 bottomLeftFar(minimum.x, minimum.y, maximum.z);
|
||||||
|
glm::vec3 bottomRightFar(maximum.x, minimum.y, maximum.z);
|
||||||
|
glm::vec3 topLeftNear(minimum.x, maximum.y, minimum.z);
|
||||||
|
glm::vec3 topRightNear(maximum.x, maximum.y, minimum.z);
|
||||||
|
glm::vec3 topLeftFar(minimum.x, maximum.y, maximum.z);
|
||||||
|
glm::vec3 topRightFar(maximum.x, maximum.y, maximum.z);
|
||||||
|
|
||||||
|
glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear;
|
||||||
|
glm::vec3 bottomRightNearRotated = rotation * bottomRightNear;
|
||||||
|
glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar;
|
||||||
|
glm::vec3 bottomRightFarRotated = rotation * bottomRightFar;
|
||||||
|
glm::vec3 topLeftNearRotated = rotation * topLeftNear;
|
||||||
|
glm::vec3 topRightNearRotated = rotation * topRightNear;
|
||||||
|
glm::vec3 topLeftFarRotated = rotation * topLeftFar;
|
||||||
|
glm::vec3 topRightFarRotated = rotation * topRightFar;
|
||||||
|
|
||||||
|
minimum = glm::min(bottomLeftNearRotated,
|
||||||
|
glm::min(bottomRightNearRotated,
|
||||||
|
glm::min(bottomLeftFarRotated,
|
||||||
|
glm::min(bottomRightFarRotated,
|
||||||
|
glm::min(topLeftNearRotated,
|
||||||
|
glm::min(topRightNearRotated,
|
||||||
|
glm::min(topLeftFarRotated,
|
||||||
|
topRightFarRotated)))))));
|
||||||
|
|
||||||
|
maximum = glm::max(bottomLeftNearRotated,
|
||||||
|
glm::max(bottomRightNearRotated,
|
||||||
|
glm::max(bottomLeftFarRotated,
|
||||||
|
glm::max(bottomRightFarRotated,
|
||||||
|
glm::max(topLeftNearRotated,
|
||||||
|
glm::max(topRightNearRotated,
|
||||||
|
glm::max(topLeftFarRotated,
|
||||||
|
topRightFarRotated)))))));
|
||||||
|
|
||||||
|
_corner = minimum;
|
||||||
|
_scale = maximum - minimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AABox::transform(const Transform& transform) {
|
||||||
|
scale(transform.getScale());
|
||||||
|
rotate(transform.getRotation());
|
||||||
|
translate(transform.getTranslation());
|
||||||
|
}
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
class AACube;
|
class AACube;
|
||||||
class Extents;
|
class Extents;
|
||||||
|
class Transform;
|
||||||
|
|
||||||
class AABox {
|
class AABox {
|
||||||
|
|
||||||
|
@ -41,11 +42,6 @@ public:
|
||||||
glm::vec3 getVertexP(const glm::vec3& normal) const;
|
glm::vec3 getVertexP(const glm::vec3& normal) const;
|
||||||
glm::vec3 getVertexN(const glm::vec3& normal) const;
|
glm::vec3 getVertexN(const glm::vec3& normal) const;
|
||||||
|
|
||||||
void shiftBy(const glm::vec3& delta) { _corner += delta; }
|
|
||||||
void rotate(const glm::quat& rotation);
|
|
||||||
void scale(float scale) { _corner *= scale; _scale *= scale; }
|
|
||||||
void scale(const glm::vec3& scale) { _corner *= scale; _scale *= scale; }
|
|
||||||
|
|
||||||
const glm::vec3& getCorner() const { return _corner; }
|
const glm::vec3& getCorner() const { return _corner; }
|
||||||
const glm::vec3& getScale() const { return _scale; }
|
const glm::vec3& getScale() const { return _scale; }
|
||||||
const glm::vec3& getDimensions() const { return _scale; }
|
const glm::vec3& getDimensions() const { return _scale; }
|
||||||
|
@ -85,6 +81,20 @@ public:
|
||||||
AABox& operator += (const glm::vec3& point);
|
AABox& operator += (const glm::vec3& point);
|
||||||
AABox& operator += (const AABox& box);
|
AABox& operator += (const AABox& box);
|
||||||
|
|
||||||
|
// Translate the AABox just moving the corner
|
||||||
|
void translate(const glm::vec3& translation) { _corner += translation; }
|
||||||
|
|
||||||
|
// Rotate the AABox around its frame origin
|
||||||
|
// meaning rotating the corners of the AABox around the point {0,0,0} and reevaluating the min max
|
||||||
|
void rotate(const glm::quat& rotation);
|
||||||
|
|
||||||
|
/// Scale the AABox
|
||||||
|
void scale(float scale);
|
||||||
|
void scale(const glm::vec3& scale);
|
||||||
|
|
||||||
|
// Transform the extents with transform
|
||||||
|
void transform(const Transform& transform);
|
||||||
|
|
||||||
bool isInvalid() const { return _corner == glm::vec3(std::numeric_limits<float>::infinity()); }
|
bool isInvalid() const { return _corner == glm::vec3(std::numeric_limits<float>::infinity()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in a new issue