mirror of
https://github.com/lubosz/overte.git
synced 2025-04-23 09:25:31 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into fix_quick_turn
This commit is contained in:
commit
910e13edeb
14 changed files with 311 additions and 100 deletions
|
@ -41,6 +41,10 @@ if (WIN32)
|
|||
message (WINDOW_SDK_PATH= ${WINDOW_SDK_PATH})
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${WINDOW_SDK_PATH})
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
# /LARGEADDRESSAWARE enables 32-bit apps to use more than 2GB of memory.
|
||||
# Caveats: http://stackoverflow.com/questions/2288728/drawbacks-of-using-largeaddressaware-for-32-bit-windows-executables
|
||||
# TODO: Remove when building 64-bit.
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE")
|
||||
elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic")
|
||||
#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unknown-pragmas")
|
||||
|
|
100
examples/entityScripts/alternativeLightController.js
Normal file
100
examples/entityScripts/alternativeLightController.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
(function() {
|
||||
this.preload = function(entityId) {
|
||||
var soundURLs = ["https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_1.wav",
|
||||
"https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_2.wav",
|
||||
"https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_3.wav"];
|
||||
this.entityId = entityId;
|
||||
this.properties = Entities.getEntityProperties(this.entityId);
|
||||
this.previousPosition = this.properties.position;
|
||||
this.previousRotation = this.properties.rotation;
|
||||
this.getUserData()
|
||||
if (!this.userData) {
|
||||
this.userData = {};
|
||||
this.userData.lightOn = false;
|
||||
this.userData.soundIndex = Math.floor(Math.random() * soundURLs.length);
|
||||
this.updateUserData();
|
||||
}
|
||||
this.sound = SoundCache.getSound(soundURLs[this.userData.soundIndex]);
|
||||
}
|
||||
|
||||
|
||||
this.getUserData = function() {
|
||||
if (this.properties.userData) {
|
||||
this.userData = JSON.parse(this.properties.userData);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
this.updateUserData = function() {
|
||||
Entities.editEntity(this.entityId, {
|
||||
userData: JSON.stringify(this.userData)
|
||||
});
|
||||
}
|
||||
|
||||
this.clickReleaseOnEntity = function(entityId, mouseEvent) {
|
||||
if (!mouseEvent.isLeftButton) {
|
||||
return;
|
||||
}
|
||||
//first find closest light
|
||||
this.entityId = entityId
|
||||
this.playSound();
|
||||
this.properties = Entities.getEntityProperties(this.entityId)
|
||||
this.light = this.findClosestLight();
|
||||
if (this.light) {
|
||||
this.lightProperties = Entities.getEntityProperties(this.light);
|
||||
this.getUserData();
|
||||
Entities.editEntity(this.light, {
|
||||
visible: !this.userData.lightOn
|
||||
});
|
||||
|
||||
this.userData.lightOn = !this.userData.lightOn;
|
||||
this.updateUserData();
|
||||
this.tryMoveLight();
|
||||
}
|
||||
}
|
||||
|
||||
this.playSound = function() {
|
||||
if (this.sound && this.sound.downloaded) {
|
||||
Audio.playSound(this.sound, {
|
||||
position: this.properties.position,
|
||||
volume: 0.3
|
||||
});
|
||||
} else {
|
||||
print("Warning: Couldn't play sound.");
|
||||
}
|
||||
}
|
||||
|
||||
this.tryMoveLight = function() {
|
||||
if (this.light) {
|
||||
//compute offset position
|
||||
var offsetPosition = Quat.multiply(Quat.inverse(this.previousRotation), Vec3.subtract(this.lightProperties.position, this.previousPosition));
|
||||
var newPosition = Vec3.sum(this.properties.position, Vec3.multiplyQbyV(this.properties.rotation, offsetPosition));
|
||||
if (!Vec3.equal(newPosition, this.lightProperties.position)) {
|
||||
Entities.editEntity(this.light, {position: newPosition});
|
||||
}
|
||||
this.previousPosition = this.properties.position;
|
||||
this.previousRotation = this.properties.rotation;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
this.findClosestLight = function() {
|
||||
var entities = Entities.findEntities(this.properties.position, 10);
|
||||
var lightEntities = [];
|
||||
var closestLight = null;
|
||||
var nearestDistance = 20
|
||||
|
||||
for (var i = 0; i < entities.length; i++) {
|
||||
var props = Entities.getEntityProperties(entities[i]);
|
||||
if (props.type === "Light") {
|
||||
var distance = Vec3.distance(props.position, this.properties.position)
|
||||
if (distance < nearestDistance) {
|
||||
closestLight = entities[i];
|
||||
nearestDistance = distance
|
||||
}
|
||||
}
|
||||
}
|
||||
return closestLight;
|
||||
}
|
||||
|
||||
});
|
|
@ -211,7 +211,14 @@
|
|||
disableChildren(document.getElementById("properties-list"), 'input');
|
||||
} else {
|
||||
var activeElement = document.activeElement;
|
||||
var selected = activeElement.selectionStart == 0 && activeElement.selectionEnd == activeElement.value.length;
|
||||
|
||||
try {
|
||||
var selected = (activeElement
|
||||
&& activeElement.selectionStart == 0
|
||||
&& activeElement.selectionEnd == activeElement.value.length);
|
||||
} catch (e) {
|
||||
var selected = false;
|
||||
}
|
||||
|
||||
var properties = data.selections[0].properties;
|
||||
|
||||
|
|
|
@ -201,11 +201,11 @@ var usersWindow = (function () {
|
|||
WINDOW_BASE_MARGIN = 6, // A little less is needed in order look correct
|
||||
WINDOW_FONT = { size: 12 },
|
||||
WINDOW_FOREGROUND_COLOR = { red: 240, green: 240, blue: 240 },
|
||||
WINDOW_FOREGROUND_ALPHA = 0.9,
|
||||
WINDOW_FOREGROUND_ALPHA = 0.95,
|
||||
WINDOW_HEADING_COLOR = { red: 180, green: 180, blue: 180 },
|
||||
WINDOW_HEADING_ALPHA = 0.9,
|
||||
WINDOW_HEADING_ALPHA = 0.95,
|
||||
WINDOW_BACKGROUND_COLOR = { red: 80, green: 80, blue: 80 },
|
||||
WINDOW_BACKGROUND_ALPHA = 0.7,
|
||||
WINDOW_BACKGROUND_ALPHA = 0.8,
|
||||
windowPane,
|
||||
windowHeading,
|
||||
MIN_MAX_BUTTON_SVG = HIFI_PUBLIC_BUCKET + "images/tools/min-max-toggle.svg",
|
||||
|
@ -223,7 +223,7 @@ var usersWindow = (function () {
|
|||
SCROLLBAR_BAR_MIN_HEIGHT = 5,
|
||||
SCROLLBAR_BAR_COLOR = { red: 170, green: 170, blue: 170 },
|
||||
SCROLLBAR_BAR_ALPHA = 0.8,
|
||||
SCROLLBAR_BAR_SELECTED_ALPHA = 0.9,
|
||||
SCROLLBAR_BAR_SELECTED_ALPHA = 0.95,
|
||||
scrollbarBar,
|
||||
scrollbarBackgroundHeight,
|
||||
scrollbarBarHeight,
|
||||
|
@ -233,12 +233,12 @@ var usersWindow = (function () {
|
|||
FRIENDS_BUTTON_SVG_HEIGHT = 27,
|
||||
FRIENDS_BUTTON_WIDTH = FRIENDS_BUTTON_SVG_WIDTH,
|
||||
FRIENDS_BUTTON_HEIGHT = FRIENDS_BUTTON_SVG_HEIGHT,
|
||||
FRIENDS_BUTTON_COLOR = { red: 255, green: 255, blue: 255 },
|
||||
FRIENDS_BUTTON_ALPHA = 0.9,
|
||||
FRIENDS_BUTTON_COLOR = { red: 225, green: 225, blue: 225 },
|
||||
FRIENDS_BUTTON_ALPHA = 0.95,
|
||||
friendsButton,
|
||||
|
||||
OPTION_BACKGROUND_COLOR = { red: 60, green: 60, blue: 60 },
|
||||
OPTION_BACKGROUND_ALPHA = 0.8,
|
||||
OPTION_BACKGROUND_ALPHA = 0.1,
|
||||
|
||||
DISPLAY_SPACER = 12, // Space before display control
|
||||
DISPLAY_PROMPT = "Show me:",
|
||||
|
@ -247,8 +247,8 @@ var usersWindow = (function () {
|
|||
DISPLAY_FRIENDS = "friends",
|
||||
DISPLAY_VALUES = [DISPLAY_EVERYONE, DISPLAY_FRIENDS],
|
||||
DISPLAY_DISPLAY_VALUES = DISPLAY_VALUES,
|
||||
DISPLAY_OPTIONS_BACKGROUND_COLOR = { red: 40, green: 40, blue: 40 },
|
||||
DISPLAY_OPTIONS_BACKGROUND_ALPHA = 0.95,
|
||||
DISPLAY_OPTIONS_BACKGROUND_COLOR = { red: 120, green: 120, blue: 120 },
|
||||
DISPLAY_OPTIONS_BACKGROUND_ALPHA = 0.9,
|
||||
displayControl,
|
||||
|
||||
VISIBILITY_SPACER = 6, // Space before visibility control
|
||||
|
|
|
@ -212,6 +212,7 @@ void Renderer::glUpload(GLsizei numStars) {
|
|||
void Renderer::glBatch(GLfloat const* matrix, GLsizei n_ranges, float alpha) {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
// setup modelview matrix
|
||||
glPushMatrix();
|
||||
|
|
|
@ -201,7 +201,7 @@
|
|||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(P, S)\
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
QString newValue = P.toVariant().toString();\
|
||||
QString newValue = P.toVariant().toString().trimmed();\
|
||||
if (_defaultSettings || newValue != _##P) { \
|
||||
S(newValue); \
|
||||
} \
|
||||
|
|
|
@ -116,6 +116,24 @@ bool OBJTokenizer::isNextTokenFloat() {
|
|||
return ok;
|
||||
}
|
||||
|
||||
void setMeshPartDefaults(FBXMeshPart &meshPart, QString materialID) {
|
||||
meshPart.diffuseColor = glm::vec3(1, 1, 1);
|
||||
meshPart.specularColor = glm::vec3(1, 1, 1);
|
||||
meshPart.emissiveColor = glm::vec3(0, 0, 0);
|
||||
meshPart.emissiveParams = glm::vec2(0, 1);
|
||||
meshPart.shininess = 40;
|
||||
meshPart.opacity = 1;
|
||||
|
||||
meshPart.materialID = materialID;
|
||||
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));
|
||||
}
|
||||
|
||||
bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
|
||||
FBXGeometry &geometry, QVector<glm::vec3>& faceNormals, QVector<int>& faceNormalIndexes,
|
||||
float& scaleGuess) {
|
||||
|
@ -125,21 +143,7 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping,
|
|||
bool sawG = false;
|
||||
bool result = true;
|
||||
|
||||
meshPart.diffuseColor = glm::vec3(1, 1, 1);
|
||||
meshPart.specularColor = glm::vec3(1, 1, 1);
|
||||
meshPart.emissiveColor = glm::vec3(0, 0, 0);
|
||||
meshPart.emissiveParams = glm::vec2(0, 1);
|
||||
meshPart.shininess = 40;
|
||||
meshPart.opacity = 1;
|
||||
|
||||
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));
|
||||
setMeshPartDefaults(meshPart, QString("dontknow") + QString::number(mesh.parts.count()));
|
||||
|
||||
while (true) {
|
||||
int tokenType = tokenizer.nextToken();
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
FBXGeometry readOBJ(const QByteArray& model, const QVariantHash& mapping);
|
||||
FBXGeometry readOBJ(QIODevice* device, const QVariantHash& mapping);
|
||||
void fbxDebugDump(const FBXGeometry& fbxgeo);
|
||||
void setMeshPartDefaults(FBXMeshPart &meshPart, QString materialID);
|
||||
|
|
|
@ -27,7 +27,7 @@ Resource::Size Resource::Sysmem::allocateMemory(Byte** dataAllocated, Size size)
|
|||
if (size > 0) {
|
||||
// Try allocating as much as the required size + one block of memory
|
||||
newSize = size;
|
||||
(*dataAllocated) = new Byte[newSize];
|
||||
(*dataAllocated) = new (std::nothrow) Byte[newSize];
|
||||
// Failed?
|
||||
if (!(*dataAllocated)) {
|
||||
qWarning() << "Buffer::Sysmem::allocate() : Can't allocate a system memory buffer of " << newSize << "bytes. Fails to create the buffer Sysmem.";
|
||||
|
|
|
@ -1024,7 +1024,7 @@ int Octree::encodeTreeBitstream(OctreeElement* element,
|
|||
roomForOctalCode = packetData->startSubTree(newCode);
|
||||
|
||||
if (newCode) {
|
||||
delete newCode;
|
||||
delete[] newCode;
|
||||
codeLength = numberOfThreeBitSectionsInCode(newCode);
|
||||
} else {
|
||||
codeLength = 1;
|
||||
|
@ -2064,7 +2064,7 @@ bool Octree::readJSONFromStream(unsigned long streamLength, QDataStream& inputSt
|
|||
QVariant asVariant = asDocument.toVariant();
|
||||
QVariantMap asMap = asVariant.toMap();
|
||||
readFromMap(asMap);
|
||||
delete rawData;
|
||||
delete[] rawData;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) {
|
|||
float diagonal = 4.0f * glm::length2(info.getHalfExtents());
|
||||
const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube
|
||||
const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e6f; // 1000 m cube
|
||||
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) {
|
||||
if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED /* || diagonal > MAX_SHAPE_DIAGONAL_SQUARED*/ ) {
|
||||
// qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -50,42 +50,92 @@ bool vhacd::VHACDUtil::loadFBX(const QString filename, FBXGeometry& result) {
|
|||
}
|
||||
|
||||
|
||||
unsigned int getTrianglesInMeshPart(const FBXMeshPart &meshPart, std::vector<int>& triangles) {
|
||||
// append all the triangles (and converted quads) from this mesh-part to triangles
|
||||
std::vector<int> meshPartTriangles = meshPart.triangleIndices.toStdVector();
|
||||
triangles.insert(triangles.end(), meshPartTriangles.begin(), meshPartTriangles.end());
|
||||
|
||||
// void vhacd::VHACDUtil::fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const {
|
||||
// convert quads to triangles
|
||||
unsigned int triangleCount = meshPart.triangleIndices.size() / 3;
|
||||
unsigned int quadCount = meshPart.quadIndices.size() / 4;
|
||||
for (unsigned int i = 0; i < quadCount; i++) {
|
||||
unsigned int p0Index = meshPart.quadIndices[i * 4];
|
||||
unsigned int p1Index = meshPart.quadIndices[i * 4 + 1];
|
||||
unsigned int p2Index = meshPart.quadIndices[i * 4 + 2];
|
||||
unsigned int p3Index = meshPart.quadIndices[i * 4 + 3];
|
||||
// split each quad into two triangles
|
||||
triangles.push_back(p0Index);
|
||||
triangles.push_back(p1Index);
|
||||
triangles.push_back(p2Index);
|
||||
triangles.push_back(p0Index);
|
||||
triangles.push_back(p2Index);
|
||||
triangles.push_back(p3Index);
|
||||
triangleCount += 2;
|
||||
}
|
||||
|
||||
// for (int i = 0; i < meshes->meshCount; i++) {
|
||||
// QVector<glm::vec3> vertices = meshes->perMeshVertices.at(i);
|
||||
// QVector<int> triangles = meshes->perMeshTriangleIndices.at(i);
|
||||
// const float largestDimension = meshes->perMeshLargestDimension.at(i);
|
||||
return triangleCount;
|
||||
}
|
||||
|
||||
// results->perMeshVertices.append(vertices);
|
||||
// results->perMeshTriangleIndices.append(triangles);
|
||||
// results->perMeshLargestDimension.append(largestDimension);
|
||||
|
||||
// for (int j = 0; j < triangles.size(); j += 3) {
|
||||
// auto p0 = vertices[triangles[j]];
|
||||
// auto p1 = vertices[triangles[j+1]];
|
||||
// auto p2 = vertices[triangles[j+2]];
|
||||
void vhacd::VHACDUtil::fattenMeshes(const FBXMesh& mesh, FBXMesh& result,
|
||||
unsigned int& meshPartCount,
|
||||
unsigned int startMeshIndex, unsigned int endMeshIndex) const {
|
||||
// this is used to make meshes generated from a highfield collidable. each triangle
|
||||
// is converted into a tetrahedron and made into its own mesh-part.
|
||||
|
||||
// auto d0 = p1 - p0;
|
||||
// auto d1 = p2 - p0;
|
||||
std::vector<int> triangles;
|
||||
foreach (const FBXMeshPart &meshPart, mesh.parts) {
|
||||
if (meshPartCount < startMeshIndex || meshPartCount >= endMeshIndex) {
|
||||
meshPartCount++;
|
||||
continue;
|
||||
}
|
||||
getTrianglesInMeshPart(meshPart, triangles);
|
||||
}
|
||||
|
||||
// auto cp = glm::cross(d0, d1);
|
||||
// cp = -2.0f * glm::normalize(cp);
|
||||
unsigned int triangleCount = triangles.size() / 3;
|
||||
if (triangleCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// auto p3 = p0 + cp;
|
||||
|
||||
// auto n = results->perMeshVertices.size();
|
||||
// results->perMeshVertices[i] << p3;
|
||||
int indexStartOffset = result.vertices.size();
|
||||
|
||||
// results->perMeshTriangleIndices[i] << triangles[j] << n << triangles[j + 1];
|
||||
// results->perMeshTriangleIndices[i] << triangles[j + 1] << n << triangles[j + 2];
|
||||
// results->perMeshTriangleIndices[i] << triangles[j + 2] << n << triangles[j];
|
||||
// }
|
||||
// new mesh gets the transformed points from the original
|
||||
for (int i = 0; i < mesh.vertices.size(); i++) {
|
||||
// apply the source mesh's transform to the points
|
||||
glm::vec4 v = mesh.modelTransform * glm::vec4(mesh.vertices[i], 1.0f);
|
||||
result.vertices += glm::vec3(v);
|
||||
}
|
||||
|
||||
// results->meshCount++;
|
||||
// }
|
||||
// }
|
||||
// turn each triangle into a tetrahedron
|
||||
|
||||
for (unsigned int i = 0; i < triangleCount; i++) {
|
||||
int index0 = triangles[i * 3] + indexStartOffset;
|
||||
int index1 = triangles[i * 3 + 1] + indexStartOffset;
|
||||
int index2 = triangles[i * 3 + 2] + indexStartOffset;
|
||||
|
||||
glm::vec3 p0 = result.vertices[index0];
|
||||
glm::vec3 p1 = result.vertices[index1];
|
||||
glm::vec3 p2 = result.vertices[index2];
|
||||
glm::vec3 av = (p0 + p1 + p2) / 3.0f; // center of the triangular face
|
||||
|
||||
float dropAmount = 0;
|
||||
dropAmount = glm::max(glm::length(p1 - p0), dropAmount);
|
||||
dropAmount = glm::max(glm::length(p2 - p1), dropAmount);
|
||||
dropAmount = glm::max(glm::length(p0 - p2), dropAmount);
|
||||
|
||||
glm::vec3 p3 = av - glm::vec3(0, dropAmount, 0); // a point 1 meter below the average of this triangle's points
|
||||
int index3 = result.vertices.size();
|
||||
result.vertices << p3; // add the new point to the result mesh
|
||||
|
||||
FBXMeshPart newMeshPart;
|
||||
setMeshPartDefaults(newMeshPart, "unknown");
|
||||
newMeshPart.triangleIndices << index0 << index1 << index2;
|
||||
newMeshPart.triangleIndices << index0 << index3 << index1;
|
||||
newMeshPart.triangleIndices << index1 << index3 << index2;
|
||||
newMeshPart.triangleIndices << index2 << index3 << index0;
|
||||
result.parts.append(newMeshPart);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -127,8 +177,7 @@ bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
|
|||
FBXGeometry& result,
|
||||
int startMeshIndex,
|
||||
int endMeshIndex,
|
||||
float minimumMeshSize, float maximumMeshSize,
|
||||
bool fattenFaces) {
|
||||
float minimumMeshSize, float maximumMeshSize) {
|
||||
// count the mesh-parts
|
||||
int meshCount = 0;
|
||||
foreach (const FBXMesh& mesh, geometry.meshes) {
|
||||
|
@ -168,27 +217,8 @@ bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
|
|||
|
||||
qDebug() << "--------------------";
|
||||
|
||||
std::vector<int> triangles = meshPart.triangleIndices.toStdVector();
|
||||
|
||||
AABox aaBox = getAABoxForMeshPart(mesh, meshPart);
|
||||
|
||||
// convert quads to triangles
|
||||
unsigned int triangleCount = meshPart.triangleIndices.size() / 3;
|
||||
unsigned int quadCount = meshPart.quadIndices.size() / 4;
|
||||
for (unsigned int i = 0; i < quadCount; i++) {
|
||||
unsigned int p0Index = meshPart.quadIndices[i * 4];
|
||||
unsigned int p1Index = meshPart.quadIndices[i * 4 + 1];
|
||||
unsigned int p2Index = meshPart.quadIndices[i * 4 + 2];
|
||||
unsigned int p3Index = meshPart.quadIndices[i * 4 + 3];
|
||||
// split each quad into two triangles
|
||||
triangles.push_back(p0Index);
|
||||
triangles.push_back(p1Index);
|
||||
triangles.push_back(p2Index);
|
||||
triangles.push_back(p0Index);
|
||||
triangles.push_back(p2Index);
|
||||
triangles.push_back(p3Index);
|
||||
triangleCount += 2;
|
||||
}
|
||||
std::vector<int> triangles;
|
||||
unsigned int triangleCount = getTrianglesInMeshPart(meshPart, triangles);
|
||||
|
||||
// only process meshes with triangles
|
||||
if (triangles.size() <= 0) {
|
||||
|
@ -198,6 +228,7 @@ bool vhacd::VHACDUtil::computeVHACD(FBXGeometry& geometry,
|
|||
}
|
||||
|
||||
int nPoints = vertices.size();
|
||||
AABox aaBox = getAABoxForMeshPart(mesh, meshPart);
|
||||
const float largestDimension = aaBox.getLargestDimension();
|
||||
|
||||
qDebug() << "Mesh " << count << " -- " << nPoints << " points, " << triangleCount << " triangles, "
|
||||
|
|
|
@ -26,14 +26,16 @@ namespace vhacd {
|
|||
class VHACDUtil {
|
||||
public:
|
||||
bool loadFBX(const QString filename, FBXGeometry& result);
|
||||
// void combineMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const;
|
||||
// void fattenMeshes(vhacd::LoadFBXResults *meshes, vhacd::LoadFBXResults *results) const;
|
||||
|
||||
void fattenMeshes(const FBXMesh& mesh, FBXMesh& result,
|
||||
unsigned int& meshPartCount,
|
||||
unsigned int startMeshIndex, unsigned int endMeshIndex) const;
|
||||
|
||||
bool computeVHACD(FBXGeometry& geometry,
|
||||
VHACD::IVHACD::Parameters params,
|
||||
FBXGeometry& result,
|
||||
int startMeshIndex, int endMeshIndex,
|
||||
float minimumMeshSize, float maximumMeshSize,
|
||||
bool fattenFaces);
|
||||
float minimumMeshSize, float maximumMeshSize);
|
||||
~VHACDUtil();
|
||||
};
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ QString formatFloat(double n) {
|
|||
}
|
||||
|
||||
|
||||
bool writeOBJ(QString outFileName, FBXGeometry& geometry, int whichMeshPart = -1) {
|
||||
bool writeOBJ(QString outFileName, FBXGeometry& geometry, bool outputCentimeters, int whichMeshPart = -1) {
|
||||
QFile file(outFileName);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
qDebug() << "Unable to write to " << outFileName;
|
||||
|
@ -41,6 +41,10 @@ bool writeOBJ(QString outFileName, FBXGeometry& geometry, int whichMeshPart = -1
|
|||
}
|
||||
QTextStream out(&file);
|
||||
|
||||
if (outputCentimeters) {
|
||||
out << "# This file uses centimeters as units\n\n";
|
||||
}
|
||||
|
||||
unsigned int nth = 0;
|
||||
|
||||
// vertex indexes in obj files span the entire file
|
||||
|
@ -116,6 +120,9 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
const QCommandLineOption outputFilenameOption("o", "output file", "filename.obj");
|
||||
parser.addOption(outputFilenameOption);
|
||||
|
||||
const QCommandLineOption outputCentimetersOption("c", "output units are centimeters");
|
||||
parser.addOption(outputCentimetersOption);
|
||||
|
||||
const QCommandLineOption startMeshIndexOption("s", "start-mesh index", "0");
|
||||
parser.addOption(startMeshIndexOption);
|
||||
|
||||
|
@ -137,7 +144,21 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
"according the \"best\" clipping plane (range=1-32)", "20");
|
||||
parser.addOption(vHacdDepthOption);
|
||||
|
||||
const QCommandLineOption vHacdDeltaOption("delta", "Controls the bias toward maximaxing local concavity (range=0.0-1.0)", "0.05");
|
||||
|
||||
const QCommandLineOption vHacdAlphaOption("alpha", "Controls the bias toward clipping along symmetry "
|
||||
"planes (range=0.0-1.0)", "0.05");
|
||||
parser.addOption(vHacdAlphaOption);
|
||||
|
||||
const QCommandLineOption vHacdBetaOption("beta", "Controls the bias toward clipping along revolution "
|
||||
"axes (range=0.0-1.0)", "0.05");
|
||||
parser.addOption(vHacdBetaOption);
|
||||
|
||||
const QCommandLineOption vHacdGammaOption("gamma", "Controls the maximum allowed concavity during the "
|
||||
"merge stage (range=0.0-1.0)", "0.00125");
|
||||
parser.addOption(vHacdGammaOption);
|
||||
|
||||
const QCommandLineOption vHacdDeltaOption("delta", "Controls the bias toward maximaxing local "
|
||||
"concavity (range=0.0-1.0)", "0.05");
|
||||
parser.addOption(vHacdDeltaOption);
|
||||
|
||||
const QCommandLineOption vHacdConcavityOption("concavity", "Maximum allowed concavity (range=0.0-1.0)", "0.0025");
|
||||
|
@ -152,10 +173,6 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
"plane selection stage (range=1-16)", "4");
|
||||
parser.addOption(vHacdConvexhulldownsamplingOption);
|
||||
|
||||
// alpha
|
||||
// beta
|
||||
// gamma
|
||||
// delta
|
||||
// pca
|
||||
// mode
|
||||
|
||||
|
@ -178,9 +195,11 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
bool fattenFaces = parser.isSet(fattenFacesOption);
|
||||
bool outputCentimeters = parser.isSet(outputCentimetersOption);
|
||||
|
||||
bool fattenFaces = parser.isSet(fattenFacesOption);
|
||||
bool generateHulls = parser.isSet(generateHullsOption);
|
||||
bool splitModel = parser.isSet(splitOption);
|
||||
|
||||
|
||||
QString inputFilename;
|
||||
|
@ -236,6 +255,21 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
vHacdDepth = parser.value(vHacdDepthOption).toInt();
|
||||
}
|
||||
|
||||
float vHacdAlpha = 0.05;
|
||||
if (parser.isSet(vHacdAlphaOption)) {
|
||||
vHacdAlpha = parser.value(vHacdAlphaOption).toFloat();
|
||||
}
|
||||
|
||||
float vHacdBeta = 0.05;
|
||||
if (parser.isSet(vHacdBetaOption)) {
|
||||
vHacdBeta = parser.value(vHacdBetaOption).toFloat();
|
||||
}
|
||||
|
||||
float vHacdGamma = 0.00125;
|
||||
if (parser.isSet(vHacdGammaOption)) {
|
||||
vHacdGamma = parser.value(vHacdGammaOption).toFloat();
|
||||
}
|
||||
|
||||
float vHacdDelta = 0.05;
|
||||
if (parser.isSet(vHacdDeltaOption)) {
|
||||
vHacdDelta = parser.value(vHacdDeltaOption).toFloat();
|
||||
|
@ -261,8 +295,8 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
vHacdMaxVerticesPerCH = parser.value(vHacdMaxVerticesPerCHOption).toInt();
|
||||
}
|
||||
|
||||
if (!parser.isSet(splitOption) && !generateHulls) {
|
||||
cerr << "\nNothing to do! Use -g or --split\n\n";
|
||||
if (!splitModel && !generateHulls && !fattenFaces) {
|
||||
cerr << "\nNothing to do! Use -g or -f or --split\n\n";
|
||||
parser.showHelp();
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
@ -279,14 +313,14 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
auto loadDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count();
|
||||
|
||||
|
||||
if (parser.isSet(splitOption)) {
|
||||
if (splitModel) {
|
||||
QVector<QString> infileExtensions = {"fbx", "obj"};
|
||||
QString baseFileName = fileNameWithoutExtension(inputFilename, infileExtensions);
|
||||
int count = 0;
|
||||
foreach (const FBXMesh& mesh, fbx.meshes) {
|
||||
foreach (const FBXMeshPart &meshPart, mesh.parts) {
|
||||
QString outputFileName = baseFileName + "-" + QString::number(count) + ".obj";
|
||||
writeOBJ(outputFileName, fbx, count);
|
||||
writeOBJ(outputFileName, fbx, outputCentimeters, count);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -304,9 +338,9 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
params.m_delta = vHacdDelta;
|
||||
params.m_planeDownsampling = vHacdPlanedownsampling;
|
||||
params.m_convexhullDownsampling = vHacdConvexhulldownsampling;
|
||||
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_alpha = vHacdAlpha;
|
||||
params.m_beta = vHacdBeta;
|
||||
params.m_gamma = vHacdGamma;
|
||||
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 = vHacdMaxVerticesPerCH;
|
||||
|
@ -321,7 +355,7 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
|
||||
FBXGeometry result;
|
||||
if (!vUtil.computeVHACD(fbx, params, result, startMeshIndex, endMeshIndex,
|
||||
minimumMeshSize, maximumMeshSize, fattenFaces)) {
|
||||
minimumMeshSize, maximumMeshSize)) {
|
||||
cout << "Compute Failed...";
|
||||
}
|
||||
end = std::chrono::high_resolution_clock::now();
|
||||
|
@ -350,7 +384,34 @@ VHACDUtilApp::VHACDUtilApp(int argc, char* argv[]) :
|
|||
cout << "Total FBX load time: " << (double)loadDuration / 1000000000.00 << " seconds" << endl;
|
||||
cout << "V-HACD Compute time: " << (double)computeDuration / 1000000000.00 << " seconds" << endl;
|
||||
|
||||
writeOBJ(outputFilename, result);
|
||||
writeOBJ(outputFilename, result, outputCentimeters);
|
||||
}
|
||||
|
||||
if (fattenFaces) {
|
||||
FBXGeometry newFbx;
|
||||
FBXMesh result;
|
||||
|
||||
// count the mesh-parts
|
||||
unsigned int meshCount = 0;
|
||||
foreach (const FBXMesh& mesh, fbx.meshes) {
|
||||
meshCount += mesh.parts.size();
|
||||
}
|
||||
|
||||
if (startMeshIndex < 0) {
|
||||
startMeshIndex = 0;
|
||||
}
|
||||
if (endMeshIndex < 0) {
|
||||
endMeshIndex = meshCount;
|
||||
}
|
||||
|
||||
unsigned int meshPartCount = 0;
|
||||
result.modelTransform = glm::mat4(); // Identity matrix
|
||||
foreach (const FBXMesh& mesh, fbx.meshes) {
|
||||
vUtil.fattenMeshes(mesh, result, meshPartCount, startMeshIndex, endMeshIndex);
|
||||
}
|
||||
|
||||
newFbx.meshes.append(result);
|
||||
writeOBJ(outputFilename, newFbx, outputCentimeters);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue