mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 12:37:51 +02:00
adding the atmosphere in the directional lighting pass, debug
This commit is contained in:
commit
853cf75f60
42 changed files with 868 additions and 212 deletions
|
@ -385,7 +385,7 @@ var toolBar = (function () {
|
||||||
} else if (browseModelsButtonDown) {
|
} else if (browseModelsButtonDown) {
|
||||||
var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||||
if (browseModelsButton === toolBar.clicked(clickedOverlay)) {
|
if (browseModelsButton === toolBar.clicked(clickedOverlay)) {
|
||||||
url = Window.s3Browse(".*(fbx|FBX)");
|
url = Window.s3Browse(".*(fbx|FBX|obj|OBJ)");
|
||||||
if (url !== null && url !== "") {
|
if (url !== null && url !== "") {
|
||||||
addModel(url);
|
addModel(url);
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,6 +158,7 @@
|
||||||
|
|
||||||
var elModelSections = document.querySelectorAll(".model-section");
|
var elModelSections = document.querySelectorAll(".model-section");
|
||||||
var elModelURL = document.getElementById("property-model-url");
|
var elModelURL = document.getElementById("property-model-url");
|
||||||
|
var elCollisionModelURL = document.getElementById("property-collision-model-url");
|
||||||
var elModelAnimationURL = document.getElementById("property-model-animation-url");
|
var elModelAnimationURL = document.getElementById("property-model-animation-url");
|
||||||
var elModelAnimationPlaying = document.getElementById("property-model-animation-playing");
|
var elModelAnimationPlaying = document.getElementById("property-model-animation-playing");
|
||||||
var elModelAnimationFPS = document.getElementById("property-model-animation-fps");
|
var elModelAnimationFPS = document.getElementById("property-model-animation-fps");
|
||||||
|
@ -287,6 +288,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
elModelURL.value = properties.modelURL;
|
elModelURL.value = properties.modelURL;
|
||||||
|
elCollisionModelURL.value = properties.collisionModelURL;
|
||||||
elModelAnimationURL.value = properties.animationURL;
|
elModelAnimationURL.value = properties.animationURL;
|
||||||
elModelAnimationPlaying.checked = properties.animationIsPlaying;
|
elModelAnimationPlaying.checked = properties.animationIsPlaying;
|
||||||
elModelAnimationFPS.value = properties.animationFPS;
|
elModelAnimationFPS.value = properties.animationFPS;
|
||||||
|
@ -411,6 +413,7 @@
|
||||||
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
|
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
|
||||||
|
|
||||||
elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL'));
|
elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL'));
|
||||||
|
elCollisionModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionModelURL'));
|
||||||
elModelAnimationURL.addEventListener('change', createEmitTextPropertyUpdateFunction('animationURL'));
|
elModelAnimationURL.addEventListener('change', createEmitTextPropertyUpdateFunction('animationURL'));
|
||||||
elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying'));
|
elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying'));
|
||||||
elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS'));
|
elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS'));
|
||||||
|
@ -642,6 +645,12 @@
|
||||||
<input type="text" id="property-model-url" class="url"></input>
|
<input type="text" id="property-model-url" class="url"></input>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="model-section property">
|
||||||
|
<div class="label">Collision Model URL</div>
|
||||||
|
<div class="value">
|
||||||
|
<input type="text" id="property-collision-model-url" class="url"></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="model-section property">
|
<div class="model-section property">
|
||||||
<div class="label">Animation URL</div>
|
<div class="label">Animation URL</div>
|
||||||
<div class="value">
|
<div class="value">
|
||||||
|
|
|
@ -53,6 +53,7 @@ function Tooltip() {
|
||||||
text += "ID: " + properties.id + "\n"
|
text += "ID: " + properties.id + "\n"
|
||||||
if (properties.type == "Model") {
|
if (properties.type == "Model") {
|
||||||
text += "Model URL: " + properties.modelURL + "\n"
|
text += "Model URL: " + properties.modelURL + "\n"
|
||||||
|
text += "Collision Model URL: " + properties.collisionModelURL + "\n"
|
||||||
text += "Animation URL: " + properties.animationURL + "\n"
|
text += "Animation URL: " + properties.animationURL + "\n"
|
||||||
text += "Animation is playing: " + properties.animationIsPlaying + "\n"
|
text += "Animation is playing: " + properties.animationIsPlaying + "\n"
|
||||||
if (properties.sittingPoints && properties.sittingPoints.length > 0) {
|
if (properties.sittingPoints && properties.sittingPoints.length > 0) {
|
||||||
|
|
|
@ -52,6 +52,8 @@ EntityPropertyDialogBox = (function () {
|
||||||
if (properties.type == "Model") {
|
if (properties.type == "Model") {
|
||||||
array.push({ label: "Model URL:", value: properties.modelURL });
|
array.push({ label: "Model URL:", value: properties.modelURL });
|
||||||
index++;
|
index++;
|
||||||
|
array.push({ label: "Collision Model URL:", value: properties.collisionModelURL });
|
||||||
|
index++;
|
||||||
array.push({ label: "Animation URL:", value: properties.animationURL });
|
array.push({ label: "Animation URL:", value: properties.animationURL });
|
||||||
index++;
|
index++;
|
||||||
array.push({ label: "Animation is playing:", type: "checkbox", value: properties.animationIsPlaying });
|
array.push({ label: "Animation is playing:", type: "checkbox", value: properties.animationIsPlaying });
|
||||||
|
@ -275,6 +277,7 @@ EntityPropertyDialogBox = (function () {
|
||||||
properties.locked = array[index++].value;
|
properties.locked = array[index++].value;
|
||||||
if (properties.type == "Model") {
|
if (properties.type == "Model") {
|
||||||
properties.modelURL = array[index++].value;
|
properties.modelURL = array[index++].value;
|
||||||
|
properties.collisionModelURL = array[index++].value;
|
||||||
properties.animationURL = array[index++].value;
|
properties.animationURL = array[index++].value;
|
||||||
|
|
||||||
var newAnimationIsPlaying = array[index++].value;
|
var newAnimationIsPlaying = array[index++].value;
|
||||||
|
|
|
@ -1143,6 +1143,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Qt::Key_Comma: {
|
||||||
|
_myAvatar->togglePhysicsEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
event->ignore();
|
event->ignore();
|
||||||
|
@ -1807,6 +1811,9 @@ void Application::init() {
|
||||||
tree->setSimulation(&_physicsEngine);
|
tree->setSimulation(&_physicsEngine);
|
||||||
_physicsEngine.init(&_entityEditSender);
|
_physicsEngine.init(&_entityEditSender);
|
||||||
|
|
||||||
|
|
||||||
|
_physicsEngine.setAvatarData(_myAvatar);
|
||||||
|
|
||||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||||
|
|
||||||
connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity,
|
connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity,
|
||||||
|
@ -2869,6 +2876,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
DependencyManager::get<DeferredLightingEffect>()->setAmbientLightMode(getRenderAmbientLight());
|
||||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity());
|
DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(skyStage->getSunLight()->getDirection(), skyStage->getSunLight()->getColor(), skyStage->getSunLight()->getIntensity());
|
||||||
|
DependencyManager::get<DeferredLightingEffect>()->setGlobalAtmosphere(skyStage->getAtmosphere());
|
||||||
|
|
||||||
PROFILE_RANGE("DeferredLighting");
|
PROFILE_RANGE("DeferredLighting");
|
||||||
PerformanceTimer perfTimer("lighting");
|
PerformanceTimer perfTimer("lighting");
|
||||||
|
@ -3908,8 +3916,8 @@ void Application::takeSnapshot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setVSyncEnabled() {
|
void Application::setVSyncEnabled() {
|
||||||
bool vsyncOn = Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn);
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
|
bool vsyncOn = Menu::getInstance()->isOptionChecked(MenuOption::RenderTargetFramerateVSyncOn);
|
||||||
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
||||||
wglSwapIntervalEXT(vsyncOn);
|
wglSwapIntervalEXT(vsyncOn);
|
||||||
int swapInterval = wglGetSwapIntervalEXT();
|
int swapInterval = wglGetSwapIntervalEXT();
|
||||||
|
@ -3932,7 +3940,6 @@ void Application::setVSyncEnabled() {
|
||||||
#else
|
#else
|
||||||
qDebug("V-Sync is FORCED ON on this system\n");
|
qDebug("V-Sync is FORCED ON on this system\n");
|
||||||
#endif
|
#endif
|
||||||
vsyncOn = true; // Turns off unused variable warning
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Application::isVSyncOn() const {
|
bool Application::isVSyncOn() const {
|
||||||
|
|
|
@ -332,8 +332,7 @@ void ModelUploader::populateBasicMapping(QVariantHash& mapping, QString filename
|
||||||
// mixamo blendshapes - in the event that a mixamo file was edited by some other tool, it's likely the applicationName will
|
// mixamo blendshapes - in the event that a mixamo file was edited by some other tool, it's likely the applicationName will
|
||||||
// be rewritten, so we detect the existence of several different blendshapes which indicate we're likely a mixamo file
|
// be rewritten, so we detect the existence of several different blendshapes which indicate we're likely a mixamo file
|
||||||
bool likelyMixamoFile = geometry.applicationName == "mixamo.com" ||
|
bool likelyMixamoFile = geometry.applicationName == "mixamo.com" ||
|
||||||
(geometry.blendshapeChannelNames.contains("Facial_Blends") &&
|
(geometry.blendshapeChannelNames.contains("BrowsDown_Right") &&
|
||||||
geometry.blendshapeChannelNames.contains("BrowsDown_Right") &&
|
|
||||||
geometry.blendshapeChannelNames.contains("MouthOpen") &&
|
geometry.blendshapeChannelNames.contains("MouthOpen") &&
|
||||||
geometry.blendshapeChannelNames.contains("Blink_Left") &&
|
geometry.blendshapeChannelNames.contains("Blink_Left") &&
|
||||||
geometry.blendshapeChannelNames.contains("Blink_Right") &&
|
geometry.blendshapeChannelNames.contains("Blink_Right") &&
|
||||||
|
|
|
@ -63,7 +63,6 @@ Avatar::Avatar() :
|
||||||
_skeletonModel(this),
|
_skeletonModel(this),
|
||||||
_skeletonOffset(0.0f),
|
_skeletonOffset(0.0f),
|
||||||
_bodyYawDelta(0.0f),
|
_bodyYawDelta(0.0f),
|
||||||
_velocity(0.0f),
|
|
||||||
_positionDeltaAccumulator(0.0f),
|
_positionDeltaAccumulator(0.0f),
|
||||||
_lastVelocity(0.0f),
|
_lastVelocity(0.0f),
|
||||||
_acceleration(0.0f),
|
_acceleration(0.0f),
|
||||||
|
|
|
@ -155,7 +155,6 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE glm::vec3 getNeckPosition() const;
|
Q_INVOKABLE glm::vec3 getNeckPosition() const;
|
||||||
|
|
||||||
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
|
|
||||||
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
|
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
|
||||||
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
|
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
|
||||||
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
|
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
|
||||||
|
@ -184,11 +183,9 @@ protected:
|
||||||
QVector<Model*> _attachmentModels;
|
QVector<Model*> _attachmentModels;
|
||||||
float _bodyYawDelta;
|
float _bodyYawDelta;
|
||||||
|
|
||||||
glm::vec3 _velocity;
|
|
||||||
|
|
||||||
// These position histories and derivatives are in the world-frame.
|
// These position histories and derivatives are in the world-frame.
|
||||||
// The derivatives are the MEASURED results of all external and internal forces
|
// The derivatives are the MEASURED results of all external and internal forces
|
||||||
// and are therefor READ-ONLY --> motion control of the Avatar is NOT obtained
|
// and are therefore READ-ONLY --> motion control of the Avatar is NOT obtained
|
||||||
// by setting these values.
|
// by setting these values.
|
||||||
// Floating point error prevents us from accurately measuring velocity using a naive approach
|
// Floating point error prevents us from accurately measuring velocity using a naive approach
|
||||||
// (e.g. vel = (pos - lastPos)/dt) so instead we use _positionDeltaAccumulator.
|
// (e.g. vel = (pos - lastPos)/dt) so instead we use _positionDeltaAccumulator.
|
||||||
|
|
|
@ -181,7 +181,11 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("transform");
|
PerformanceTimer perfTimer("transform");
|
||||||
updateOrientation(deltaTime);
|
updateOrientation(deltaTime);
|
||||||
updatePosition(deltaTime);
|
if (isPhysicsEnabled()) {
|
||||||
|
updatePositionWithPhysics(deltaTime);
|
||||||
|
} else {
|
||||||
|
updatePosition(deltaTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1397,6 +1401,25 @@ void MyAvatar::updatePosition(float deltaTime) {
|
||||||
measureMotionDerivatives(deltaTime);
|
measureMotionDerivatives(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::updatePositionWithPhysics(float deltaTime) {
|
||||||
|
// rotate velocity into camera frame
|
||||||
|
glm::quat rotation = getHead()->getCameraOrientation();
|
||||||
|
glm::vec3 localVelocity = glm::inverse(rotation) * _velocity;
|
||||||
|
|
||||||
|
bool hasFloor = false;
|
||||||
|
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor);
|
||||||
|
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
|
||||||
|
|
||||||
|
// cap avatar speed
|
||||||
|
float speed = glm::length(newLocalVelocity);
|
||||||
|
if (speed > MAX_WALKING_SPEED) {
|
||||||
|
newLocalVelocity *= MAX_WALKING_SPEED / speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// rotate back into world-frame
|
||||||
|
_velocity = rotation * newLocalVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
|
void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
|
||||||
glm::vec3 up = getBodyUpDirection();
|
glm::vec3 up = getBodyUpDirection();
|
||||||
const float ENVIRONMENT_SURFACE_ELASTICITY = 0.0f;
|
const float ENVIRONMENT_SURFACE_ELASTICITY = 0.0f;
|
||||||
|
|
|
@ -164,8 +164,6 @@ public slots:
|
||||||
glm::vec3 getThrust() { return _thrust; };
|
glm::vec3 getThrust() { return _thrust; };
|
||||||
void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }
|
void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }
|
||||||
|
|
||||||
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
|
||||||
|
|
||||||
void updateMotionBehavior();
|
void updateMotionBehavior();
|
||||||
void onToggleRagdoll();
|
void onToggleRagdoll();
|
||||||
|
|
||||||
|
@ -233,6 +231,7 @@ private:
|
||||||
glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor);
|
glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor);
|
||||||
glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity);
|
glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity);
|
||||||
void updatePosition(float deltaTime);
|
void updatePosition(float deltaTime);
|
||||||
|
void updatePositionWithPhysics(float deltaTime);
|
||||||
void updateCollisionWithAvatars(float deltaTime);
|
void updateCollisionWithAvatars(float deltaTime);
|
||||||
void updateCollisionWithEnvironment(float deltaTime, float radius);
|
void updateCollisionWithEnvironment(float deltaTime, float radius);
|
||||||
void updateCollisionWithVoxels(float deltaTime, float radius);
|
void updateCollisionWithVoxels(float deltaTime, float radius);
|
||||||
|
|
|
@ -55,7 +55,8 @@ AvatarData::AvatarData() :
|
||||||
_billboard(),
|
_billboard(),
|
||||||
_errorLogExpiry(0),
|
_errorLogExpiry(0),
|
||||||
_owningAvatarMixer(),
|
_owningAvatarMixer(),
|
||||||
_lastUpdateTimer()
|
_lastUpdateTimer(),
|
||||||
|
_velocity(0.0f)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ typedef unsigned long long quint64;
|
||||||
#include <QVariantMap>
|
#include <QVariantMap>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QtScript/QScriptable>
|
#include <QtScript/QScriptable>
|
||||||
|
#include <QReadWriteLock>
|
||||||
|
|
||||||
#include <CollisionInfo.h>
|
#include <CollisionInfo.h>
|
||||||
#include <RegisteredMetaTypes.h>
|
#include <RegisteredMetaTypes.h>
|
||||||
|
@ -300,6 +301,19 @@ public:
|
||||||
|
|
||||||
const Referential* getReferential() const { return _referential; }
|
const Referential* getReferential() const { return _referential; }
|
||||||
|
|
||||||
|
void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; }
|
||||||
|
bool isPhysicsEnabled() { return _enablePhysics; }
|
||||||
|
void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; }
|
||||||
|
|
||||||
|
void lockForRead() { _lock.lockForRead(); }
|
||||||
|
bool tryLockForRead() { return _lock.tryLockForRead(); }
|
||||||
|
void lockForWrite() { _lock.lockForWrite(); }
|
||||||
|
bool tryLockForWrite() { return _lock.tryLockForWrite(); }
|
||||||
|
void unlock() { _lock.unlock(); }
|
||||||
|
|
||||||
|
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
||||||
|
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void sendAvatarDataPacket();
|
void sendAvatarDataPacket();
|
||||||
void sendIdentityPacket();
|
void sendIdentityPacket();
|
||||||
|
@ -389,10 +403,15 @@ protected:
|
||||||
virtual void updateJointMappings();
|
virtual void updateJointMappings();
|
||||||
void changeReferential(Referential* ref);
|
void changeReferential(Referential* ref);
|
||||||
|
|
||||||
|
glm::vec3 _velocity;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// privatize the copy constructor and assignment operator so they cannot be called
|
// privatize the copy constructor and assignment operator so they cannot be called
|
||||||
AvatarData(const AvatarData&);
|
AvatarData(const AvatarData&);
|
||||||
AvatarData& operator= (const AvatarData&);
|
AvatarData& operator= (const AvatarData&);
|
||||||
|
|
||||||
|
QReadWriteLock _lock;
|
||||||
|
bool _enablePhysics = false;
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(AvatarData*)
|
Q_DECLARE_METATYPE(AvatarData*)
|
||||||
|
|
||||||
|
|
|
@ -501,7 +501,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
||||||
dataAt += propertyFlags.getEncodedLength();
|
dataAt += propertyFlags.getEncodedLength();
|
||||||
bytesRead += propertyFlags.getEncodedLength();
|
bytesRead += propertyFlags.getEncodedLength();
|
||||||
bool useMeters = (args.bitstreamVersion == VERSION_ENTITIES_USE_METERS_AND_RADIANS);
|
bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS);
|
||||||
if (useMeters) {
|
if (useMeters) {
|
||||||
READ_ENTITY_PROPERTY_SETTER(PROP_POSITION, glm::vec3, updatePosition);
|
READ_ENTITY_PROPERTY_SETTER(PROP_POSITION, glm::vec3, updatePosition);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -40,6 +40,7 @@ EntityItemProperties::EntityItemProperties() :
|
||||||
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
|
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
|
||||||
CONSTRUCT_PROPERTY(color, ),
|
CONSTRUCT_PROPERTY(color, ),
|
||||||
CONSTRUCT_PROPERTY(modelURL, ""),
|
CONSTRUCT_PROPERTY(modelURL, ""),
|
||||||
|
CONSTRUCT_PROPERTY(collisionModelURL, ""),
|
||||||
CONSTRUCT_PROPERTY(animationURL, ""),
|
CONSTRUCT_PROPERTY(animationURL, ""),
|
||||||
CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS),
|
CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS),
|
||||||
CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
|
CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
|
||||||
|
@ -158,6 +159,7 @@ void EntityItemProperties::debugDump() const {
|
||||||
qDebug() << " _position=" << _position.x << "," << _position.y << "," << _position.z;
|
qDebug() << " _position=" << _position.x << "," << _position.y << "," << _position.z;
|
||||||
qDebug() << " _dimensions=" << getDimensions();
|
qDebug() << " _dimensions=" << getDimensions();
|
||||||
qDebug() << " _modelURL=" << _modelURL;
|
qDebug() << " _modelURL=" << _modelURL;
|
||||||
|
qDebug() << " _collisionModelURL=" << _collisionModelURL;
|
||||||
qDebug() << " changed properties...";
|
qDebug() << " changed properties...";
|
||||||
EntityPropertyFlags props = getChangedProperties();
|
EntityPropertyFlags props = getChangedProperties();
|
||||||
props.debugDumpBits();
|
props.debugDumpBits();
|
||||||
|
@ -213,6 +215,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
||||||
CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script);
|
CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
|
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
|
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
|
||||||
|
CHECK_PROPERTY_CHANGE(PROP_COLLISION_MODEL_URL, collisionModelURL);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying);
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying);
|
||||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex);
|
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex);
|
||||||
|
@ -276,6 +279,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color);
|
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
|
||||||
|
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionModelURL);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying);
|
||||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS);
|
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS);
|
||||||
|
@ -356,6 +360,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(visible, setVisible);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(visible, setVisible);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(color, setColor);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(color, setColor);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(modelURL, setModelURL);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(modelURL, setModelURL);
|
||||||
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(collisionModelURL, setCollisionModelURL);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationURL, setAnimationURL);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationURL, setAnimationURL);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying);
|
||||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS);
|
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS);
|
||||||
|
@ -541,6 +546,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
||||||
|
|
||||||
if (properties.getType() == EntityTypes::Model) {
|
if (properties.getType() == EntityTypes::Model) {
|
||||||
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL());
|
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, properties.getCollisionModelURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex());
|
||||||
|
@ -769,6 +775,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
||||||
|
|
||||||
if (properties.getType() == EntityTypes::Model) {
|
if (properties.getType() == EntityTypes::Model) {
|
||||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL);
|
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL);
|
||||||
|
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COLLISION_MODEL_URL, setCollisionModelURL);
|
||||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL);
|
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
|
||||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
|
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
|
||||||
|
@ -845,6 +852,7 @@ void EntityItemProperties::markAllChanged() {
|
||||||
_visibleChanged = true;
|
_visibleChanged = true;
|
||||||
_colorChanged = true;
|
_colorChanged = true;
|
||||||
_modelURLChanged = true;
|
_modelURLChanged = true;
|
||||||
|
_collisionModelURLChanged = true;
|
||||||
_animationURLChanged = true;
|
_animationURLChanged = true;
|
||||||
_animationIsPlayingChanged = true;
|
_animationIsPlayingChanged = true;
|
||||||
_animationFrameIndexChanged = true;
|
_animationFrameIndexChanged = true;
|
||||||
|
|
|
@ -102,6 +102,7 @@ enum EntityPropertyList {
|
||||||
PROP_TEXT = PROP_MODEL_URL,
|
PROP_TEXT = PROP_MODEL_URL,
|
||||||
PROP_LINE_HEIGHT = PROP_ANIMATION_URL,
|
PROP_LINE_HEIGHT = PROP_ANIMATION_URL,
|
||||||
PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS,
|
PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS,
|
||||||
|
PROP_COLLISION_MODEL_URL,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
|
typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags;
|
||||||
|
@ -164,6 +165,7 @@ public:
|
||||||
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString);
|
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString);
|
||||||
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
|
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
|
||||||
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
|
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
|
||||||
|
DEFINE_PROPERTY_REF(PROP_COLLISION_MODEL_URL, CollisionModelURL, collisionModelURL, QString);
|
||||||
DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString);
|
DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString);
|
||||||
DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float);
|
DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float);
|
||||||
DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float);
|
DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float);
|
||||||
|
@ -291,6 +293,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, "");
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
|
||||||
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionModelURL, collisionModelURL, "");
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, "");
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFPS, animationFPS, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFPS, animationFPS, "");
|
||||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFrameIndex, animationFrameIndex, "");
|
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFrameIndex, animationFrameIndex, "");
|
||||||
|
|
|
@ -35,7 +35,7 @@ const int DIRTY_SIMULATION_FLAGS =
|
||||||
class EntitySimulation : public QObject {
|
class EntitySimulation : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL) { }
|
EntitySimulation() : _mutex(QMutex::Recursive), _entityTree(NULL), _nextExpiry(quint64(-1)) { }
|
||||||
virtual ~EntitySimulation() { setEntityTree(NULL); }
|
virtual ~EntitySimulation() { setEntityTree(NULL); }
|
||||||
|
|
||||||
void lock() { _mutex.lock(); }
|
void lock() { _mutex.lock(); }
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "ModelEntityItem.h"
|
#include "ModelEntityItem.h"
|
||||||
|
|
||||||
const QString ModelEntityItem::DEFAULT_MODEL_URL = QString("");
|
const QString ModelEntityItem::DEFAULT_MODEL_URL = QString("");
|
||||||
|
const QString ModelEntityItem::DEFAULT_COLLISION_MODEL_URL = QString("");
|
||||||
const QString ModelEntityItem::DEFAULT_ANIMATION_URL = QString("");
|
const QString ModelEntityItem::DEFAULT_ANIMATION_URL = QString("");
|
||||||
const float ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f;
|
const float ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f;
|
||||||
const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false;
|
const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false;
|
||||||
|
@ -44,6 +45,7 @@ EntityItemProperties ModelEntityItem::getProperties() const {
|
||||||
|
|
||||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
|
||||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);
|
||||||
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionModelURL, getCollisionModelURL);
|
||||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationURL, getAnimationURL);
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationURL, getAnimationURL);
|
||||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying);
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying);
|
||||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
|
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
|
||||||
|
@ -61,6 +63,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
|
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionModelURL, setCollisionModelURL);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
|
||||||
|
@ -92,6 +95,11 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
|
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
|
||||||
READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL);
|
READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL);
|
||||||
|
if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) {
|
||||||
|
setCollisionModelURL("");
|
||||||
|
} else {
|
||||||
|
READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL, setCollisionModelURL);
|
||||||
|
}
|
||||||
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL);
|
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL);
|
||||||
|
|
||||||
// Because we're using AnimationLoop which will reset the frame index if you change it's running state
|
// Because we're using AnimationLoop which will reset the frame index if you change it's running state
|
||||||
|
@ -128,6 +136,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
|
||||||
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||||
|
|
||||||
requestedProperties += PROP_MODEL_URL;
|
requestedProperties += PROP_MODEL_URL;
|
||||||
|
requestedProperties += PROP_COLLISION_MODEL_URL;
|
||||||
requestedProperties += PROP_ANIMATION_URL;
|
requestedProperties += PROP_ANIMATION_URL;
|
||||||
requestedProperties += PROP_ANIMATION_FPS;
|
requestedProperties += PROP_ANIMATION_FPS;
|
||||||
requestedProperties += PROP_ANIMATION_FRAME_INDEX;
|
requestedProperties += PROP_ANIMATION_FRAME_INDEX;
|
||||||
|
@ -151,6 +160,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
||||||
|
|
||||||
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
|
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL());
|
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL());
|
||||||
|
APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, getCollisionModelURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS());
|
||||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex());
|
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex());
|
||||||
|
@ -258,6 +268,7 @@ void ModelEntityItem::debugDump() const {
|
||||||
qDebug() << " position:" << getPosition();
|
qDebug() << " position:" << getPosition();
|
||||||
qDebug() << " dimensions:" << getDimensions();
|
qDebug() << " dimensions:" << getDimensions();
|
||||||
qDebug() << " model URL:" << getModelURL();
|
qDebug() << " model URL:" << getModelURL();
|
||||||
|
qDebug() << " collision model URL:" << getCollisionModelURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelEntityItem::updateShapeType(ShapeType type) {
|
void ModelEntityItem::updateShapeType(ShapeType type) {
|
||||||
|
|
|
@ -57,10 +57,14 @@ public:
|
||||||
const rgbColor& getColor() const { return _color; }
|
const rgbColor& getColor() const { return _color; }
|
||||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||||
bool hasModel() const { return !_modelURL.isEmpty(); }
|
bool hasModel() const { return !_modelURL.isEmpty(); }
|
||||||
|
bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); }
|
||||||
|
|
||||||
static const QString DEFAULT_MODEL_URL;
|
static const QString DEFAULT_MODEL_URL;
|
||||||
const QString& getModelURL() const { return _modelURL; }
|
const QString& getModelURL() const { return _modelURL; }
|
||||||
|
|
||||||
|
static const QString DEFAULT_COLLISION_MODEL_URL;
|
||||||
|
const QString& getCollisionModelURL() const { return _collisionModelURL; }
|
||||||
|
|
||||||
bool hasAnimation() const { return !_animationURL.isEmpty(); }
|
bool hasAnimation() const { return !_animationURL.isEmpty(); }
|
||||||
static const QString DEFAULT_ANIMATION_URL;
|
static const QString DEFAULT_ANIMATION_URL;
|
||||||
const QString& getAnimationURL() const { return _animationURL; }
|
const QString& getAnimationURL() const { return _animationURL; }
|
||||||
|
@ -74,6 +78,7 @@ public:
|
||||||
|
|
||||||
// model related properties
|
// model related properties
|
||||||
void setModelURL(const QString& url) { _modelURL = url; }
|
void setModelURL(const QString& url) { _modelURL = url; }
|
||||||
|
void setCollisionModelURL(const QString& url) { _collisionModelURL = url; }
|
||||||
void setAnimationURL(const QString& url);
|
void setAnimationURL(const QString& url);
|
||||||
static const float DEFAULT_ANIMATION_FRAME_INDEX;
|
static const float DEFAULT_ANIMATION_FRAME_INDEX;
|
||||||
void setAnimationFrameIndex(float value);
|
void setAnimationFrameIndex(float value);
|
||||||
|
@ -121,6 +126,7 @@ protected:
|
||||||
|
|
||||||
rgbColor _color;
|
rgbColor _color;
|
||||||
QString _modelURL;
|
QString _modelURL;
|
||||||
|
QString _collisionModelURL;
|
||||||
|
|
||||||
quint64 _lastAnimated;
|
quint64 _lastAnimated;
|
||||||
QString _animationURL;
|
QString _animationURL;
|
||||||
|
|
|
@ -295,7 +295,11 @@ public:
|
||||||
|
|
||||||
Tokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { }
|
Tokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { }
|
||||||
|
|
||||||
enum SpecialToken { DATUM_TOKEN = 0x100 };
|
enum SpecialToken {
|
||||||
|
NO_TOKEN = -1,
|
||||||
|
NO_PUSHBACKED_TOKEN = -1,
|
||||||
|
DATUM_TOKEN = 0x100
|
||||||
|
};
|
||||||
|
|
||||||
int nextToken();
|
int nextToken();
|
||||||
const QByteArray& getDatum() const { return _datum; }
|
const QByteArray& getDatum() const { return _datum; }
|
||||||
|
@ -311,9 +315,9 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
int Tokenizer::nextToken() {
|
int Tokenizer::nextToken() {
|
||||||
if (_pushedBackToken != -1) {
|
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
|
||||||
int token = _pushedBackToken;
|
int token = _pushedBackToken;
|
||||||
_pushedBackToken = -1;
|
_pushedBackToken = NO_PUSHBACKED_TOKEN;
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +365,7 @@ int Tokenizer::nextToken() {
|
||||||
return DATUM_TOKEN;
|
return DATUM_TOKEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return NO_TOKEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
FBXNode parseTextFBXNode(Tokenizer& tokenizer) {
|
FBXNode parseTextFBXNode(Tokenizer& tokenizer) {
|
||||||
|
@ -378,7 +382,7 @@ FBXNode parseTextFBXNode(Tokenizer& tokenizer) {
|
||||||
|
|
||||||
int token;
|
int token;
|
||||||
bool expectingDatum = true;
|
bool expectingDatum = true;
|
||||||
while ((token = tokenizer.nextToken()) != -1) {
|
while ((token = tokenizer.nextToken()) != Tokenizer::NO_TOKEN) {
|
||||||
if (token == '{') {
|
if (token == '{') {
|
||||||
for (FBXNode child = parseTextFBXNode(tokenizer); !child.name.isNull(); child = parseTextFBXNode(tokenizer)) {
|
for (FBXNode child = parseTextFBXNode(tokenizer); !child.name.isNull(); child = parseTextFBXNode(tokenizer)) {
|
||||||
node.children.append(child);
|
node.children.append(child);
|
||||||
|
|
|
@ -152,8 +152,6 @@ public:
|
||||||
|
|
||||||
bool hasSpecularTexture() const;
|
bool hasSpecularTexture() const;
|
||||||
bool hasEmissiveTexture() const;
|
bool hasEmissiveTexture() const;
|
||||||
|
|
||||||
model::Mesh _mesh;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A single animation frame extracted from an FBX document.
|
/// A single animation frame extracted from an FBX document.
|
||||||
|
|
287
libraries/fbx/src/OBJReader.cpp
Normal file
287
libraries/fbx/src/OBJReader.cpp
Normal file
|
@ -0,0 +1,287 @@
|
||||||
|
//
|
||||||
|
// OBJReader.cpp
|
||||||
|
// libraries/fbx/src/
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 3/7/15.
|
||||||
|
// Copyright 2013 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// http://en.wikipedia.org/wiki/Wavefront_.obj_file
|
||||||
|
// http://www.scratchapixel.com/old/lessons/3d-advanced-lessons/obj-file-format/obj-file-format/
|
||||||
|
// http://paulbourke.net/dataformats/obj/
|
||||||
|
|
||||||
|
|
||||||
|
#include <QBuffer>
|
||||||
|
#include <QIODevice>
|
||||||
|
|
||||||
|
#include "FBXReader.h"
|
||||||
|
#include "OBJReader.h"
|
||||||
|
#include "Shape.h"
|
||||||
|
|
||||||
|
|
||||||
|
class OBJTokenizer {
|
||||||
|
public:
|
||||||
|
OBJTokenizer(QIODevice* device) : _device(device), _pushedBackToken(-1) { }
|
||||||
|
enum SpecialToken {
|
||||||
|
NO_TOKEN = -1,
|
||||||
|
NO_PUSHBACKED_TOKEN = -1,
|
||||||
|
DATUM_TOKEN = 0x100
|
||||||
|
};
|
||||||
|
int nextToken();
|
||||||
|
const QByteArray& getDatum() const { return _datum; }
|
||||||
|
void skipLine() { _device->readLine(); }
|
||||||
|
void pushBackToken(int token) { _pushedBackToken = token; }
|
||||||
|
void ungetChar(char ch) { _device->ungetChar(ch); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QIODevice* _device;
|
||||||
|
QByteArray _datum;
|
||||||
|
int _pushedBackToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int OBJTokenizer::nextToken() {
|
||||||
|
if (_pushedBackToken != NO_PUSHBACKED_TOKEN) {
|
||||||
|
int token = _pushedBackToken;
|
||||||
|
_pushedBackToken = NO_PUSHBACKED_TOKEN;
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
char ch;
|
||||||
|
while (_device->getChar(&ch)) {
|
||||||
|
if (QChar(ch).isSpace()) {
|
||||||
|
continue; // skip whitespace
|
||||||
|
}
|
||||||
|
switch (ch) {
|
||||||
|
case '#':
|
||||||
|
_device->readLine(); // skip the comment
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\"':
|
||||||
|
_datum = "";
|
||||||
|
while (_device->getChar(&ch)) {
|
||||||
|
if (ch == '\"') { // end on closing quote
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ch == '\\') { // handle escaped quotes
|
||||||
|
if (_device->getChar(&ch) && ch != '\"') {
|
||||||
|
_datum.append('\\');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_datum.append(ch);
|
||||||
|
}
|
||||||
|
return DATUM_TOKEN;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_datum = "";
|
||||||
|
_datum.append(ch);
|
||||||
|
while (_device->getChar(&ch)) {
|
||||||
|
if (QChar(ch).isSpace() || ch == '\"') {
|
||||||
|
ungetChar(ch); // read until we encounter a special character, then replace it
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_datum.append(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DATUM_TOKEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NO_TOKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, FBXGeometry &geometry) {
|
||||||
|
FBXMesh &mesh = geometry.meshes[0];
|
||||||
|
mesh.parts.append(FBXMeshPart());
|
||||||
|
FBXMeshPart &meshPart = mesh.parts.last();
|
||||||
|
bool sawG = false;
|
||||||
|
bool result = true;
|
||||||
|
|
||||||
|
meshPart.materialID = QString("dontknow") + QString::number(mesh.parts.count());
|
||||||
|
meshPart.opacity = 1.0;
|
||||||
|
meshPart._material = model::MaterialPointer(new model::Material());
|
||||||
|
meshPart._material->setDiffuse(glm::vec3(1.0, 1.0, 1.0));
|
||||||
|
meshPart._material->setOpacity(1.0);
|
||||||
|
meshPart._material->setSpecular(glm::vec3(1.0, 1.0, 1.0));
|
||||||
|
meshPart._material->setShininess(96.0);
|
||||||
|
meshPart._material->setEmissive(glm::vec3(0.0, 0.0, 0.0));
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||||
|
result = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QByteArray token = tokenizer.getDatum();
|
||||||
|
if (token == "g") {
|
||||||
|
if (sawG) {
|
||||||
|
// we've encountered the beginning of the next group.
|
||||||
|
tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sawG = true;
|
||||||
|
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
QByteArray groupName = tokenizer.getDatum();
|
||||||
|
meshPart.materialID = groupName;
|
||||||
|
} else if (token == "v") {
|
||||||
|
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
float x = std::stof(tokenizer.getDatum().data());
|
||||||
|
// notice the order of z and y -- in OBJ files, up is the 3rd value
|
||||||
|
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
float z = std::stof(tokenizer.getDatum().data());
|
||||||
|
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
float y = std::stof(tokenizer.getDatum().data());
|
||||||
|
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// the spec gets vague here. might be w, might be a color... chop it off.
|
||||||
|
tokenizer.skipLine();
|
||||||
|
mesh.vertices.append(glm::vec3(x, y, z));
|
||||||
|
mesh.colors.append(glm::vec3(1, 1, 1));
|
||||||
|
} else if (token == "f") {
|
||||||
|
// a face can have 3 or more vertices
|
||||||
|
QVector<int> indices;
|
||||||
|
while (true) {
|
||||||
|
if (tokenizer.nextToken() != OBJTokenizer::DATUM_TOKEN) { goto done; }
|
||||||
|
try {
|
||||||
|
int vertexIndex = std::stoi(tokenizer.getDatum().data());
|
||||||
|
// negative indexes count backward from the current end of the vertex list
|
||||||
|
vertexIndex = (vertexIndex >= 0 ? vertexIndex : mesh.vertices.count() + vertexIndex + 1);
|
||||||
|
// obj index is 1 based
|
||||||
|
assert(vertexIndex >= 1);
|
||||||
|
indices.append(vertexIndex - 1);
|
||||||
|
}
|
||||||
|
catch(const std::exception& e) {
|
||||||
|
// wasn't a number, but it back.
|
||||||
|
tokenizer.pushBackToken(OBJTokenizer::DATUM_TOKEN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (indices.count() == 3) {
|
||||||
|
// flip these around (because of the y/z swap above) so our triangles face outward
|
||||||
|
meshPart.triangleIndices.append(indices[0]);
|
||||||
|
meshPart.triangleIndices.append(indices[2]);
|
||||||
|
meshPart.triangleIndices.append(indices[1]);
|
||||||
|
} else if (indices.count() == 4) {
|
||||||
|
meshPart.quadIndices << indices;
|
||||||
|
} else {
|
||||||
|
qDebug() << "no support for more than 4 vertices on a face in OBJ files";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// something we don't (yet) care about
|
||||||
|
qDebug() << "OBJ parser is skipping a line with" << token;
|
||||||
|
tokenizer.skipLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FBXGeometry extractOBJGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
||||||
|
FBXGeometry geometry;
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping) {
|
||||||
|
QBuffer buffer(const_cast<QByteArray*>(&model));
|
||||||
|
buffer.open(QIODevice::ReadOnly);
|
||||||
|
return readOBJ(&buffer, mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping) {
|
||||||
|
FBXGeometry geometry;
|
||||||
|
OBJTokenizer tokenizer(device);
|
||||||
|
|
||||||
|
geometry.meshExtents.reset();
|
||||||
|
geometry.meshes.append(FBXMesh());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
// call parseOBJGroup as long as it's returning true. Each successful call will
|
||||||
|
// add a new meshPart to the geometry's single mesh.
|
||||||
|
bool success = true;
|
||||||
|
while (success) {
|
||||||
|
success = parseOBJGroup(tokenizer, mapping, geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
FBXMesh &mesh = geometry.meshes[0];
|
||||||
|
|
||||||
|
mesh.meshExtents.reset();
|
||||||
|
foreach (const glm::vec3& vertex, mesh.vertices) {
|
||||||
|
mesh.meshExtents.addPoint(vertex);
|
||||||
|
geometry.meshExtents.addPoint(vertex);
|
||||||
|
}
|
||||||
|
|
||||||
|
geometry.joints.resize(1);
|
||||||
|
geometry.joints[0].isFree = false;
|
||||||
|
// geometry.joints[0].freeLineage;
|
||||||
|
geometry.joints[0].parentIndex = -1;
|
||||||
|
geometry.joints[0].distanceToParent = 0;
|
||||||
|
geometry.joints[0].boneRadius = 0;
|
||||||
|
geometry.joints[0].translation = glm::vec3(0, 0, 0);
|
||||||
|
// geometry.joints[0].preTransform = ;
|
||||||
|
geometry.joints[0].preRotation = glm::quat(0, 0, 0, 1);
|
||||||
|
geometry.joints[0].rotation = glm::quat(0, 0, 0, 1);
|
||||||
|
geometry.joints[0].postRotation = glm::quat(0, 0, 0, 1);
|
||||||
|
// geometry.joints[0].postTransform = ;
|
||||||
|
// geometry.joints[0].transform = ;
|
||||||
|
geometry.joints[0].rotationMin = glm::vec3(0, 0, 0);
|
||||||
|
geometry.joints[0].rotationMax = glm::vec3(0, 0, 0);
|
||||||
|
geometry.joints[0].inverseDefaultRotation = glm::quat(0, 0, 0, 1);
|
||||||
|
geometry.joints[0].inverseBindRotation = glm::quat(0, 0, 0, 1);
|
||||||
|
// geometry.joints[0].bindTransform = ;
|
||||||
|
geometry.joints[0].name = "OBJ";
|
||||||
|
geometry.joints[0].shapePosition = glm::vec3(0, 0, 0);
|
||||||
|
geometry.joints[0].shapeRotation = glm::quat(0, 0, 0, 1);
|
||||||
|
geometry.joints[0].shapeType = SPHERE_SHAPE;
|
||||||
|
geometry.joints[0].isSkeletonJoint = false;
|
||||||
|
|
||||||
|
// add bogus normal data for this mesh
|
||||||
|
mesh.normals.fill(glm::vec3(0,0,0), mesh.vertices.count());
|
||||||
|
mesh.tangents.fill(glm::vec3(0,0,0), mesh.vertices.count());
|
||||||
|
|
||||||
|
foreach (FBXMeshPart meshPart, mesh.parts) {
|
||||||
|
int triCount = meshPart.triangleIndices.count() / 3;
|
||||||
|
for (int i = 0; i < triCount; i++) {
|
||||||
|
int p0Index = meshPart.triangleIndices[i*3];
|
||||||
|
int p1Index = meshPart.triangleIndices[i*3+1];
|
||||||
|
int p2Index = meshPart.triangleIndices[i*3+2];
|
||||||
|
|
||||||
|
glm::vec3 p0 = mesh.vertices[p0Index];
|
||||||
|
glm::vec3 p1 = mesh.vertices[p1Index];
|
||||||
|
glm::vec3 p2 = mesh.vertices[p2Index];
|
||||||
|
|
||||||
|
glm::vec3 n = glm::cross(p1 - p0, p2 - p0);
|
||||||
|
glm::vec3 t = glm::cross(p2 - p0, n);
|
||||||
|
|
||||||
|
mesh.normals[p0Index] = n;
|
||||||
|
mesh.normals[p1Index] = n;
|
||||||
|
mesh.normals[p2Index] = n;
|
||||||
|
|
||||||
|
mesh.tangents[p0Index] = t;
|
||||||
|
mesh.tangents[p1Index] = t;
|
||||||
|
mesh.tangents[p2Index] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(const std::exception& e) {
|
||||||
|
qDebug() << "something went wrong in OBJ reader";
|
||||||
|
}
|
||||||
|
|
||||||
|
return geometry;
|
||||||
|
}
|
6
libraries/fbx/src/OBJReader.h
Normal file
6
libraries/fbx/src/OBJReader.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include "FBXReader.h"
|
||||||
|
|
||||||
|
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping);
|
||||||
|
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping);
|
|
@ -114,13 +114,14 @@ vec4 evalAtmosphereContribution(Atmosphere atmospheric, vec3 position, vec3 came
|
||||||
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
//gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
float fSampleLength = fFar / fSamples;
|
float fSampleLength = fFar / fSamples;
|
||||||
float fScaledLength = fSampleLength * fScale;
|
float fScaledLength = fSampleLength * fScale;
|
||||||
|
|
||||||
vec3 v3SampleRay = v3Ray * fSampleLength;
|
vec3 v3SampleRay = v3Ray * fSampleLength;
|
||||||
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5;
|
||||||
|
|
||||||
// Now loop through the sample rays
|
// Now loop through the sample rays
|
||||||
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
vec3 v3FrontColor = vec3(0.0, 0.0, 0.0);
|
||||||
int nSamples = numSamples;
|
// int nSamples = numSamples;
|
||||||
// int nSamples = int(fSamples);
|
int nSamples = int(fSamples);
|
||||||
for(int i=0; i<nSamples; i++)
|
for(int i=0; i<nSamples; i++)
|
||||||
{
|
{
|
||||||
float fHeight = length(v3SamplePoint);
|
float fHeight = length(v3SamplePoint);
|
||||||
|
|
|
@ -76,26 +76,26 @@ public:
|
||||||
void setOpacity(float opacity);
|
void setOpacity(float opacity);
|
||||||
|
|
||||||
// Schema to access the attribute values of the material
|
// Schema to access the attribute values of the material
|
||||||
class Schema {
|
class Schema {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Color _diffuse;
|
Color _diffuse;
|
||||||
float _opacity;
|
float _opacity;
|
||||||
Color _specular;
|
Color _specular;
|
||||||
float _shininess;
|
float _shininess;
|
||||||
Color _emissive;
|
Color _emissive;
|
||||||
float _spare0;
|
float _spare0;
|
||||||
|
|
||||||
Schema() :
|
Schema() :
|
||||||
_diffuse(0.5f),
|
_diffuse(0.5f),
|
||||||
_opacity(1.0f),
|
_opacity(1.0f),
|
||||||
_specular(0.03f),
|
_specular(0.03f),
|
||||||
_shininess(0.1f),
|
_shininess(0.1f),
|
||||||
_emissive(0.0f)
|
_emissive(0.0f)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; }
|
const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; }
|
||||||
|
|
||||||
void setTextureView(MapChannel channel, const TextureView& texture);
|
void setTextureView(MapChannel channel, const TextureView& texture);
|
||||||
const TextureMap& getTextureMap() const { return _textureMap; }
|
const TextureMap& getTextureMap() const { return _textureMap; }
|
||||||
|
|
|
@ -26,14 +26,14 @@ class Assignment : public NodeData {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
AudioMixerType,
|
AudioMixerType = 0,
|
||||||
AvatarMixerType,
|
AvatarMixerType = 1,
|
||||||
AgentType,
|
AgentType = 2,
|
||||||
UNUSED_0,
|
UNUSED_0 = 3,
|
||||||
UNUSED_1,
|
UNUSED_1 = 4,
|
||||||
UNUSED_2,
|
UNUSED_2 = 5,
|
||||||
EntityServerType,
|
EntityServerType = 6,
|
||||||
AllTypes
|
AllTypes = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Command {
|
enum Command {
|
||||||
|
|
|
@ -48,7 +48,8 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short
|
||||||
_localSockAddr(),
|
_localSockAddr(),
|
||||||
_publicSockAddr(),
|
_publicSockAddr(),
|
||||||
_stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT),
|
_stunSockAddr(STUN_SERVER_HOSTNAME, STUN_SERVER_PORT),
|
||||||
_packetStatTimer()
|
_packetStatTimer(),
|
||||||
|
_thisNodeCanAdjustLocks(false)
|
||||||
{
|
{
|
||||||
static bool firstCall = true;
|
static bool firstCall = true;
|
||||||
if (firstCall) {
|
if (firstCall) {
|
||||||
|
|
|
@ -216,7 +216,6 @@ protected:
|
||||||
void handleNodeKill(const SharedNodePointer& node);
|
void handleNodeKill(const SharedNodePointer& node);
|
||||||
|
|
||||||
QUuid _sessionUUID;
|
QUuid _sessionUUID;
|
||||||
bool _thisNodeCanAdjustLocks;
|
|
||||||
NodeHash _nodeHash;
|
NodeHash _nodeHash;
|
||||||
QReadWriteLock _nodeMutex;
|
QReadWriteLock _nodeMutex;
|
||||||
QUdpSocket _nodeSocket;
|
QUdpSocket _nodeSocket;
|
||||||
|
@ -230,6 +229,7 @@ protected:
|
||||||
int _numCollectedBytes;
|
int _numCollectedBytes;
|
||||||
|
|
||||||
QElapsedTimer _packetStatTimer;
|
QElapsedTimer _packetStatTimer;
|
||||||
|
bool _thisNodeCanAdjustLocks;
|
||||||
|
|
||||||
template<typename IteratorLambda>
|
template<typename IteratorLambda>
|
||||||
void eachNodeHashIterator(IteratorLambda functor) {
|
void eachNodeHashIterator(IteratorLambda functor) {
|
||||||
|
|
|
@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
||||||
return 1;
|
return 1;
|
||||||
case PacketTypeEntityAddOrEdit:
|
case PacketTypeEntityAddOrEdit:
|
||||||
case PacketTypeEntityData:
|
case PacketTypeEntityData:
|
||||||
return VERSION_ENTITIES_USE_METERS_AND_RADIANS;
|
return VERSION_ENTITIES_HAS_COLLISION_MODEL;
|
||||||
case PacketTypeEntityErase:
|
case PacketTypeEntityErase:
|
||||||
return 2;
|
return 2;
|
||||||
case PacketTypeAudioStreamStats:
|
case PacketTypeAudioStreamStats:
|
||||||
|
|
|
@ -131,6 +131,7 @@ const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8;
|
||||||
const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = 9;
|
const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = 9;
|
||||||
const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10;
|
const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10;
|
||||||
const PacketVersion VERSION_ENTITIES_USE_METERS_AND_RADIANS = 11;
|
const PacketVersion VERSION_ENTITIES_USE_METERS_AND_RADIANS = 11;
|
||||||
|
const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12;
|
||||||
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
||||||
|
|
||||||
#endif // hifi_PacketHeaders_h
|
#endif // hifi_PacketHeaders_h
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "ShapeInfoUtil.h"
|
#include "ShapeInfoUtil.h"
|
||||||
#include "PhysicsHelpers.h"
|
#include "PhysicsHelpers.h"
|
||||||
#include "ThreadSafeDynamicsWorld.h"
|
#include "ThreadSafeDynamicsWorld.h"
|
||||||
|
#include "AvatarData.h"
|
||||||
|
|
||||||
static uint32_t _numSubsteps;
|
static uint32_t _numSubsteps;
|
||||||
|
|
||||||
|
@ -286,6 +287,20 @@ void PhysicsEngine::stepSimulation() {
|
||||||
_clock.reset();
|
_clock.reset();
|
||||||
float timeStep = btMin(dt, MAX_TIMESTEP);
|
float timeStep = btMin(dt, MAX_TIMESTEP);
|
||||||
|
|
||||||
|
if (_avatarData->isPhysicsEnabled()) {
|
||||||
|
_avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
|
||||||
|
glmToBullet(_avatarData->getPosition())));
|
||||||
|
// WORKAROUND: there is a bug in the debug Bullet-2.82 libs where a zero length walk velocity will trigger
|
||||||
|
// an assert when the getNormalizedVector() helper function in btKinematicCharacterController.cpp tries to
|
||||||
|
// first normalize a vector before checking its length. Here we workaround the problem by checking the
|
||||||
|
// length first. NOTE: the character's velocity is reset to zero after each step, so when we DON'T set
|
||||||
|
// the velocity for this time interval it is the same thing as setting its velocity to zero.
|
||||||
|
btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity());
|
||||||
|
if (walkVelocity.length2() > FLT_EPSILON * FLT_EPSILON) {
|
||||||
|
_characterController->setVelocityForTimeInterval(walkVelocity, timeStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is step (2).
|
// This is step (2).
|
||||||
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||||
_numSubsteps += (uint32_t)numSubsteps;
|
_numSubsteps += (uint32_t)numSubsteps;
|
||||||
|
@ -302,9 +317,18 @@ void PhysicsEngine::stepSimulation() {
|
||||||
//
|
//
|
||||||
// TODO: untangle these lock sequences.
|
// TODO: untangle these lock sequences.
|
||||||
_entityTree->lockForWrite();
|
_entityTree->lockForWrite();
|
||||||
|
_avatarData->lockForWrite();
|
||||||
lock();
|
lock();
|
||||||
_dynamicsWorld->synchronizeMotionStates();
|
_dynamicsWorld->synchronizeMotionStates();
|
||||||
|
|
||||||
|
if (_avatarData->isPhysicsEnabled()) {
|
||||||
|
const btTransform& avatarTransform = _avatarGhostObject->getWorldTransform();
|
||||||
|
_avatarData->setOrientation(bulletToGLM(avatarTransform.getRotation()));
|
||||||
|
_avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()));
|
||||||
|
}
|
||||||
|
|
||||||
unlock();
|
unlock();
|
||||||
|
_avatarData->unlock();
|
||||||
_entityTree->unlock();
|
_entityTree->unlock();
|
||||||
|
|
||||||
computeCollisionEvents();
|
computeCollisionEvents();
|
||||||
|
@ -582,3 +606,32 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio
|
||||||
body->activate();
|
body->activate();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void PhysicsEngine::setAvatarData(AvatarData *avatarData) {
|
||||||
|
_avatarData = avatarData;
|
||||||
|
_avatarGhostObject = new btPairCachingGhostObject();
|
||||||
|
_avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
|
||||||
|
glmToBullet(_avatarData->getPosition())));
|
||||||
|
|
||||||
|
// XXX these values should be computed from the character model.
|
||||||
|
btScalar characterRadius = 0.3;
|
||||||
|
btScalar characterHeight = 1.75 - 2.0f * characterRadius;
|
||||||
|
btScalar stepHeight = btScalar(0.35);
|
||||||
|
|
||||||
|
btConvexShape* capsule = new btCapsuleShape(characterRadius, characterHeight);
|
||||||
|
_avatarGhostObject->setCollisionShape(capsule);
|
||||||
|
_avatarGhostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT);
|
||||||
|
|
||||||
|
_characterController = new btKinematicCharacterController(_avatarGhostObject, capsule, stepHeight);
|
||||||
|
|
||||||
|
_dynamicsWorld->addCollisionObject(_avatarGhostObject, btBroadphaseProxy::CharacterFilter,
|
||||||
|
btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter);
|
||||||
|
_dynamicsWorld->addAction(_characterController);
|
||||||
|
_characterController->reset (_dynamicsWorld);
|
||||||
|
// _characterController->warp (btVector3(10.210001,-2.0306311,16.576973));
|
||||||
|
|
||||||
|
btGhostPairCallback* ghostPairCallback = new btGhostPairCallback();
|
||||||
|
_dynamicsWorld->getPairCache()->setInternalGhostPairCallback(ghostPairCallback);
|
||||||
|
}
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <btBulletDynamicsCommon.h>
|
#include <btBulletDynamicsCommon.h>
|
||||||
|
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
|
||||||
|
#include <BulletCollision/CollisionDispatch/btGhostObject.h>
|
||||||
|
#include <BulletDynamics/Character/btCharacterControllerInterface.h>
|
||||||
|
#include <BulletCollision/CollisionShapes/btCapsuleShape.h>
|
||||||
|
#include <BulletDynamics/Character/btKinematicCharacterController.h>
|
||||||
|
|
||||||
#include <EntityItem.h>
|
#include <EntityItem.h>
|
||||||
#include <EntitySimulation.h>
|
#include <EntitySimulation.h>
|
||||||
|
@ -25,6 +30,7 @@
|
||||||
#include "EntityMotionState.h"
|
#include "EntityMotionState.h"
|
||||||
#include "ShapeManager.h"
|
#include "ShapeManager.h"
|
||||||
#include "ThreadSafeDynamicsWorld.h"
|
#include "ThreadSafeDynamicsWorld.h"
|
||||||
|
#include "AvatarData.h"
|
||||||
|
|
||||||
const float HALF_SIMULATION_EXTENT = 512.0f; // meters
|
const float HALF_SIMULATION_EXTENT = 512.0f; // meters
|
||||||
|
|
||||||
|
@ -82,6 +88,8 @@ public:
|
||||||
/// process queue of changed from external sources
|
/// process queue of changed from external sources
|
||||||
void relayIncomingChangesToSimulation();
|
void relayIncomingChangesToSimulation();
|
||||||
|
|
||||||
|
void setAvatarData(AvatarData *avatarData);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// \param motionState pointer to Object's MotionState
|
/// \param motionState pointer to Object's MotionState
|
||||||
void removeObjectFromBullet(ObjectMotionState* motionState);
|
void removeObjectFromBullet(ObjectMotionState* motionState);
|
||||||
|
@ -113,6 +121,11 @@ private:
|
||||||
ContactMap _contactMap;
|
ContactMap _contactMap;
|
||||||
uint32_t _numContactFrames = 0;
|
uint32_t _numContactFrames = 0;
|
||||||
uint32_t _lastNumSubstepsAtUpdateInternal = 0;
|
uint32_t _lastNumSubstepsAtUpdateInternal = 0;
|
||||||
|
|
||||||
|
/// character collisions
|
||||||
|
btCharacterControllerInterface* _characterController = 0;
|
||||||
|
class btPairCachingGhostObject* _avatarGhostObject = 0;
|
||||||
|
AvatarData *_avatarData = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_PhysicsEngine_h
|
#endif // hifi_PhysicsEngine_h
|
||||||
|
|
|
@ -61,6 +61,8 @@ public:
|
||||||
|
|
||||||
bool getShapeCollisions(const Shape* shape, CollisionList& collisions) const;
|
bool getShapeCollisions(const Shape* shape, CollisionList& collisions) const;
|
||||||
|
|
||||||
|
void setupAvatarCollision();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void integrate(float deltaTime);
|
void integrate(float deltaTime);
|
||||||
|
|
||||||
|
|
|
@ -2084,6 +2084,7 @@ void GeometryReader::run() {
|
||||||
urlValid &= !urlname.isEmpty();
|
urlValid &= !urlname.isEmpty();
|
||||||
urlValid &= !_url.path().isEmpty();
|
urlValid &= !_url.path().isEmpty();
|
||||||
urlValid &= _url.path().toLower().endsWith(".fbx")
|
urlValid &= _url.path().toLower().endsWith(".fbx")
|
||||||
|
|| _url.path().toLower().endsWith(".obj")
|
||||||
|| _url.path().toLower().endsWith(".svo");
|
|| _url.path().toLower().endsWith(".svo");
|
||||||
|
|
||||||
if (urlValid) {
|
if (urlValid) {
|
||||||
|
@ -2101,6 +2102,8 @@ void GeometryReader::run() {
|
||||||
lightmapLevel = 3.5f;
|
lightmapLevel = 3.5f;
|
||||||
}
|
}
|
||||||
fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel);
|
fbxgeo = readFBX(_reply, _mapping, grabLightmaps, lightmapLevel);
|
||||||
|
} else if (_url.path().toLower().endsWith(".obj")) {
|
||||||
|
fbxgeo = readOBJ(_reply, _mapping);
|
||||||
}
|
}
|
||||||
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));
|
QMetaObject::invokeMethod(geometry.data(), "setGeometry", Q_ARG(const FBXGeometry&, fbxgeo));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <ResourceCache.h>
|
#include <ResourceCache.h>
|
||||||
|
|
||||||
#include <FBXReader.h>
|
#include <FBXReader.h>
|
||||||
|
#include <OBJReader.h>
|
||||||
|
|
||||||
#include <AnimationCache.h>
|
#include <AnimationCache.h>
|
||||||
|
|
||||||
|
|
|
@ -198,51 +198,51 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo
|
||||||
locations.emissiveTextureUnit = -1;
|
locations.emissiveTextureUnit = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bindable uniform version
|
// bindable uniform version
|
||||||
#if defined(Q_OS_MAC)
|
#if defined(Q_OS_MAC)
|
||||||
loc = program.uniformLocation("materialBuffer");
|
loc = program.uniformLocation("materialBuffer");
|
||||||
if (loc >= 0) {
|
if (loc >= 0) {
|
||||||
locations.materialBufferUnit = loc;
|
locations.materialBufferUnit = loc;
|
||||||
} else {
|
} else {
|
||||||
locations.materialBufferUnit = -1;
|
locations.materialBufferUnit = -1;
|
||||||
}
|
}
|
||||||
#elif defined(Q_OS_WIN)
|
#elif defined(Q_OS_WIN)
|
||||||
loc = glGetUniformBlockIndex(program.programId(), "materialBuffer");
|
loc = glGetUniformBlockIndex(program.programId(), "materialBuffer");
|
||||||
if (loc >= 0) {
|
if (loc >= 0) {
|
||||||
glUniformBlockBinding(program.programId(), loc, 1);
|
glUniformBlockBinding(program.programId(), loc, 1);
|
||||||
locations.materialBufferUnit = 1;
|
locations.materialBufferUnit = 1;
|
||||||
} else {
|
} else {
|
||||||
locations.materialBufferUnit = -1;
|
locations.materialBufferUnit = -1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
loc = program.uniformLocation("materialBuffer");
|
loc = program.uniformLocation("materialBuffer");
|
||||||
if (loc >= 0) {
|
if (loc >= 0) {
|
||||||
locations.materialBufferUnit = loc;
|
locations.materialBufferUnit = loc;
|
||||||
} else {
|
} else {
|
||||||
locations.materialBufferUnit = -1;
|
locations.materialBufferUnit = -1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
loc = glGetUniformBlockIndex(program.programId(), "transformObjectBuffer");
|
loc = glGetUniformBlockIndex(program.programId(), "transformObjectBuffer");
|
||||||
if (loc >= 0) {
|
if (loc >= 0) {
|
||||||
glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_OBJECT_SLOT);
|
glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_OBJECT_SLOT);
|
||||||
// locations.materialBufferUnit = 1;
|
// locations.materialBufferUnit = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
loc = glGetUniformBlockIndex(program.programId(), "transformCameraBuffer");
|
loc = glGetUniformBlockIndex(program.programId(), "transformCameraBuffer");
|
||||||
if (loc >= 0) {
|
if (loc >= 0) {
|
||||||
glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_CAMERA_SLOT);
|
glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_CAMERA_SLOT);
|
||||||
// locations.materialBufferUnit = 1;
|
// locations.materialBufferUnit = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//program.link();
|
//program.link();
|
||||||
if (!program.isLinked()) {
|
if (!program.isLinked()) {
|
||||||
program.release();
|
program.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
program.release();
|
program.release();
|
||||||
}
|
}
|
||||||
|
@ -385,7 +385,6 @@ void Model::init() {
|
||||||
_program.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
_program.addShaderFromSourceCode(QGLShader::Vertex, model_vert);
|
||||||
_program.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
_program.addShaderFromSourceCode(QGLShader::Fragment, model_frag);
|
||||||
initProgram(_program, _locations);
|
initProgram(_program, _locations);
|
||||||
|
|
||||||
|
|
||||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
_normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert);
|
||||||
_normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
_normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag);
|
||||||
|
@ -450,7 +449,7 @@ void Model::init() {
|
||||||
|
|
||||||
|
|
||||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert);
|
||||||
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
_skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag);
|
||||||
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
|
initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2554,16 +2553,16 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
|
||||||
qDebug() << "part INDEX:" << j;
|
qDebug() << "part INDEX:" << j;
|
||||||
qDebug() << "NEW part.materialID:" << part.materialID;
|
qDebug() << "NEW part.materialID:" << part.materialID;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locations->glowIntensity >= 0) {
|
if (locations->glowIntensity >= 0) {
|
||||||
GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity());
|
GLBATCH(glUniform1f)(locations->glowIntensity, glowEffect->getIntensity());
|
||||||
}
|
}
|
||||||
if (!(translucent && alphaThreshold == 0.0f)) {
|
if (!(translucent && alphaThreshold == 0.0f)) {
|
||||||
GLBATCH(glAlphaFunc)(GL_EQUAL, glowEffect->getIntensity());
|
GLBATCH(glAlphaFunc)(GL_EQUAL, glowEffect->getIntensity());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locations->materialBufferUnit >= 0) {
|
if (locations->materialBufferUnit >= 0) {
|
||||||
batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer());
|
batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer());
|
||||||
}
|
}
|
||||||
|
|
||||||
Texture* diffuseMap = networkPart.diffuseTexture.data();
|
Texture* diffuseMap = networkPart.diffuseTexture.data();
|
||||||
|
|
|
@ -32,6 +32,7 @@ enum ExamplePropertyList {
|
||||||
EXAMPLE_PROP_POSITION,
|
EXAMPLE_PROP_POSITION,
|
||||||
EXAMPLE_PROP_RADIUS,
|
EXAMPLE_PROP_RADIUS,
|
||||||
EXAMPLE_PROP_MODEL_URL,
|
EXAMPLE_PROP_MODEL_URL,
|
||||||
|
EXAMPLE_PROP_COLLISION_MODEL_URL,
|
||||||
EXAMPLE_PROP_ROTATION,
|
EXAMPLE_PROP_ROTATION,
|
||||||
EXAMPLE_PROP_COLOR,
|
EXAMPLE_PROP_COLOR,
|
||||||
EXAMPLE_PROP_SCRIPT,
|
EXAMPLE_PROP_SCRIPT,
|
||||||
|
@ -73,6 +74,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
||||||
props.setHasProperty(PROP_POSITION);
|
props.setHasProperty(PROP_POSITION);
|
||||||
props.setHasProperty(PROP_RADIUS);
|
props.setHasProperty(PROP_RADIUS);
|
||||||
props.setHasProperty(PROP_MODEL_URL);
|
props.setHasProperty(PROP_MODEL_URL);
|
||||||
|
props.setHasProperty(PROP_COLLISION_MODEL_URL);
|
||||||
props.setHasProperty(PROP_ROTATION);
|
props.setHasProperty(PROP_ROTATION);
|
||||||
|
|
||||||
QByteArray encoded = props.encode();
|
QByteArray encoded = props.encode();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
set(TARGET_NAME vhacd)
|
set(TARGET_NAME vhacd-util)
|
||||||
setup_hifi_project()
|
setup_hifi_project(Core Widgets)
|
||||||
link_hifi_libraries(shared model fbx gpu networking octree)
|
link_hifi_libraries(shared model fbx gpu networking octree)
|
||||||
|
|
||||||
#find_package(VHACD REQUIRED) done in CMakeList.txt in parent directory
|
#find_package(VHACD REQUIRED) done in CMakeList.txt in parent directory
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
|
|
||||||
//Read all the meshes from provided FBX file
|
//Read all the meshes from provided FBX file
|
||||||
bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results){
|
bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *results) {
|
||||||
|
|
||||||
// open the fbx file
|
// open the fbx file
|
||||||
QFile fbx(filename);
|
QFile fbx(filename);
|
||||||
|
@ -24,11 +24,25 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re
|
||||||
std::cout << "Reading FBX.....\n";
|
std::cout << "Reading FBX.....\n";
|
||||||
|
|
||||||
QByteArray fbxContents = fbx.readAll();
|
QByteArray fbxContents = fbx.readAll();
|
||||||
FBXGeometry geometry = readFBX(fbxContents, QVariantHash());
|
|
||||||
|
|
||||||
|
FBXGeometry geometry;
|
||||||
|
|
||||||
|
if (filename.toLower().endsWith(".obj")) {
|
||||||
|
geometry = readOBJ(fbxContents, QVariantHash());
|
||||||
|
} else if (filename.toLower().endsWith(".fbx")) {
|
||||||
|
geometry = readFBX(fbxContents, QVariantHash());
|
||||||
|
} else {
|
||||||
|
qDebug() << "unknown file extension";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//results->meshCount = geometry.meshes.count();
|
//results->meshCount = geometry.meshes.count();
|
||||||
|
// qDebug() << "read in" << geometry.meshes.count() << "meshes";
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
foreach(FBXMesh mesh, geometry.meshes){
|
foreach(FBXMesh mesh, geometry.meshes) {
|
||||||
//get vertices for each mesh
|
//get vertices for each mesh
|
||||||
QVector<glm::vec3> vertices = mesh.vertices;
|
QVector<glm::vec3> vertices = mesh.vertices;
|
||||||
|
|
||||||
|
@ -40,9 +54,9 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, vhacd::LoadFBXResults *re
|
||||||
}
|
}
|
||||||
|
|
||||||
//only read meshes with triangles
|
//only read meshes with triangles
|
||||||
if (triangles.count() <= 0){
|
if (triangles.count() <= 0){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
results->perMeshVertices.append(vertices);
|
results->perMeshVertices.append(vertices);
|
||||||
results->perMeshTriangleIndices.append(triangles);
|
results->perMeshTriangleIndices.append(triangles);
|
||||||
count++;
|
count++;
|
||||||
|
@ -82,6 +96,23 @@ bool vhacd::VHACDUtil::computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD
|
||||||
for (unsigned int j = 0; j < nConvexHulls; j++){
|
for (unsigned int j = 0; j < nConvexHulls; j++){
|
||||||
VHACD::IVHACD::ConvexHull hull;
|
VHACD::IVHACD::ConvexHull hull;
|
||||||
interfaceVHACD->GetConvexHull(j, hull);
|
interfaceVHACD->GetConvexHull(j, hull);
|
||||||
|
|
||||||
|
double *m_points_copy = new double[hull.m_nPoints * 3];
|
||||||
|
// std::copy(std::begin(hull.m_points), std::end(hull.m_points), std::begin(m_points_copy));
|
||||||
|
for (unsigned int i=0; i<hull.m_nPoints * 3; i++) {
|
||||||
|
m_points_copy[ i ] = hull.m_points[ i ];
|
||||||
|
}
|
||||||
|
hull.m_points = m_points_copy;
|
||||||
|
|
||||||
|
|
||||||
|
int *m_triangles_copy = new int[hull.m_nTriangles * 3];
|
||||||
|
// std::copy(std::begin(hull.m_triangles), std::end(hull.m_triangles), std::begin(m_triangles_copy));
|
||||||
|
for (unsigned int i=0; i<hull.m_nTriangles * 3; i++) {
|
||||||
|
m_triangles_copy[ i ] = hull.m_triangles[ i ];
|
||||||
|
}
|
||||||
|
hull.m_triangles = m_triangles_copy;
|
||||||
|
|
||||||
|
|
||||||
convexHulls.append(hull);
|
convexHulls.append(hull);
|
||||||
}
|
}
|
||||||
results->convexHullList.append(convexHulls);
|
results->convexHullList.append(convexHulls);
|
||||||
|
|
|
@ -19,30 +19,31 @@
|
||||||
#include <chrono> //c++11 feature
|
#include <chrono> //c++11 feature
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <FBXReader.h>
|
#include <FBXReader.h>
|
||||||
|
#include <OBJReader.h>
|
||||||
#include <VHACD.h>
|
#include <VHACD.h>
|
||||||
|
|
||||||
namespace vhacd{
|
namespace vhacd {
|
||||||
|
|
||||||
typedef struct{
|
typedef struct {
|
||||||
int meshCount;
|
int meshCount;
|
||||||
QVector<int> convexHullsCountList;
|
QVector<int> convexHullsCountList;
|
||||||
QVector<QVector<VHACD::IVHACD::ConvexHull>> convexHullList;
|
QVector<QVector<VHACD::IVHACD::ConvexHull>> convexHullList;
|
||||||
}ComputeResults;
|
} ComputeResults;
|
||||||
|
|
||||||
typedef struct{
|
typedef struct {
|
||||||
int meshCount;
|
int meshCount;
|
||||||
QVector<QVector<glm::vec3>> perMeshVertices;
|
QVector<QVector<glm::vec3>> perMeshVertices;
|
||||||
QVector<QVector<int>> perMeshTriangleIndices;
|
QVector<QVector<int>> perMeshTriangleIndices;
|
||||||
}LoadFBXResults;
|
} LoadFBXResults;
|
||||||
|
|
||||||
class VHACDUtil{
|
class VHACDUtil {
|
||||||
public:
|
public:
|
||||||
bool loadFBX(const QString filename, vhacd::LoadFBXResults *results);
|
bool loadFBX(const QString filename, vhacd::LoadFBXResults *results);
|
||||||
bool computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params, vhacd::ComputeResults *results)const;
|
bool computeVHACD(vhacd::LoadFBXResults *meshes, VHACD::IVHACD::Parameters params, vhacd::ComputeResults *results)const;
|
||||||
~VHACDUtil();
|
~VHACDUtil();
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProgressCallback : public VHACD::IVHACD::IUserCallback{
|
class ProgressCallback : public VHACD::IVHACD::IUserCallback {
|
||||||
public:
|
public:
|
||||||
ProgressCallback(void);
|
ProgressCallback(void);
|
||||||
~ProgressCallback();
|
~ProgressCallback();
|
||||||
|
@ -52,4 +53,4 @@ namespace vhacd{
|
||||||
const char * const stage, const char * const operation);
|
const char * const stage, const char * const operation);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif //hifi_VHACDUtil_h
|
#endif //hifi_VHACDUtil_h
|
||||||
|
|
224
tools/vhacd/src/VHACDUtilApp.cpp
Normal file
224
tools/vhacd/src/VHACDUtilApp.cpp
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
//
|
||||||
|
// VHACDUtil.h
|
||||||
|
// tools/vhacd/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 3/5/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
#include <VHACD.h>
|
||||||
|
#include "VHACDUtilApp.h"
|
||||||
|
#include "VHACDUtil.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace VHACD;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QString formatFloat(double n) {
|
||||||
|
// limit precision to 6, but don't output trailing zeros.
|
||||||
|
QString s = QString::number(n, 'f', 6);
|
||||||
|
while (s.endsWith("0")) {
|
||||||
|
s.remove(s.size() - 1, 1);
|
||||||
|
}
|
||||||
|
if (s.endsWith(".")) {
|
||||||
|
s.remove(s.size() - 1, 1);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool writeOBJ(QString outFileName, QVector<QVector<VHACD::IVHACD::ConvexHull>>& meshList, bool outputOneMesh) {
|
||||||
|
QFile file(outFileName);
|
||||||
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
|
qDebug() << "Unable to write to " << outFileName;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream out(&file);
|
||||||
|
|
||||||
|
unsigned int pointStartOffset = 0;
|
||||||
|
|
||||||
|
foreach (QVector<VHACD::IVHACD::ConvexHull> hulls, meshList) {
|
||||||
|
unsigned int nth = 0;
|
||||||
|
foreach (VHACD::IVHACD::ConvexHull hull, hulls) {
|
||||||
|
out << "g hull-" << nth++ << "\n";
|
||||||
|
for (unsigned int i = 0; i < hull.m_nPoints; i++) {
|
||||||
|
out << "v ";
|
||||||
|
out << formatFloat(hull.m_points[i*3]) << " ";
|
||||||
|
// swap y and z because up is 3rd value in OBJ
|
||||||
|
out << formatFloat(hull.m_points[i*3+2]) << " ";
|
||||||
|
out << formatFloat(hull.m_points[i*3+1]) << "\n";
|
||||||
|
}
|
||||||
|
for (unsigned int i = 0; i < hull.m_nTriangles; i++) {
|
||||||
|
out << "f ";
|
||||||
|
// change order to flip normal (due to swapping y and z, above)
|
||||||
|
out << hull.m_triangles[i*3+1] + 1 + pointStartOffset << " ";
|
||||||
|
out << hull.m_triangles[i*3] + 1 + pointStartOffset << " ";
|
||||||
|
out << hull.m_triangles[i*3+2] + 1 + pointStartOffset << "\n";
|
||||||
|
}
|
||||||
|
out << "\n";
|
||||||
|
pointStartOffset += hull.m_nPoints;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
||||||
|
QCoreApplication(argc, argv)
|
||||||
|
{
|
||||||
|
vector<int> triangles; // array of indexes
|
||||||
|
vector<float> points; // array of coordinates
|
||||||
|
vhacd::VHACDUtil vUtil;
|
||||||
|
vhacd::LoadFBXResults fbx; //mesh data from loaded fbx file
|
||||||
|
vhacd::ComputeResults results; // results after computing vhacd
|
||||||
|
VHACD::IVHACD::Parameters params;
|
||||||
|
vhacd::ProgressCallback pCallBack;
|
||||||
|
|
||||||
|
|
||||||
|
// parse command-line
|
||||||
|
QCommandLineParser parser;
|
||||||
|
parser.setApplicationDescription("High Fidelity Object Decomposer");
|
||||||
|
parser.addHelpOption();
|
||||||
|
|
||||||
|
const QCommandLineOption helpOption = parser.addHelpOption();
|
||||||
|
|
||||||
|
const QCommandLineOption outputOneMeshOption("1", "output hulls as single mesh");
|
||||||
|
parser.addOption(outputOneMeshOption);
|
||||||
|
|
||||||
|
const QCommandLineOption inputFilenameOption("i", "input file", "filename.fbx");
|
||||||
|
parser.addOption(inputFilenameOption);
|
||||||
|
|
||||||
|
const QCommandLineOption outputFilenameOption("o", "output file", "filename.obj");
|
||||||
|
parser.addOption(outputFilenameOption);
|
||||||
|
|
||||||
|
|
||||||
|
if (!parser.parse(QCoreApplication::arguments())) {
|
||||||
|
qCritical() << parser.errorText() << endl;
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser.isSet(helpOption)) {
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool outputOneMesh = parser.isSet(outputOneMeshOption);
|
||||||
|
|
||||||
|
QString inputFilename;
|
||||||
|
// check for an assignment pool passed on the command line or in the config
|
||||||
|
if (parser.isSet(inputFilenameOption)) {
|
||||||
|
inputFilename = parser.value(inputFilenameOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString outputFilename;
|
||||||
|
// check for an assignment pool passed on the command line or in the config
|
||||||
|
if (parser.isSet(outputFilenameOption)) {
|
||||||
|
outputFilename = parser.value(outputFilenameOption);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (inputFilename == "") {
|
||||||
|
cerr << "input filename is required.";
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outputFilename == "") {
|
||||||
|
cerr << "output filename is required.";
|
||||||
|
parser.showHelp();
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//set parameters for V-HACD
|
||||||
|
params.m_callback = &pCallBack; //progress callback
|
||||||
|
params.m_resolution = 100000; // 100000
|
||||||
|
params.m_depth = 20; // 20
|
||||||
|
params.m_concavity = 0.001; // 0.001
|
||||||
|
params.m_delta = 0.01; // 0.05
|
||||||
|
params.m_planeDownsampling = 4; // 4
|
||||||
|
params.m_convexhullDownsampling = 4; // 4
|
||||||
|
params.m_alpha = 0.05; // 0.05 // controls the bias toward clipping along symmetry planes
|
||||||
|
params.m_beta = 0.05; // 0.05
|
||||||
|
params.m_gamma = 0.0005; // 0.0005
|
||||||
|
params.m_pca = 0; // 0 enable/disable normalizing the mesh before applying the convex decomposition
|
||||||
|
params.m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based
|
||||||
|
params.m_maxNumVerticesPerCH = 64; // 64
|
||||||
|
params.m_minVolumePerCH = 0.00001; // 0.0001
|
||||||
|
params.m_callback = 0; // 0
|
||||||
|
params.m_logger = 0; // 0
|
||||||
|
params.m_convexhullApproximation = true; // true
|
||||||
|
params.m_oclAcceleration = true; // true
|
||||||
|
|
||||||
|
// load the mesh
|
||||||
|
|
||||||
|
auto begin = std::chrono::high_resolution_clock::now();
|
||||||
|
if (!vUtil.loadFBX(inputFilename, &fbx)){
|
||||||
|
cout << "Error in opening FBX file....";
|
||||||
|
}
|
||||||
|
auto end = std::chrono::high_resolution_clock::now();
|
||||||
|
auto loadDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
|
||||||
|
|
||||||
|
//perform vhacd computation
|
||||||
|
begin = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
|
|
||||||
|
if (!vUtil.computeVHACD(&fbx, params, &results)){
|
||||||
|
cout << "Compute Failed...";
|
||||||
|
}
|
||||||
|
end = std::chrono::high_resolution_clock::now();
|
||||||
|
auto computeDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
|
||||||
|
|
||||||
|
int totalVertices = 0;
|
||||||
|
for (int i = 0; i < fbx.meshCount; i++){
|
||||||
|
totalVertices += fbx.perMeshVertices.at(i).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalTriangles = 0;
|
||||||
|
for (int i = 0; i < fbx.meshCount; i++){
|
||||||
|
totalTriangles += fbx.perMeshTriangleIndices.at(i).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
int totalHulls = 0;
|
||||||
|
QVector<int> hullCounts = results.convexHullsCountList;
|
||||||
|
for (int i = 0; i < results.meshCount; i++){
|
||||||
|
totalHulls += hullCounts.at(i);
|
||||||
|
}
|
||||||
|
cout << endl << "Summary of V-HACD Computation..................." << endl;
|
||||||
|
cout << "File Path : " << inputFilename.toStdString() << endl;
|
||||||
|
cout << "Number Of Meshes : " << fbx.meshCount << endl;
|
||||||
|
cout << "Processed Meshes : " << results.meshCount << endl;
|
||||||
|
cout << "Total vertices : " << totalVertices << endl;
|
||||||
|
cout << "Total Triangles : " << totalTriangles << endl;
|
||||||
|
cout << "Total Convex Hulls : " << totalHulls << endl;
|
||||||
|
cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl;
|
||||||
|
cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl;
|
||||||
|
cout << endl << "Summary per convex hull ........................" << endl <<endl;
|
||||||
|
for (int i = 0; i < results.meshCount; i++) {
|
||||||
|
cout << "Mesh : " << i + 1 << endl;
|
||||||
|
QVector<VHACD::IVHACD::ConvexHull> chList = results.convexHullList.at(i);
|
||||||
|
cout << "\t" << "Number Of Hulls : " << chList.count() << endl;
|
||||||
|
|
||||||
|
for (int j = 0; j < results.convexHullList.at(i).count(); j++){
|
||||||
|
cout << "\tHUll : " << j + 1 << endl;
|
||||||
|
cout << "\t\tNumber Of Points : " << chList.at(j).m_nPoints << endl;
|
||||||
|
cout << "\t\tNumber Of Triangles : " << chList.at(j).m_nTriangles << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeOBJ(outputFilename, results.convexHullList, outputOneMesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
VHACDUtilApp::~VHACDUtilApp() {
|
||||||
|
}
|
28
tools/vhacd/src/VHACDUtilApp.h
Normal file
28
tools/vhacd/src/VHACDUtilApp.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// VHACDUtil.h
|
||||||
|
// tools/vhacd/src
|
||||||
|
//
|
||||||
|
// Created by Seth Alves on 3/5/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef hifi_VHACDUtilApp_h
|
||||||
|
#define hifi_VHACDUtilApp_h
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
|
||||||
|
class VHACDUtilApp : public QCoreApplication {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
VHACDUtilApp(int argc, char* argv[]);
|
||||||
|
~VHACDUtilApp();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif //hifi_VHACDUtilApp_h
|
|
@ -8,104 +8,20 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
#include <stdio.h>
|
// #include <stdio.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <VHACD.h>
|
#include <VHACD.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "VHACDUtil.h"
|
|
||||||
|
#include "VHACDUtilApp.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace VHACD;
|
using namespace VHACD;
|
||||||
|
|
||||||
int main(int argc, char * argv[]){
|
|
||||||
vector<int> triangles; // array of indexes
|
|
||||||
vector<float> points; // array of coordinates
|
|
||||||
vhacd::VHACDUtil vUtil;
|
|
||||||
vhacd::LoadFBXResults fbx; //mesh data from loaded fbx file
|
|
||||||
vhacd::ComputeResults results; // results after computing vhacd
|
|
||||||
VHACD::IVHACD::Parameters params;
|
|
||||||
vhacd::ProgressCallback pCallBack;
|
|
||||||
if (argc < 2){
|
|
||||||
cout << "please provide a FBX file as argument\n ";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
string filename(argv[1]);
|
|
||||||
if (filename.empty()){
|
|
||||||
cout << "please provide a FBX file as argument\n ";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString fname = QString::fromStdString(filename);
|
int main(int argc, char * argv[]) {
|
||||||
|
VHACDUtilApp app(argc, argv);
|
||||||
//set parameters for V-HACD
|
|
||||||
params.m_callback = &pCallBack; //progress callback
|
|
||||||
params.m_resolution = 50000;
|
|
||||||
params.m_depth = 10;
|
|
||||||
params.m_concavity = 0.003;
|
|
||||||
params.m_alpha = 0.05; // controls the bias toward clipping along symmetry planes
|
|
||||||
params.m_pca = 1; // enable/disable normalizing the mesh before applying the convex decomposition
|
|
||||||
params.m_mode = 1; // 0: voxel - based approximate convex decomposition, 1 : tetrahedron - based approximate convex decomposition
|
|
||||||
params.m_maxNumVerticesPerCH = 128;
|
|
||||||
params.m_minVolumePerCH = 0.0001; // controls the adaptive sampling of the generated convex - hulls
|
|
||||||
|
|
||||||
// load the mesh
|
|
||||||
|
|
||||||
auto begin = std::chrono::high_resolution_clock::now();
|
|
||||||
if (!vUtil.loadFBX(fname, &fbx)){
|
|
||||||
cout << "Error in opening FBX file....";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
auto end = std::chrono::high_resolution_clock::now();
|
|
||||||
auto loadDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
|
|
||||||
|
|
||||||
//perform vhacd computation
|
|
||||||
begin = std::chrono::high_resolution_clock::now();
|
|
||||||
if (!vUtil.computeVHACD(&fbx, params, &results)){
|
|
||||||
cout << "Compute Failed...";
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
end = std::chrono::high_resolution_clock::now();
|
|
||||||
auto computeDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
|
|
||||||
|
|
||||||
int totalVertices = 0;
|
|
||||||
for (int i = 0; i < fbx.meshCount; i++){
|
|
||||||
totalVertices += fbx.perMeshVertices.at(i).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
int totalTriangles = 0;
|
|
||||||
for (int i = 0; i < fbx.meshCount; i++){
|
|
||||||
totalTriangles += fbx.perMeshTriangleIndices.at(i).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
int totalHulls = 0;
|
|
||||||
QVector<int> hullCounts = results.convexHullsCountList;
|
|
||||||
for (int i = 0; i < results.meshCount; i++){
|
|
||||||
totalHulls += hullCounts.at(i);
|
|
||||||
}
|
|
||||||
cout << endl << "Summary of V-HACD Computation..................." << endl;
|
|
||||||
cout << "File Path : " << fname.toStdString() << endl;
|
|
||||||
cout << "Number Of Meshes : " << fbx.meshCount << endl;
|
|
||||||
cout << "Processed Meshes : " << results.meshCount << endl;
|
|
||||||
cout << "Total vertices : " << totalVertices << endl;
|
|
||||||
cout << "Total Triangles : " << totalTriangles << endl;
|
|
||||||
cout << "Total Convex Hulls : " << totalHulls << endl;
|
|
||||||
cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl;
|
|
||||||
cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl;
|
|
||||||
cout << endl << "Summary per convex hull ........................" << endl <<endl;
|
|
||||||
for (int i = 0; i < results.meshCount; i++){
|
|
||||||
cout << "Mesh : " << i + 1 << endl;
|
|
||||||
QVector<VHACD::IVHACD::ConvexHull> chList = results.convexHullList.at(i);
|
|
||||||
cout << "\t" << "Number Of Hulls : " << chList.count() << endl;
|
|
||||||
|
|
||||||
for (int j = 0; j < results.convexHullList.at(i).count(); j++){
|
|
||||||
cout << "\tHUll : " << j + 1 << endl;
|
|
||||||
cout << "\t\tNumber Of Points : " << chList.at(j).m_nPoints << endl;
|
|
||||||
cout << "\t\tNumber Of Triangles : " << chList.at(j).m_nTriangles << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getchar();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue