Merge remote-tracking branch 'upstream/master'

This commit is contained in:
James Pollack 2015-09-29 12:58:43 -07:00
commit f5743aa770
76 changed files with 1240 additions and 4415 deletions

View file

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

View 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);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -46,6 +46,7 @@ public:
int overlayID;
float distance;
BoxFace face;
glm::vec3 surfaceNormal;
glm::vec3 intersection;
QString extraInfo;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -43,6 +43,7 @@ public:
float distance;
BoxFace face;
glm::vec3 intersection;
glm::vec3 surfaceNormal;
EntityItemPointer entity;
};

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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