mirror of
https://github.com/overte-org/overte.git
synced 2025-08-05 04:41:15 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
f5743aa770
76 changed files with 1240 additions and 4415 deletions
|
@ -186,7 +186,6 @@ setup_externals_binary_dir()
|
|||
option(GET_BULLET "Get Bullet library automatically as external project" 1)
|
||||
option(GET_GLM "Get GLM library automatically as external project" 1)
|
||||
option(GET_GVERB "Get Gverb library automatically as external project" 1)
|
||||
option(GET_SOXR "Get Soxr library automatically as external project" 1)
|
||||
option(GET_TBB "Get Threading Building Blocks library automatically as external project" 1)
|
||||
option(GET_LIBOVR "Get LibOVR library automatically as external project" 1)
|
||||
option(GET_VHACD "Get V-HACD library automatically as external project" 1)
|
||||
|
|
84
examples/acScripts/flickeringLight.js
Normal file
84
examples/acScripts/flickeringLight.js
Normal file
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// flickeringLight.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2015/09/29.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Creates an ephemeral flickering light that will randomly flicker as long as the script is running.
|
||||
// After the script stops running, the light will eventually disappear (~10 seconds later). This script
|
||||
// can run in the interface or in an assignment client and it will work equally well.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
function randFloat(low, high) {
|
||||
return low + Math.random() * (high - low);
|
||||
}
|
||||
|
||||
var LIGHT_NAME = "flickering fire";
|
||||
|
||||
var LIGHT_POSITION = {
|
||||
x: 551.13,
|
||||
y: 494.77,
|
||||
z: 502.26
|
||||
};
|
||||
|
||||
var LIGHT_COLOR = {
|
||||
red: 255,
|
||||
green: 100,
|
||||
blue: 28
|
||||
};
|
||||
|
||||
var ZERO_VEC = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
|
||||
var totalTime = 0;
|
||||
|
||||
var MINIMUM_LIGHT_INTENSITY = 0.75;
|
||||
var MAXIMUM_LIGHT_INTENSITY = 2.75;
|
||||
var LIGHT_INTENSITY_RANDOMNESS = 0.3;
|
||||
var EPHEMERAL_LIFETIME = 10; // ephemeral entities will live for 10 seconds after script stops running
|
||||
|
||||
var LightMaker = {
|
||||
light: null,
|
||||
spawnLight: function() {
|
||||
print('CREATING LIGHT')
|
||||
var _this = this;
|
||||
_this.light = Entities.addEntity({
|
||||
type: "Light",
|
||||
name: LIGHT_NAME,
|
||||
position: LIGHT_POSITION,
|
||||
lifetime: EPHEMERAL_LIFETIME,
|
||||
color: LIGHT_COLOR,
|
||||
dimensions: { x: 10, y: 10, z: 10 }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var hasSpawned = false;
|
||||
|
||||
function update(deltaTime) {
|
||||
|
||||
if (!Entities.serversExist() || !Entities.canRez()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasSpawned === false) {
|
||||
hasSpawned = true;
|
||||
LightMaker.spawnLight();
|
||||
} else {
|
||||
totalTime += deltaTime;
|
||||
var intensity = (MINIMUM_LIGHT_INTENSITY + (MAXIMUM_LIGHT_INTENSITY + (Math.sin(totalTime) * MAXIMUM_LIGHT_INTENSITY)));
|
||||
intensity += randFloat(-LIGHT_INTENSITY_RANDOMNESS, LIGHT_INTENSITY_RANDOMNESS);
|
||||
var properties = Entities.getEntityProperties(LightMaker.light, "age");
|
||||
Entities.editEntity(LightMaker.light, { intensity: intensity, lifetime: properties.age + EPHEMERAL_LIFETIME });
|
||||
}
|
||||
}
|
||||
|
||||
Script.update.connect(update);
|
|
@ -1035,7 +1035,7 @@ function handeMenuEvent(menuItem) {
|
|||
|
||||
var importURL;
|
||||
if (menuItem == "Import Entities") {
|
||||
importURL = Window.browse("Select models to import", "", "*.json");
|
||||
importURL = "file:///" + Window.browse("Select models to import", "", "*.json");
|
||||
} else {
|
||||
importURL = Window.prompt("URL of SVO to import", "");
|
||||
}
|
||||
|
|
|
@ -11,6 +11,17 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
var normalDisplay = Entities.addEntity({
|
||||
type: "Line",
|
||||
name: "normalDisplay",
|
||||
visible: false,
|
||||
color: { red: 255, green: 0, blue: 0 },
|
||||
dimensions: { x: 100, y: 100, z: 100 }
|
||||
});
|
||||
|
||||
var wasVisible = false;
|
||||
|
||||
function mouseMoveEvent(event) {
|
||||
print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y);
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
|
@ -18,26 +29,45 @@ function mouseMoveEvent(event) {
|
|||
print("computePickRay origin=" + pickRay.origin.x + ", " + pickRay.origin.y + ", " + pickRay.origin.z);
|
||||
print("computePickRay direction=" + pickRay.direction.x + ", " + pickRay.direction.y + ", " + pickRay.direction.z);
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
intersection = Entities.findRayIntersection(pickRay);
|
||||
intersection = Entities.findRayIntersection(pickRay, true); // to get precise picking
|
||||
if (!intersection.accurate) {
|
||||
print(">>> NOTE: intersection not accurate. will try calling Entities.findRayIntersectionBlocking()");
|
||||
intersection = Entities.findRayIntersectionBlocking(pickRay);
|
||||
intersection = Entities.findRayIntersectionBlocking(pickRay, true); // to get precise picking
|
||||
print(">>> AFTER BLOCKING CALL intersection.accurate=" + intersection.accurate);
|
||||
}
|
||||
|
||||
if (intersection.intersects) {
|
||||
print("intersection entityID.id=" + intersection.entityID.id);
|
||||
print("intersection entityID=" + intersection.entityID);
|
||||
print("intersection properties.modelURL=" + intersection.properties.modelURL);
|
||||
print("intersection face=" + intersection.face);
|
||||
print("intersection distance=" + intersection.distance);
|
||||
print("intersection intersection.x/y/z=" + intersection.intersection.x + ", "
|
||||
print("intersection intersection.x/y/z=" + intersection.intersection.x + ", "
|
||||
+ intersection.intersection.y + ", " + intersection.intersection.z);
|
||||
print("intersection surfaceNormal.x/y/z=" + intersection.surfaceNormal.x + ", "
|
||||
+ intersection.surfaceNormal.y + ", " + intersection.surfaceNormal.z);
|
||||
|
||||
|
||||
// Note: line entity takes points in "entity relative frame"
|
||||
var lineStart = { x: 0, y: 0, z: 0 };
|
||||
var lineEnd = intersection.surfaceNormal;
|
||||
|
||||
Entities.editEntity(normalDisplay, {
|
||||
visible: true,
|
||||
position: intersection.intersection,
|
||||
linePoints: [lineStart, lineEnd],
|
||||
});
|
||||
wasVisible = true;
|
||||
} else {
|
||||
if (wasVisible) {
|
||||
Entities.editEntity(normalDisplay, { visible: false });
|
||||
wasVisible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
Script.scriptEnding.connect(function() {
|
||||
Entities.deleteEntity(normalDisplay);
|
||||
});
|
||||
|
||||
|
|
|
@ -1055,6 +1055,9 @@ void Application::paintGL() {
|
|||
displayPlugin->preRender();
|
||||
_offscreenContext->makeCurrent();
|
||||
|
||||
// update the avatar with a fresh HMD pose
|
||||
_myAvatar->updateFromHMDSensorMatrix(getHMDSensorPose());
|
||||
|
||||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
|
||||
|
||||
|
@ -2337,7 +2340,8 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
|
|||
QVector<EntityItemPointer> entities;
|
||||
|
||||
auto entityTree = _entities.getTree();
|
||||
EntityTree exportTree;
|
||||
auto exportTree = std::make_shared<EntityTree>();
|
||||
exportTree->createRootElement();
|
||||
|
||||
glm::vec3 root(TREE_SCALE, TREE_SCALE, TREE_SCALE);
|
||||
for (auto entityID : entityIDs) {
|
||||
|
@ -2364,10 +2368,10 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt
|
|||
auto properties = entityItem->getProperties();
|
||||
|
||||
properties.setPosition(properties.getPosition() - root);
|
||||
exportTree.addEntity(entityItem->getEntityItemID(), properties);
|
||||
exportTree->addEntity(entityItem->getEntityItemID(), properties);
|
||||
}
|
||||
|
||||
exportTree.writeToJSONFile(filename.toLocal8Bit().constData());
|
||||
exportTree->writeToJSONFile(filename.toLocal8Bit().constData());
|
||||
|
||||
// restore the main window's active state
|
||||
_window->activateWindow();
|
||||
|
@ -2380,15 +2384,16 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa
|
|||
|
||||
if (entities.size() > 0) {
|
||||
glm::vec3 root(x, y, z);
|
||||
EntityTree exportTree;
|
||||
auto exportTree = std::make_shared<EntityTree>();
|
||||
exportTree->createRootElement();
|
||||
|
||||
for (int i = 0; i < entities.size(); i++) {
|
||||
EntityItemProperties properties = entities.at(i)->getProperties();
|
||||
EntityItemID id = entities.at(i)->getEntityItemID();
|
||||
properties.setPosition(properties.getPosition() - root);
|
||||
exportTree.addEntity(id, properties);
|
||||
exportTree->addEntity(id, properties);
|
||||
}
|
||||
exportTree.writeToSVOFile(filename.toLocal8Bit().constData());
|
||||
exportTree->writeToSVOFile(filename.toLocal8Bit().constData());
|
||||
} else {
|
||||
qCDebug(interfaceapp) << "No models were selected";
|
||||
return false;
|
||||
|
@ -2895,9 +2900,6 @@ void Application::update(float deltaTime) {
|
|||
userInputMapper->getActionState(UserInputMapper::SHIFT), RIGHT_HAND_INDEX);
|
||||
}
|
||||
|
||||
// update the avatar with a fresh HMD pose
|
||||
_myAvatar->updateFromHMDSensorMatrix(getHMDSensorPose(), deltaTime);
|
||||
|
||||
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
|
||||
|
||||
updateCamera(deltaTime); // handle various camera tweaks like off axis projection
|
||||
|
|
|
@ -270,9 +270,18 @@ glm::mat4 MyAvatar::getSensorToWorldMatrix() const {
|
|||
return _sensorToWorldMatrix;
|
||||
}
|
||||
|
||||
// best called at start of main loop just after we have a fresh hmd pose.
|
||||
// update internal body position from new hmd pose.
|
||||
void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix, float deltaTime) {
|
||||
// Pass a recent sample of the HMD to the avatar.
|
||||
// This can also update the avatar's position to follow the HMD
|
||||
// as it moves through the world.
|
||||
void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
||||
|
||||
auto now = usecTimestampNow();
|
||||
auto deltaUsecs = now - _lastUpdateFromHMDTime;
|
||||
_lastUpdateFromHMDTime = now;
|
||||
double actualDeltaTime = (double)deltaUsecs / (double)USECS_PER_SECOND;
|
||||
const float BIGGEST_DELTA_TIME_SECS = 0.25f;
|
||||
float deltaTime = glm::clamp((float)actualDeltaTime, 0.0f, BIGGEST_DELTA_TIME_SECS);
|
||||
|
||||
// update the sensorMatrices based on the new hmd pose
|
||||
_hmdSensorMatrix = hmdSensorMatrix;
|
||||
_hmdSensorPosition = extractTranslation(hmdSensorMatrix);
|
||||
|
|
|
@ -66,9 +66,10 @@ public:
|
|||
const glm::quat& getHMDSensorOrientation() const { return _hmdSensorOrientation; }
|
||||
glm::mat4 getSensorToWorldMatrix() const;
|
||||
|
||||
// best called at start of main loop just after we have a fresh hmd pose.
|
||||
// update internal body position from new hmd pose.
|
||||
void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix, float deltaTime);
|
||||
// Pass a recent sample of the HMD to the avatar.
|
||||
// This can also update the avatar's position to follow the HMD
|
||||
// as it moves through the world.
|
||||
void updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix);
|
||||
|
||||
// best called at end of main loop, just before rendering.
|
||||
// update sensor to world matrix from current body position and hmd sensor.
|
||||
|
@ -361,6 +362,8 @@ private:
|
|||
|
||||
bool _straightingLean = false;
|
||||
float _straightingLeanAlpha = 0.0f;
|
||||
|
||||
quint64 _lastUpdateFromHMDTime = usecTimestampNow();
|
||||
};
|
||||
|
||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||
|
|
|
@ -19,17 +19,40 @@ float ClipboardScriptingInterface::getClipboardContentsLargestDimension() {
|
|||
}
|
||||
|
||||
bool ClipboardScriptingInterface::exportEntities(const QString& filename, const QVector<EntityItemID>& entityIDs) {
|
||||
return Application::getInstance()->exportEntities(filename, entityIDs);
|
||||
bool retVal;
|
||||
QMetaObject::invokeMethod(Application::getInstance(), "exportEntities", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(bool, retVal),
|
||||
Q_ARG(const QString&, filename),
|
||||
Q_ARG(const QVector<EntityItemID>&, entityIDs));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool ClipboardScriptingInterface::exportEntities(const QString& filename, float x, float y, float z, float s) {
|
||||
return Application::getInstance()->exportEntities(filename, x, y, z, s);
|
||||
bool retVal;
|
||||
QMetaObject::invokeMethod(Application::getInstance(), "exportEntities", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(bool, retVal),
|
||||
Q_ARG(const QString&, filename),
|
||||
Q_ARG(float, x),
|
||||
Q_ARG(float, y),
|
||||
Q_ARG(float, z),
|
||||
Q_ARG(float, s));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
bool ClipboardScriptingInterface::importEntities(const QString& filename) {
|
||||
return Application::getInstance()->importEntities(filename);
|
||||
bool retVal;
|
||||
QMetaObject::invokeMethod(Application::getInstance(), "importEntities", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(bool, retVal),
|
||||
Q_ARG(const QString&, filename));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
QVector<EntityItemID> ClipboardScriptingInterface::pasteEntities(glm::vec3 position) {
|
||||
return Application::getInstance()->pasteEntities(position.x, position.y, position.z);
|
||||
QVector<EntityItemID> retVal;
|
||||
QMetaObject::invokeMethod(Application::getInstance(), "pasteEntities", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(QVector<EntityItemID>, retVal),
|
||||
Q_ARG(float, position.x),
|
||||
Q_ARG(float, position.y),
|
||||
Q_ARG(float, position.z));
|
||||
return retVal;
|
||||
}
|
||||
|
|
|
@ -171,6 +171,6 @@ QScriptValue Base3DOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -57,11 +57,12 @@ public:
|
|||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
|
||||
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, QString& extraInfo) {
|
||||
return findRayIntersection(origin, direction, distance, face);
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) {
|
||||
return findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -391,10 +391,10 @@ QScriptValue Circle3DOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
|
||||
bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin,
|
||||
const glm::vec3& direction, float& distance, BoxFace& face) {
|
||||
bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
|
||||
bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face);
|
||||
bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
||||
|
||||
if (intersects) {
|
||||
glm::vec3 hitPosition = origin + (distance * direction);
|
||||
|
|
|
@ -52,7 +52,8 @@ public:
|
|||
void setMajorTickMarksColor(const xColor& value) { _majorTickMarksColor = value; }
|
||||
void setMinorTickMarksColor(const xColor& value) { _minorTickMarksColor = value; }
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
|
||||
virtual Circle3DOverlay* createClone() const;
|
||||
|
||||
|
|
|
@ -166,7 +166,7 @@ void Image3DOverlay::setURL(const QString& url) {
|
|||
}
|
||||
|
||||
bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
if (_texture && _texture->isLoaded()) {
|
||||
// Make sure position and rotation is updated.
|
||||
applyTransformTo(_transform, true);
|
||||
|
@ -178,6 +178,7 @@ bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec
|
|||
float maxSize = glm::max(width, height);
|
||||
glm::vec2 dimensions = _dimensions * glm::vec2(width / maxSize, height / maxSize);
|
||||
|
||||
// FIXME - face and surfaceNormal not being set
|
||||
return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), dimensions, distance);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ public:
|
|||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
|
||||
virtual Image3DOverlay* createClone() const;
|
||||
|
||||
|
|
|
@ -159,16 +159,16 @@ QScriptValue ModelOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
|
||||
QString subMeshNameTemp;
|
||||
return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, subMeshNameTemp);
|
||||
return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, subMeshNameTemp);
|
||||
}
|
||||
|
||||
bool ModelOverlay::findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, QString& extraInfo) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) {
|
||||
|
||||
return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo);
|
||||
return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo);
|
||||
}
|
||||
|
||||
ModelOverlay* ModelOverlay::createClone() const {
|
||||
|
|
|
@ -29,9 +29,10 @@ public:
|
|||
virtual void render(RenderArgs* args);
|
||||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, QString& extraInfo);
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo);
|
||||
|
||||
virtual ModelOverlay* createClone() const;
|
||||
|
||||
|
|
|
@ -346,6 +346,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
|||
glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT);
|
||||
glm::vec3 direction(0, 0, 1);
|
||||
BoxFace thisFace;
|
||||
glm::vec3 thisSurfaceNormal;
|
||||
float distance;
|
||||
|
||||
while (i.hasPrevious()) {
|
||||
|
@ -354,7 +355,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
|||
if (i.value()->is3D()) {
|
||||
auto thisOverlay = std::dynamic_pointer_cast<Base3DOverlay>(i.value());
|
||||
if (thisOverlay && !thisOverlay->getIgnoreRayIntersection()) {
|
||||
if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace)) {
|
||||
if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace, thisSurfaceNormal)) {
|
||||
return thisID;
|
||||
}
|
||||
}
|
||||
|
@ -423,8 +424,10 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray)
|
|||
if (thisOverlay && thisOverlay->getVisible() && !thisOverlay->getIgnoreRayIntersection() && thisOverlay->isLoaded()) {
|
||||
float thisDistance;
|
||||
BoxFace thisFace;
|
||||
glm::vec3 thisSurfaceNormal;
|
||||
QString thisExtraInfo;
|
||||
if (thisOverlay->findRayIntersectionExtraInfo(ray.origin, ray.direction, thisDistance, thisFace, thisExtraInfo)) {
|
||||
if (thisOverlay->findRayIntersectionExtraInfo(ray.origin, ray.direction, thisDistance,
|
||||
thisFace, thisSurfaceNormal, thisExtraInfo)) {
|
||||
bool isDrawInFront = thisOverlay->getDrawInFront();
|
||||
if (thisDistance < bestDistance && (!bestIsFront || isDrawInFront)) {
|
||||
bestIsFront = isDrawInFront;
|
||||
|
@ -432,6 +435,7 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray)
|
|||
result.intersects = true;
|
||||
result.distance = thisDistance;
|
||||
result.face = thisFace;
|
||||
result.surfaceNormal = thisSurfaceNormal;
|
||||
result.overlayID = thisID;
|
||||
result.intersection = ray.origin + (ray.direction * thisDistance);
|
||||
result.extraInfo = thisExtraInfo;
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
int overlayID;
|
||||
float distance;
|
||||
BoxFace face;
|
||||
glm::vec3 surfaceNormal;
|
||||
glm::vec3 intersection;
|
||||
QString extraInfo;
|
||||
};
|
||||
|
|
|
@ -92,6 +92,7 @@ QScriptValue Planar3DOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
// FIXME - face and surfaceNormal not being returned
|
||||
return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), getDimensions(), distance);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ public:
|
|||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
|
||||
protected:
|
||||
glm::vec2 _dimensions;
|
||||
|
|
|
@ -211,7 +211,8 @@ QSizeF Text3DOverlay::textSize(const QString& text) const {
|
|||
return QSizeF(extents.x, extents.y) * pointToWorldScale;
|
||||
}
|
||||
|
||||
bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3 &direction, float &distance, BoxFace &face) {
|
||||
bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3 &direction, float &distance,
|
||||
BoxFace &face, glm::vec3& surfaceNormal) {
|
||||
applyTransformTo(_transform, true);
|
||||
return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face);
|
||||
return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
||||
}
|
||||
|
|
|
@ -54,7 +54,8 @@ public:
|
|||
|
||||
QSizeF textSize(const QString& test) const; // Meters
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
|
||||
virtual Text3DOverlay* createClone() const;
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ QScriptValue Volume3DOverlay::getProperty(const QString& property) {
|
|||
}
|
||||
|
||||
bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face) {
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::mat4 worldToEntityMatrix;
|
||||
_transform.getInverseMatrix(worldToEntityMatrix);
|
||||
|
@ -103,5 +103,5 @@ bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
|
|||
|
||||
// we can use the AABox's ray intersection by mapping our origin and direction into the overlays frame
|
||||
// and testing intersection there.
|
||||
return _localBoundingBox.findRayIntersection(overlayFrameOrigin, overlayFrameDirection, distance, face);
|
||||
return _localBoundingBox.findRayIntersection(overlayFrameOrigin, overlayFrameDirection, distance, face, surfaceNormal);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@ public:
|
|||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
|
||||
protected:
|
||||
// Centered local bounding box
|
||||
|
|
|
@ -151,8 +151,10 @@ void Web3DOverlay::setURL(const QString& url) {
|
|||
|
||||
}
|
||||
|
||||
bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) {
|
||||
//// Make sure position and rotation is updated.
|
||||
bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
// FIXME - face and surfaceNormal not being returned
|
||||
|
||||
// Make sure position and rotation is updated.
|
||||
applyTransformTo(_transform, true);
|
||||
vec2 size = _resolution / _dpi * INCHES_TO_METERS * vec2(getDimensions());
|
||||
// Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale.
|
||||
|
|
|
@ -34,7 +34,8 @@ public:
|
|||
virtual void setProperties(const QScriptValue& properties);
|
||||
virtual QScriptValue getProperty(const QString& property);
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face);
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal);
|
||||
|
||||
virtual Web3DOverlay* createClone() const;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -31,6 +31,8 @@ public:
|
|||
|
||||
private:
|
||||
float* _polyphaseFilter;
|
||||
int* _stepTable;
|
||||
|
||||
float* _history[MAX_CHANNELS];
|
||||
float* _inputs[MAX_CHANNELS];
|
||||
float* _outputs[MAX_CHANNELS];
|
||||
|
@ -45,10 +47,13 @@ private:
|
|||
int _numTaps;
|
||||
int _numHistory;
|
||||
|
||||
int _phase;
|
||||
int64_t _offset;
|
||||
int64_t _step;
|
||||
|
||||
int createPolyphaseFilter(int upFactor, int downFactor, float gain);
|
||||
int createRationalFilter(int upFactor, int downFactor, float gain);
|
||||
int createIrrationalFilter(int upFactor, int downFactor, float gain);
|
||||
|
||||
int multirateFilter1(const float* input0, float* output0, int inputFrames);
|
||||
int multirateFilter2(const float* input0, const float* input1, float* output0, float* output1, int inputFrames);
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
set(TARGET_NAME entities-renderer)
|
||||
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model render)
|
||||
AUTOSCRIBE_SHADER_LIB(gpu model render render-utils)
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Widgets Network Script)
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
<!
|
||||
// DeferredBufferWrite.slh
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Sam Gateau on 1/12/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
|
||||
!>
|
||||
<@if not DEFERRED_BUFFER_WRITE_SLH@>
|
||||
<@def DEFERRED_BUFFER_WRITE_SLH@>
|
||||
|
||||
layout(location = 0) out vec4 _fragColor0;
|
||||
layout(location = 1) out vec4 _fragColor1;
|
||||
layout(location = 2) out vec4 _fragColor2;
|
||||
|
||||
// the glow intensity
|
||||
uniform float glowIntensity;
|
||||
|
||||
// the alpha threshold
|
||||
uniform float alphaThreshold;
|
||||
|
||||
uniform sampler2D normalFittingMap;
|
||||
|
||||
vec3 bestFitNormal(vec3 normal) {
|
||||
vec3 absNorm = abs(normal);
|
||||
float maxNAbs = max(absNorm.z, max(absNorm.x, absNorm.y));
|
||||
|
||||
vec2 texcoord = (absNorm.z < maxNAbs ?
|
||||
(absNorm.y < maxNAbs ? absNorm.yz : absNorm.xz) :
|
||||
absNorm.xy);
|
||||
texcoord = (texcoord.x < texcoord.y ? texcoord.yx : texcoord.xy);
|
||||
texcoord.y /= texcoord.x;
|
||||
vec3 cN = normal / maxNAbs;
|
||||
float fittingScale = texture(normalFittingMap, texcoord).a;
|
||||
cN *= fittingScale;
|
||||
return (cN * 0.5 + 0.5);
|
||||
}
|
||||
|
||||
float evalOpaqueFinalAlpha(float alpha, float mapAlpha) {
|
||||
return mix(alpha * glowIntensity, 1.0 - alpha * glowIntensity, step(mapAlpha, alphaThreshold));
|
||||
}
|
||||
|
||||
const vec3 DEFAULT_SPECULAR = vec3(0.1);
|
||||
const float DEFAULT_SHININESS = 10;
|
||||
|
||||
void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) {
|
||||
if (alpha != glowIntensity) {
|
||||
discard;
|
||||
}
|
||||
_fragColor0 = vec4(diffuse.rgb, alpha);
|
||||
_fragColor1 = vec4(bestFitNormal(normal), 1.0);
|
||||
_fragColor2 = vec4(specular, shininess / 128.0);
|
||||
}
|
||||
|
||||
void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess, vec3 emissive) {
|
||||
if (alpha != glowIntensity) {
|
||||
discard;
|
||||
}
|
||||
|
||||
_fragColor0 = vec4(diffuse.rgb, alpha);
|
||||
//_fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
_fragColor1 = vec4(bestFitNormal(normal), 0.5);
|
||||
_fragColor2 = vec4(emissive, shininess / 128.0);
|
||||
}
|
||||
|
||||
void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) {
|
||||
if (alpha <= alphaThreshold) {
|
||||
discard;
|
||||
}
|
||||
|
||||
_fragColor0 = vec4(diffuse.rgb, alpha);
|
||||
// _fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
// _fragColor2 = vec4(specular, shininess / 128.0);
|
||||
}
|
||||
|
||||
<@endif@>
|
|
@ -113,9 +113,7 @@ void EntityTreeRenderer::init() {
|
|||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(_entitiesScriptEngine);
|
||||
}
|
||||
|
||||
// make sure our "last avatar position" is something other than our current position, so that on our
|
||||
// first chance, we'll check for enter/leave entity events.
|
||||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
forceRecheckEntities(); // setup our state to force checking our inside/outsideness of entities
|
||||
|
||||
connect(entityTree.get(), &EntityTree::deletingEntity, this, &EntityTreeRenderer::deletingEntity, Qt::QueuedConnection);
|
||||
connect(entityTree.get(), &EntityTree::addingEntity, this, &EntityTreeRenderer::addingEntity, Qt::QueuedConnection);
|
||||
|
@ -141,6 +139,13 @@ void EntityTreeRenderer::update() {
|
|||
// check to see if the avatar has moved and if we need to handle enter/leave entity logic
|
||||
checkEnterLeaveEntities();
|
||||
|
||||
// even if we haven't changed positions, if we previously attempted to set the skybox, but
|
||||
// have a pending download of the skybox texture, then we should attempt to reapply to
|
||||
// get the correct texture.
|
||||
if (_pendingSkyboxTextureDownload) {
|
||||
applyZonePropertiesToScene(_bestZone);
|
||||
}
|
||||
|
||||
// Even if we're not moving the mouse, if we started clicking on an entity and we have
|
||||
// not yet released the hold then this is still considered a holdingClickOnEntity event
|
||||
// and we want to simulate this message here as well as in mouse move
|
||||
|
@ -156,7 +161,7 @@ void EntityTreeRenderer::update() {
|
|||
void EntityTreeRenderer::checkEnterLeaveEntities() {
|
||||
if (_tree && !_shuttingDown) {
|
||||
glm::vec3 avatarPosition = _viewState->getAvatarPosition();
|
||||
|
||||
|
||||
if (avatarPosition != _lastAvatarPosition) {
|
||||
float radius = 1.0f; // for now, assume 1 meter radius
|
||||
QVector<EntityItemPointer> foundEntities;
|
||||
|
@ -238,13 +243,17 @@ void EntityTreeRenderer::leaveAllEntities() {
|
|||
_entitiesScriptEngine->callEntityScriptMethod(entityID, "leaveEntity");
|
||||
}
|
||||
_currentEntitiesInside.clear();
|
||||
|
||||
// make sure our "last avatar position" is something other than our current position, so that on our
|
||||
// first chance, we'll check for enter/leave entity events.
|
||||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
forceRecheckEntities();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::forceRecheckEntities() {
|
||||
// make sure our "last avatar position" is something other than our current position,
|
||||
// so that on our next chance, we'll check for enter/leave entity events.
|
||||
_lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE);
|
||||
}
|
||||
|
||||
|
||||
void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone) {
|
||||
QSharedPointer<SceneScriptingInterface> scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
if (zone) {
|
||||
|
@ -289,7 +298,8 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
|
||||
_viewState->overrideEnvironmentData(data);
|
||||
scene->getSkyStage()->setBackgroundMode(model::SunSkyStage::SKY_DOME);
|
||||
|
||||
_pendingSkyboxTextureDownload = false;
|
||||
|
||||
} else {
|
||||
_viewState->endOverrideEnvironmentData();
|
||||
auto stage = scene->getSkyStage();
|
||||
|
@ -308,17 +318,26 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
}
|
||||
if (zone->getSkyboxProperties().getURL().isEmpty()) {
|
||||
skybox->setCubemap(gpu::TexturePointer());
|
||||
_pendingSkyboxTextureDownload = false;
|
||||
} else {
|
||||
// Update the Texture of the Skybox with the one pointed by this zone
|
||||
auto cubeMap = DependencyManager::get<TextureCache>()->getTexture(zone->getSkyboxProperties().getURL(), CUBE_TEXTURE);
|
||||
skybox->setCubemap(cubeMap->getGPUTexture());
|
||||
|
||||
if (cubeMap->getGPUTexture()) {
|
||||
skybox->setCubemap(cubeMap->getGPUTexture());
|
||||
_pendingSkyboxTextureDownload = false;
|
||||
} else {
|
||||
_pendingSkyboxTextureDownload = true;
|
||||
}
|
||||
}
|
||||
stage->setBackgroundMode(model::SunSkyStage::SKY_BOX);
|
||||
} else {
|
||||
stage->setBackgroundMode(model::SunSkyStage::SKY_DOME); // let the application atmosphere through
|
||||
_pendingSkyboxTextureDownload = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_pendingSkyboxTextureDownload = false;
|
||||
if (_hasPreviousZone) {
|
||||
scene->setKeyLightColor(_previousKeyLightColor);
|
||||
scene->setKeyLightIntensity(_previousKeyLightIntensity);
|
||||
|
@ -470,9 +489,10 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons
|
|||
|
||||
OctreeElementPointer element;
|
||||
EntityItemPointer intersectedEntity = NULL;
|
||||
result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
|
||||
(void**)&intersectedEntity, lockType, &result.accurate,
|
||||
precisionPicking);
|
||||
result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance,
|
||||
result.face, result.surfaceNormal,
|
||||
(void**)&intersectedEntity, lockType, &result.accurate,
|
||||
precisionPicking);
|
||||
if (result.intersects && intersectedEntity) {
|
||||
result.entityID = intersectedEntity->getEntityItemID();
|
||||
result.properties = intersectedEntity->getProperties();
|
||||
|
@ -641,6 +661,8 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
|||
_entitiesScriptEngine->unloadEntityScript(entityID);
|
||||
}
|
||||
|
||||
forceRecheckEntities(); // reset our state to force checking our inside/outsideness of entities
|
||||
|
||||
// here's where we remove the entity payload from the scene
|
||||
if (_entitiesInScene.contains(entityID)) {
|
||||
auto entity = _entitiesInScene.take(entityID);
|
||||
|
@ -652,6 +674,7 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
|||
}
|
||||
|
||||
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
||||
forceRecheckEntities(); // reset our state to force checking our inside/outsideness of entities
|
||||
checkAndCallPreload(entityID);
|
||||
auto entity = std::static_pointer_cast<EntityTree>(_tree)->findEntityByID(entityID);
|
||||
if (entity) {
|
||||
|
|
|
@ -87,10 +87,10 @@ public:
|
|||
QList<EntityItemID>& getEntitiesLastInScene() { return _entityIDsLastInScene; }
|
||||
|
||||
signals:
|
||||
void mousePressOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId);
|
||||
void mousePressOffEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId);
|
||||
void mouseMoveOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId);
|
||||
void mouseReleaseOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId);
|
||||
void mousePressOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId);
|
||||
void mousePressOffEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId);
|
||||
void mouseMoveOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId);
|
||||
void mouseReleaseOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId);
|
||||
|
||||
void clickDownOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
|
||||
void holdingClickOnEntity(const EntityItemID& entityItemID, const MouseEvent& event);
|
||||
|
@ -138,7 +138,10 @@ private:
|
|||
QScriptValueList createEntityArgs(const EntityItemID& entityID);
|
||||
void checkEnterLeaveEntities();
|
||||
void leaveAllEntities();
|
||||
void forceRecheckEntities();
|
||||
|
||||
glm::vec3 _lastAvatarPosition;
|
||||
bool _pendingSkyboxTextureDownload = false;
|
||||
QVector<EntityItemID> _currentEntitiesInside;
|
||||
|
||||
bool _wantScripts;
|
||||
|
|
|
@ -54,8 +54,9 @@ void RenderableLightEntityItem::render(RenderArgs* args) {
|
|||
};
|
||||
|
||||
bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
|
||||
// TODO: consider if this is really what we want to do. We've made it so that "lights are pickable" is a global state
|
||||
// this is probably reasonable since there's typically only one tree you'd be picking on at a time. Technically we could
|
||||
|
|
|
@ -26,7 +26,8 @@ public:
|
|||
virtual void render(RenderArgs* args);
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
|
|
@ -366,9 +366,9 @@ EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlag
|
|||
return properties;
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const {
|
||||
if (!_model) {
|
||||
return true;
|
||||
}
|
||||
|
@ -376,7 +376,8 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
|||
// << precisionPicking;
|
||||
|
||||
QString extraInfo;
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking);
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||
face, surfaceNormal, extraInfo, precisionPicking);
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
|
||||
|
|
|
@ -55,8 +55,9 @@ public:
|
|||
virtual void render(RenderArgs* args);
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
Model* getModel(EntityTreeRenderer* renderer);
|
||||
|
||||
|
|
|
@ -348,13 +348,10 @@ public:
|
|||
const PolyVox::SimpleVolume<uint8_t>* _vol = nullptr;
|
||||
};
|
||||
|
||||
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin,
|
||||
const glm::vec3& direction,
|
||||
bool& keepSearching,
|
||||
OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face,
|
||||
void** intersectedObject,
|
||||
bool precisionPicking) const
|
||||
bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const
|
||||
{
|
||||
// TODO -- correctly pick against marching-cube generated meshes
|
||||
if (!precisionPicking) {
|
||||
|
@ -392,7 +389,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
|||
|
||||
float voxelDistance;
|
||||
|
||||
bool hit = voxelBox.findRayIntersection(glm::vec3(originInVoxel), glm::vec3(directionInVoxel), voxelDistance, face);
|
||||
bool hit = voxelBox.findRayIntersection(glm::vec3(originInVoxel), glm::vec3(directionInVoxel), voxelDistance, face, surfaceNormal);
|
||||
|
||||
glm::vec4 voxelIntersectionPoint = glm::vec4(glm::vec3(originInVoxel) + glm::vec3(directionInVoxel) * voxelDistance, 1.0);
|
||||
glm::vec4 intersectionPoint = vtwMatrix * voxelIntersectionPoint;
|
||||
|
|
|
@ -64,8 +64,9 @@ public:
|
|||
void render(RenderArgs* args);
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
virtual void setVoxelData(QByteArray voxelData);
|
||||
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
|
||||
|
|
|
@ -206,7 +206,8 @@ public:
|
|||
|
||||
virtual bool supportsDetailedRayIntersection() const { return false; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const { return true; }
|
||||
|
||||
// attributes applicable to all entity types
|
||||
|
|
|
@ -297,7 +297,7 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorke
|
|||
OctreeElementPointer element;
|
||||
EntityItemPointer intersectedEntity = NULL;
|
||||
result.intersects = _entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
|
||||
(void**)&intersectedEntity, lockType, &result.accurate,
|
||||
result.surfaceNormal, (void**)&intersectedEntity, lockType, &result.accurate,
|
||||
precisionPicking);
|
||||
if (result.intersects && intersectedEntity) {
|
||||
result.entityID = intersectedEntity->getEntityItemID();
|
||||
|
@ -393,6 +393,9 @@ QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, c
|
|||
|
||||
QScriptValue intersection = vec3toScriptValue(engine, value.intersection);
|
||||
obj.setProperty("intersection", intersection);
|
||||
|
||||
QScriptValue surfaceNormal = vec3toScriptValue(engine, value.surfaceNormal);
|
||||
obj.setProperty("surfaceNormal", surfaceNormal);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -426,6 +429,10 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra
|
|||
if (intersection.isValid()) {
|
||||
vec3FromScriptValue(intersection, value.intersection);
|
||||
}
|
||||
QScriptValue surfaceNormal = object.property("surfaceNormal");
|
||||
if (surfaceNormal.isValid()) {
|
||||
vec3FromScriptValue(surfaceNormal, value.surfaceNormal);
|
||||
}
|
||||
}
|
||||
|
||||
bool EntityScriptingInterface::setVoxels(QUuid entityID,
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
float distance;
|
||||
BoxFace face;
|
||||
glm::vec3 intersection;
|
||||
glm::vec3 surfaceNormal;
|
||||
EntityItemPointer entity;
|
||||
};
|
||||
|
||||
|
|
|
@ -492,9 +492,9 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3
|
|||
return false;
|
||||
}
|
||||
|
||||
bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking, float distanceToElementCube) {
|
||||
bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking, float distanceToElementCube) {
|
||||
|
||||
// only called if we do intersect our bounding cube, but find if we actually intersect with entities...
|
||||
int entityNumber = 0;
|
||||
|
@ -503,9 +503,10 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
|
|||
AABox entityBox = entity->getAABox();
|
||||
float localDistance;
|
||||
BoxFace localFace;
|
||||
glm::vec3 localSurfaceNormal;
|
||||
|
||||
// if the ray doesn't intersect with our cube, we can stop searching!
|
||||
if (!entityBox.findRayIntersection(origin, direction, localDistance, localFace)) {
|
||||
if (!entityBox.findRayIntersection(origin, direction, localDistance, localFace, localSurfaceNormal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -526,16 +527,18 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
|
|||
|
||||
// we can use the AABox's ray intersection by mapping our origin and direction into the entity frame
|
||||
// and testing intersection there.
|
||||
if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) {
|
||||
if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance,
|
||||
localFace, localSurfaceNormal)) {
|
||||
if (localDistance < distance) {
|
||||
// now ask the entity if we actually intersect
|
||||
if (entity->supportsDetailedRayIntersection()) {
|
||||
if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance,
|
||||
localFace, intersectedObject, precisionPicking)) {
|
||||
localFace, localSurfaceNormal, intersectedObject, precisionPicking)) {
|
||||
|
||||
if (localDistance < distance) {
|
||||
distance = localDistance;
|
||||
face = localFace;
|
||||
surfaceNormal = localSurfaceNormal;
|
||||
*intersectedObject = (void*)entity.get();
|
||||
somethingIntersected = true;
|
||||
}
|
||||
|
@ -545,6 +548,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con
|
|||
if (localDistance < distance) {
|
||||
distance = localDistance;
|
||||
face = localFace;
|
||||
surfaceNormal = localSurfaceNormal;
|
||||
*intersectedObject = (void*)entity.get();
|
||||
somethingIntersected = true;
|
||||
}
|
||||
|
|
|
@ -143,7 +143,8 @@ public:
|
|||
|
||||
virtual bool canRayIntersect() const { return hasEntities(); }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking, float distanceToElementCube);
|
||||
|
||||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||
|
|
|
@ -64,8 +64,9 @@ class LineEntityItem : public EntityItem {
|
|||
// never have a ray intersection pick a LineEntityItem.
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const { return false; }
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const { return false; }
|
||||
|
||||
virtual void debugDump() const;
|
||||
static const float DEFAULT_LINE_WIDTH;
|
||||
|
|
|
@ -73,8 +73,9 @@ class PolyLineEntityItem : public EntityItem {
|
|||
// never have a ray intersection pick a PolyLineEntityItem.
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const { return false; }
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const { return false;}
|
||||
|
||||
virtual void debugDump() const;
|
||||
static const float DEFAULT_LINE_WIDTH;
|
||||
|
|
|
@ -44,8 +44,9 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
// never have a ray intersection pick a PolyVoxEntityItem.
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const { return false; }
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const { return false; }
|
||||
|
||||
virtual void debugDump() const;
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ void SphereEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBi
|
|||
|
||||
bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element,
|
||||
float& distance, BoxFace& face,
|
||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
// determine the ray in the frame of the entity transformed from a unit sphere
|
||||
glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
|
||||
|
@ -111,6 +111,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons
|
|||
// then translate back to work coordinates
|
||||
glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f));
|
||||
distance = glm::distance(origin, hitAt);
|
||||
surfaceNormal = glm::normalize(hitAt - getCenterPosition());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -54,8 +54,9 @@ public:
|
|||
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
virtual void debugDump() const;
|
||||
|
||||
|
|
|
@ -129,12 +129,15 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
|
|||
}
|
||||
|
||||
bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
|
||||
glm::quat rotation = getRotation();
|
||||
glm::vec3 position = getPosition() + rotation *
|
||||
(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
|
||||
|
||||
// FIXME - should set face and surfaceNormal
|
||||
return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,8 @@ public:
|
|||
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
static const QString DEFAULT_TEXT;
|
||||
|
|
|
@ -99,13 +99,15 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
|
|||
}
|
||||
|
||||
bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
|
||||
glm::quat rotation = getRotation();
|
||||
glm::vec3 position = getPosition() + rotation *
|
||||
(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
|
||||
// FIXME - should set face and surfaceNormal
|
||||
return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@ public:
|
|||
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
virtual void setSourceUrl(const QString& value);
|
||||
|
|
|
@ -246,7 +246,8 @@ void ZoneEntityItem::setCompoundShapeURL(const QString& url) {
|
|||
}
|
||||
|
||||
bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
|
||||
return _zonesArePickable;
|
||||
|
|
|
@ -100,7 +100,8 @@ public:
|
|||
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
virtual void debugDump() const;
|
||||
|
|
|
@ -934,7 +934,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
_textureContent.insert(filename, content);
|
||||
}
|
||||
} else if (object.name == "Material") {
|
||||
FBXMaterial material(glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3(1.0f), glm::vec3(), glm::vec2(0.f, 1.0f), 96.0f, 1.0f);
|
||||
FBXMaterial material;
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
bool properties = false;
|
||||
QByteArray propertyName;
|
||||
|
@ -954,9 +954,17 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
if (property.name == propertyName) {
|
||||
if (property.properties.at(0) == "DiffuseColor") {
|
||||
material.diffuseColor = getVec3(property.properties, index);
|
||||
} else if (property.properties.at(0) == "Diffuse") {
|
||||
material.diffuseColor = getVec3(property.properties, index);
|
||||
} else if (property.properties.at(0) == "DiffuseFactor") {
|
||||
material.diffuseFactor = property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "SpecularColor") {
|
||||
material.specularColor = getVec3(property.properties, index);
|
||||
} else if (property.properties.at(0) == "Specular") {
|
||||
material.specularColor = getVec3(property.properties, index);
|
||||
} else if (property.properties.at(0) == "SpecularFactor") {
|
||||
material.specularFactor = property.properties.at(index).value<double>();
|
||||
|
||||
} else if (property.properties.at(0) == "Emissive") {
|
||||
material.emissiveColor = getVec3(property.properties, index);
|
||||
|
|
|
@ -137,21 +137,24 @@ public:
|
|||
class FBXMaterial {
|
||||
public:
|
||||
FBXMaterial() {};
|
||||
FBXMaterial(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor,
|
||||
const glm::vec2& emissiveParams, float shininess, float opacity) :
|
||||
diffuseColor(diffuseColor),
|
||||
specularColor(specularColor),
|
||||
emissiveColor(emissiveColor),
|
||||
emissiveParams(emissiveParams),
|
||||
shininess(shininess),
|
||||
opacity(opacity) {}
|
||||
FBXMaterial(const glm::vec3& diffuseColor, const glm::vec3& specularColor, const glm::vec3& emissiveColor,
|
||||
const glm::vec2& emissiveParams, float shininess, float opacity) :
|
||||
diffuseColor(diffuseColor),
|
||||
specularColor(specularColor),
|
||||
emissiveColor(emissiveColor),
|
||||
emissiveParams(emissiveParams),
|
||||
shininess(shininess),
|
||||
opacity(opacity) {}
|
||||
|
||||
glm::vec3 diffuseColor;
|
||||
glm::vec3 specularColor;
|
||||
glm::vec3 emissiveColor;
|
||||
glm::vec2 emissiveParams;
|
||||
float shininess;
|
||||
float opacity;
|
||||
glm::vec3 diffuseColor{ 1.0f };
|
||||
float diffuseFactor = 1.0f;
|
||||
glm::vec3 specularColor{ 0.02f };
|
||||
float specularFactor = 1.0f;
|
||||
|
||||
glm::vec3 emissiveColor{ 0.0f };
|
||||
glm::vec2 emissiveParams{ 0.0f, 1.0f };
|
||||
float shininess = 23.0f;
|
||||
float opacity = 1.0f;
|
||||
|
||||
QString materialID;
|
||||
model::MaterialPointer _material;
|
||||
|
|
|
@ -134,12 +134,16 @@ void FBXReader::consolidateFBXMaterials() {
|
|||
// Finally create the true material representation
|
||||
material._material = std::make_shared<model::Material>();
|
||||
material._material->setEmissive(material.emissiveColor);
|
||||
if (glm::all(glm::equal(material.diffuseColor, glm::vec3(0.0f)))) {
|
||||
material._material->setDiffuse(material.diffuseColor);
|
||||
} else {
|
||||
material._material->setDiffuse(material.diffuseColor);
|
||||
}
|
||||
material._material->setMetallic(glm::length(material.specularColor));
|
||||
|
||||
auto diffuse = material.diffuseColor;
|
||||
// FIXME: Do not use the Diffuse Factor yet as some FBX models have it set to 0
|
||||
// diffuse *= material.diffuseFactor;
|
||||
material._material->setDiffuse(diffuse);
|
||||
|
||||
float metallic = std::max(material.specularColor.x, std::max(material.specularColor.y, material.specularColor.z));
|
||||
// FIXME: Do not use the Specular Factor yet as some FBX models have it set to 0
|
||||
// metallic *= material.specularFactor;
|
||||
material._material->setMetallic(metallic);
|
||||
material._material->setGloss(material.shininess);
|
||||
|
||||
if (material.opacity <= 0.0f) {
|
||||
|
|
|
@ -418,10 +418,10 @@ void GLBackend::resetStages() {
|
|||
#define DO_IT_NOW(call, offset)
|
||||
|
||||
void Batch::_glActiveBindTexture(GLenum unit, GLenum target, GLuint texture) {
|
||||
// clean the cache on the texture unit we are going to use so the next call to setResourceTexture() at the same slot works fine
|
||||
setResourceTexture(unit - GL_TEXTURE0, nullptr);
|
||||
|
||||
ADD_COMMAND_GL(glActiveBindTexture);
|
||||
|
||||
_params.push_back(texture);
|
||||
_params.push_back(target);
|
||||
_params.push_back(unit);
|
||||
|
@ -434,6 +434,7 @@ void GLBackend::do_glActiveBindTexture(Batch& batch, uint32 paramOffset) {
|
|||
glBindTexture(
|
||||
batch._params[paramOffset + 1]._uint,
|
||||
batch._params[paramOffset + 0]._uint);
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,8 @@ void GLBackend::syncInputStateCache() {
|
|||
|
||||
// Core 41 doesn't expose the features to really separate the vertex format from the vertex buffers binding
|
||||
// Core 43 does :)
|
||||
#if (GPU_INPUT_PROFILE == GPU_CORE_41)
|
||||
// FIXME crashing problem with glVertexBindingDivisor / glVertexAttribFormat
|
||||
#if 1 || (GPU_INPUT_PROFILE == GPU_CORE_41)
|
||||
#define NO_SUPPORT_VERTEX_ATTRIB_FORMAT
|
||||
#else
|
||||
#define SUPPORT_VERTEX_ATTRIB_FORMAT
|
||||
|
@ -117,9 +118,9 @@ void GLBackend::updateInput() {
|
|||
for (size_t locNum = 0; locNum < locationCount; ++locNum) {
|
||||
newActivation.set(slot + locNum);
|
||||
glVertexAttribFormat(slot + locNum, count, type, isNormalized, offset + locNum * perLocationSize);
|
||||
glVertexAttribDivisor(slot + locNum, attrib._frequency);
|
||||
glVertexAttribBinding(slot + locNum, attrib._channel);
|
||||
}
|
||||
glVertexBindingDivisor(attrib._channel, attrib._frequency);
|
||||
}
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
|
|
|
@ -97,7 +97,12 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
|
|||
|
||||
if (_invalidModel) {
|
||||
_model.getMatrix(_object._model);
|
||||
_model.getInverseMatrix(_object._modelInverse);
|
||||
|
||||
// FIXME - we don't want to be using glm::inverse() here but it fixes the flickering issue we are
|
||||
// seeing with planky blocks in toybox. Our implementation of getInverseMatrix() is buggy in cases
|
||||
// of non-uniform scale. We need to fix that. In the mean time, glm::inverse() works.
|
||||
//_model.getInverseMatrix(_object._modelInverse);
|
||||
_object._modelInverse = glm::inverse(_object._model);
|
||||
}
|
||||
|
||||
if (_invalidView || _invalidProj || _invalidViewport) {
|
||||
|
|
|
@ -230,12 +230,15 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
|
|||
return TextureLoaderFunc(model::TextureUsage::createNormalTextureFromBumpImage);
|
||||
break;
|
||||
}
|
||||
case NORMAL_TEXTURE: {
|
||||
return TextureLoaderFunc(model::TextureUsage::createNormalTextureFromNormalImage);
|
||||
break;
|
||||
}
|
||||
case CUSTOM_TEXTURE: {
|
||||
return _textureLoader;
|
||||
break;
|
||||
}
|
||||
case DEFAULT_TEXTURE:
|
||||
case NORMAL_TEXTURE:
|
||||
case SPECULAR_TEXTURE:
|
||||
case EMISSIVE_TEXTURE:
|
||||
default: {
|
||||
|
|
|
@ -137,6 +137,40 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
|
|||
return theTexture;
|
||||
}
|
||||
|
||||
|
||||
gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
} else {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
}
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
bool isLinearRGB = true;
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
||||
return theTexture;
|
||||
}
|
||||
|
||||
int clampPixelCoordinate(int coordinate, int maxCoordinate) {
|
||||
return coordinate - ((int)(coordinate < 0) * coordinate) + ((int)(coordinate > maxCoordinate) * (maxCoordinate - coordinate));
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ public:
|
|||
int _environmentUsage = 0;
|
||||
|
||||
static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createNormalTextureFromNormalImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
};
|
||||
|
|
|
@ -702,6 +702,7 @@ public:
|
|||
OctreeElementPointer& element;
|
||||
float& distance;
|
||||
BoxFace& face;
|
||||
glm::vec3& surfaceNormal;
|
||||
void** intersectedObject;
|
||||
bool found;
|
||||
bool precisionPicking;
|
||||
|
@ -711,17 +712,18 @@ bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) {
|
|||
RayArgs* args = static_cast<RayArgs*>(extraData);
|
||||
bool keepSearching = true;
|
||||
if (element->findRayIntersection(args->origin, args->direction, keepSearching,
|
||||
args->element, args->distance, args->face, args->intersectedObject, args->precisionPicking)) {
|
||||
args->element, args->distance, args->face, args->surfaceNormal,
|
||||
args->intersectedObject, args->precisionPicking)) {
|
||||
args->found = true;
|
||||
}
|
||||
return keepSearching;
|
||||
}
|
||||
|
||||
bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject,
|
||||
Octree::lockType lockType, bool* accurateResult, bool precisionPicking) {
|
||||
RayArgs args = { origin, direction, element, distance, face,
|
||||
intersectedObject, false, precisionPicking};
|
||||
RayArgs args = { origin, direction, element, distance, face, surfaceNormal, intersectedObject, false, precisionPicking};
|
||||
distance = FLT_MAX;
|
||||
|
||||
bool requireLock = lockType == Octree::Lock;
|
||||
|
|
|
@ -299,7 +299,7 @@ public:
|
|||
} lockType;
|
||||
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& node, float& distance, BoxFace& face,
|
||||
OctreeElementPointer& node, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject = NULL,
|
||||
Octree::lockType lockType = Octree::TryLock,
|
||||
bool* accurateResult = NULL,
|
||||
|
|
|
@ -574,7 +574,8 @@ void OctreeElement::notifyUpdateHooks() {
|
|||
}
|
||||
|
||||
bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking) {
|
||||
|
||||
keepSearching = true; // assume that we will continue searching after this.
|
||||
|
@ -582,9 +583,10 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3
|
|||
float distanceToElementCube = std::numeric_limits<float>::max();
|
||||
float distanceToElementDetails = distance;
|
||||
BoxFace localFace;
|
||||
glm::vec3 localSurfaceNormal;
|
||||
|
||||
// if the ray doesn't intersect with our cube, we can stop searching!
|
||||
if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace)) {
|
||||
if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal)) {
|
||||
keepSearching = false; // no point in continuing to search
|
||||
return false; // we did not intersect
|
||||
}
|
||||
|
@ -599,11 +601,12 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3
|
|||
if (_cube.contains(origin) || distanceToElementCube < distance) {
|
||||
|
||||
if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails,
|
||||
face, intersectedObject, precisionPicking, distanceToElementCube)) {
|
||||
face, localSurfaceNormal, intersectedObject, precisionPicking, distanceToElementCube)) {
|
||||
|
||||
if (distanceToElementDetails < distance) {
|
||||
distance = distanceToElementDetails;
|
||||
face = localFace;
|
||||
surfaceNormal = localSurfaceNormal;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -612,7 +615,8 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3
|
|||
}
|
||||
|
||||
bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking, float distanceToElementCube) {
|
||||
|
||||
// we did hit this element, so calculate appropriate distances
|
||||
|
|
|
@ -119,11 +119,13 @@ public:
|
|||
|
||||
virtual bool canRayIntersect() const { return isLeaf(); }
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& node, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& node, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject = NULL, bool precisionPicking = false);
|
||||
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
void** intersectedObject, bool precisionPicking, float distanceToElementCube);
|
||||
|
||||
/// \param center center of sphere in meters
|
||||
|
|
|
@ -189,6 +189,7 @@ void Model::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, Model:
|
|||
locations.emissiveParams = program->getUniforms().findLocation("emissiveParams");
|
||||
locations.glowIntensity = program->getUniforms().findLocation("glowIntensity");
|
||||
locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
|
||||
locations.diffuseTextureUnit = program->getTextures().findLocation("diffuseMap");
|
||||
locations.normalTextureUnit = program->getTextures().findLocation("normalMap");
|
||||
locations.specularTextureUnit = program->getTextures().findLocation("specularMap");
|
||||
locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
|
||||
|
@ -457,7 +458,8 @@ void Model::initJointStates(QVector<JointState> states) {
|
|||
}
|
||||
|
||||
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, QString& extraInfo, bool pickAgainstTriangles) {
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QString& extraInfo, bool pickAgainstTriangles) {
|
||||
|
||||
bool intersectedSomething = false;
|
||||
|
||||
|
@ -484,11 +486,12 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
|
||||
// we can use the AABox's ray intersection by mapping our origin and direction into the model frame
|
||||
// and testing intersection there.
|
||||
if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) {
|
||||
if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face, surfaceNormal)) {
|
||||
float bestDistance = std::numeric_limits<float>::max();
|
||||
|
||||
float distanceToSubMesh;
|
||||
BoxFace subMeshFace;
|
||||
glm::vec3 subMeshSurfaceNormal;
|
||||
int subMeshIndex = 0;
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
|
@ -500,9 +503,9 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
recalculateMeshBoxes(pickAgainstTriangles);
|
||||
}
|
||||
|
||||
foreach(const AABox& subMeshBox, _calculatedMeshBoxes) {
|
||||
foreach (const AABox& subMeshBox, _calculatedMeshBoxes) {
|
||||
|
||||
if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) {
|
||||
if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace, subMeshSurfaceNormal)) {
|
||||
if (distanceToSubMesh < bestDistance) {
|
||||
if (pickAgainstTriangles) {
|
||||
if (!_calculatedMeshTrianglesValid) {
|
||||
|
@ -520,6 +523,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
bestDistance = thisTriangleDistance;
|
||||
intersectedSomething = true;
|
||||
face = subMeshFace;
|
||||
surfaceNormal = triangle.getNormal();
|
||||
extraInfo = geometry.getModelNameOfMesh(subMeshIndex);
|
||||
}
|
||||
}
|
||||
|
@ -529,6 +533,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
bestDistance = distanceToSubMesh;
|
||||
intersectedSomething = true;
|
||||
face = subMeshFace;
|
||||
surfaceNormal = subMeshSurfaceNormal;
|
||||
extraInfo = geometry.getModelNameOfMesh(subMeshIndex);
|
||||
}
|
||||
}
|
||||
|
@ -1625,7 +1630,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
|
|||
// Diffuse
|
||||
if (materialKey.isDiffuseMap()) {
|
||||
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
|
||||
|
||||
if (diffuseMap && diffuseMap->isDefined()) {
|
||||
batch.setResourceTexture(DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
|
||||
|
||||
|
|
|
@ -129,7 +129,8 @@ public:
|
|||
void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f);
|
||||
|
||||
bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false);
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QString& extraInfo, bool pickAgainstTriangles = false);
|
||||
|
||||
// Set the model to use for collisions
|
||||
Q_INVOKABLE void setCollisionModelURL(const QUrl& url);
|
||||
|
@ -344,6 +345,7 @@ private:
|
|||
int tangent;
|
||||
int alphaThreshold;
|
||||
int texcoordMatrices;
|
||||
int diffuseTextureUnit;
|
||||
int normalTextureUnit;
|
||||
int specularTextureUnit;
|
||||
int emissiveTextureUnit;
|
||||
|
|
|
@ -221,7 +221,8 @@ bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& e
|
|||
isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x));
|
||||
}
|
||||
|
||||
bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const {
|
||||
bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) const {
|
||||
// handle the trivial case where the box contains the origin
|
||||
if (contains(origin)) {
|
||||
// We still want to calculate the distance from the origin to the inside out plane
|
||||
|
@ -231,6 +232,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) {
|
||||
distance = axisDistance;
|
||||
face = direction.x > 0 ? MAX_X_FACE : MIN_X_FACE;
|
||||
surfaceNormal = glm::vec3(direction.x > 0 ? 1.0f : -1.0f, 0.0f, 0.0f);
|
||||
return true;
|
||||
}
|
||||
if ((findInsideOutIntersection(origin.y, direction.y, _corner.y, _scale.y, axisDistance) && axisDistance >= 0 &&
|
||||
|
@ -238,6 +240,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) {
|
||||
distance = axisDistance;
|
||||
face = direction.y > 0 ? MAX_Y_FACE : MIN_Y_FACE;
|
||||
surfaceNormal = glm::vec3(0.0f, direction.y > 0 ? 1.0f : -1.0f, 0.0f);
|
||||
return true;
|
||||
}
|
||||
if ((findInsideOutIntersection(origin.z, direction.z, _corner.z, _scale.z, axisDistance) && axisDistance >= 0 &&
|
||||
|
@ -245,6 +248,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {
|
||||
distance = axisDistance;
|
||||
face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE;
|
||||
surfaceNormal = glm::vec3(0.0f, 0.0f, direction.z > 0 ? 1.0f : -1.0f);
|
||||
return true;
|
||||
}
|
||||
// This case is unexpected, but mimics the previous behavior for inside out intersections
|
||||
|
@ -259,6 +263,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) {
|
||||
distance = axisDistance;
|
||||
face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE;
|
||||
surfaceNormal = glm::vec3(direction.x > 0 ? -1.0f : 1.0f, 0.0f, 0.0f);
|
||||
return true;
|
||||
}
|
||||
if ((findIntersection(origin.y, direction.y, _corner.y, _scale.y, axisDistance) && axisDistance >= 0 &&
|
||||
|
@ -266,6 +271,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) {
|
||||
distance = axisDistance;
|
||||
face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE;
|
||||
surfaceNormal = glm::vec3(0.0f, direction.y > 0 ? -1.0f : 1.0f, 0.0f);
|
||||
return true;
|
||||
}
|
||||
if ((findIntersection(origin.z, direction.z, _corner.z, _scale.z, axisDistance) && axisDistance >= 0 &&
|
||||
|
@ -273,6 +279,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) {
|
||||
distance = axisDistance;
|
||||
face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
|
||||
surfaceNormal = glm::vec3(0.0f, 0.0f, direction.z > 0 ? -1.0f : 1.0f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -67,7 +67,8 @@ public:
|
|||
|
||||
bool expandedContains(const glm::vec3& point, float expansion) const;
|
||||
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const;
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) const;
|
||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
|
||||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
||||
|
||||
|
|
|
@ -219,7 +219,8 @@ bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3&
|
|||
isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x));
|
||||
}
|
||||
|
||||
bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const {
|
||||
bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) const {
|
||||
// handle the trivial case where the box contains the origin
|
||||
if (contains(origin)) {
|
||||
|
||||
|
@ -230,6 +231,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc
|
|||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
|
||||
distance = axisDistance;
|
||||
face = direction.x > 0 ? MAX_X_FACE : MIN_X_FACE;
|
||||
surfaceNormal = glm::vec3(direction.x > 0 ? 1.0f : -1.0f, 0.0f, 0.0f);
|
||||
return true;
|
||||
}
|
||||
if ((findInsideOutIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 &&
|
||||
|
@ -237,6 +239,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc
|
|||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
|
||||
distance = axisDistance;
|
||||
face = direction.y > 0 ? MAX_Y_FACE : MIN_Y_FACE;
|
||||
surfaceNormal = glm::vec3(0.0f, direction.y > 0 ? 1.0f : -1.0f, 0.0f);
|
||||
return true;
|
||||
}
|
||||
if ((findInsideOutIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 &&
|
||||
|
@ -244,6 +247,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc
|
|||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
|
||||
distance = axisDistance;
|
||||
face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE;
|
||||
surfaceNormal = glm::vec3(0.0f, 0.0f, direction.z > 0 ? 1.0f : -1.0f);
|
||||
return true;
|
||||
}
|
||||
// This case is unexpected, but mimics the previous behavior for inside out intersections
|
||||
|
@ -258,6 +262,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc
|
|||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
|
||||
distance = axisDistance;
|
||||
face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE;
|
||||
surfaceNormal = glm::vec3(direction.x > 0 ? -1.0f : 1.0f, 0.0f, 0.0f);
|
||||
return true;
|
||||
}
|
||||
if ((findIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 &&
|
||||
|
@ -265,6 +270,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc
|
|||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
|
||||
distance = axisDistance;
|
||||
face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE;
|
||||
surfaceNormal = glm::vec3(0.0f, direction.y > 0 ? -1.0f : 1.0f, 0.0f);
|
||||
return true;
|
||||
}
|
||||
if ((findIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 &&
|
||||
|
@ -272,6 +278,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc
|
|||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
|
||||
distance = axisDistance;
|
||||
face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
|
||||
surfaceNormal = glm::vec3(0.0f, 0.0f, direction.z > 0 ? -1.0f : 1.0f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -56,7 +56,8 @@ public:
|
|||
bool touches(const AABox& otherBox) const;
|
||||
bool expandedContains(const glm::vec3& point, float expansion) const;
|
||||
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const;
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const;
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) const;
|
||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const;
|
||||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
||||
|
||||
|
|
|
@ -255,6 +255,13 @@ bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direct
|
|||
return true;
|
||||
}
|
||||
|
||||
// reference https://www.opengl.org/wiki/Calculating_a_Surface_Normal
|
||||
glm::vec3 Triangle::getNormal() const {
|
||||
glm::vec3 edge1 = v1 - v0;
|
||||
glm::vec3 edge2 = v2 - v0;
|
||||
return glm::normalize(glm::cross(edge1, edge2));
|
||||
}
|
||||
|
||||
bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance) {
|
||||
glm::vec3 firstSide = v0 - v1;
|
||||
|
|
|
@ -97,6 +97,7 @@ public:
|
|||
glm::vec3 v0;
|
||||
glm::vec3 v1;
|
||||
glm::vec3 v2;
|
||||
glm::vec3 getNormal() const;
|
||||
};
|
||||
|
||||
inline bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
|
|
|
@ -26,8 +26,9 @@ void AABoxCubeTests::raycastOutHitsXMinFace() {
|
|||
glm::vec3 direction(-1.0f, 0.0f, 0.0f);
|
||||
float distance;
|
||||
BoxFace face;
|
||||
glm::vec3 surfaceNormal;
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face);
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
||||
|
||||
QCOMPARE(intersects, true);
|
||||
QCOMPARE(distance, 0.5f);
|
||||
|
@ -44,9 +45,10 @@ void AABoxCubeTests::raycastOutHitsXMaxFace () {
|
|||
glm::vec3 direction(1.0f, 0.0f, 0.0f);
|
||||
float distance;
|
||||
BoxFace face;
|
||||
glm::vec3 surfaceNormal;
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face);
|
||||
|
||||
QCOMPARE(intersects, true);
|
||||
QCOMPARE(distance, 0.5f);
|
||||
QCOMPARE(face, MAX_X_FACE);
|
||||
|
@ -61,9 +63,10 @@ void AABoxCubeTests::raycastInHitsXMinFace () {
|
|||
glm::vec3 direction(1.0f, 0.0f, 0.0f);
|
||||
float distance;
|
||||
BoxFace face;
|
||||
glm::vec3 surfaceNormal;
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face, surfaceNormal);
|
||||
|
||||
bool intersects = box.findRayIntersection(origin, direction, distance, face);
|
||||
|
||||
QCOMPARE(intersects, true);
|
||||
QCOMPARE(distance, 0.25f);
|
||||
QCOMPARE(face, MIN_X_FACE);
|
||||
|
|
Loading…
Reference in a new issue