mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 17:53:32 +02:00
Working on avatar billboards.
This commit is contained in:
parent
7010c45b16
commit
6b90a3994d
8 changed files with 137 additions and 71 deletions
|
@ -527,73 +527,8 @@ void Application::paintGL() {
|
|||
_glowEffect.render();
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
|
||||
bool eyeRelativeCamera = false;
|
||||
if (_rearMirrorTools->getZoomLevel() == BODY) {
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getChestPosition());
|
||||
} else { // HEAD zoom level
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
|
||||
if (_myAvatar->getSkeletonModel().isActive() && _myAvatar->getHead()->getFaceModel().isActive()) {
|
||||
// as a hack until we have a better way of dealing with coordinate precision issues, reposition the
|
||||
// face/body so that the average eye position lies at the origin
|
||||
eyeRelativeCamera = true;
|
||||
_mirrorCamera.setTargetPosition(glm::vec3());
|
||||
|
||||
} else {
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
|
||||
}
|
||||
}
|
||||
|
||||
_mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||
_mirrorCamera.update(1.0f/_fps);
|
||||
|
||||
// set the bounds of rear mirror view
|
||||
glViewport(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(),
|
||||
_mirrorViewRect.width(), _mirrorViewRect.height());
|
||||
glScissor(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(),
|
||||
_mirrorViewRect.width(), _mirrorViewRect.height());
|
||||
bool updateViewFrustum = false;
|
||||
updateProjectionMatrix(_mirrorCamera, updateViewFrustum);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// render rear mirror view
|
||||
glPushMatrix();
|
||||
if (eyeRelativeCamera) {
|
||||
// save absolute translations
|
||||
glm::vec3 absoluteSkeletonTranslation = _myAvatar->getSkeletonModel().getTranslation();
|
||||
glm::vec3 absoluteFaceTranslation = _myAvatar->getHead()->getFaceModel().getTranslation();
|
||||
|
||||
// get the eye positions relative to the neck and use them to set the face translation
|
||||
glm::vec3 leftEyePosition, rightEyePosition;
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(glm::vec3());
|
||||
_myAvatar->getHead()->getFaceModel().getEyePositions(leftEyePosition, rightEyePosition);
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation((leftEyePosition + rightEyePosition) * -0.5f);
|
||||
|
||||
// get the neck position relative to the body and use it to set the skeleton translation
|
||||
glm::vec3 neckPosition;
|
||||
_myAvatar->getSkeletonModel().setTranslation(glm::vec3());
|
||||
_myAvatar->getSkeletonModel().getNeckPosition(neckPosition);
|
||||
_myAvatar->getSkeletonModel().setTranslation(_myAvatar->getHead()->getFaceModel().getTranslation() -
|
||||
neckPosition);
|
||||
|
||||
displaySide(_mirrorCamera, true);
|
||||
|
||||
// restore absolute translations
|
||||
_myAvatar->getSkeletonModel().setTranslation(absoluteSkeletonTranslation);
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(absoluteFaceTranslation);
|
||||
} else {
|
||||
displaySide(_mirrorCamera, true);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
_rearMirrorTools->render(false);
|
||||
|
||||
// reset Viewport and projection matrix
|
||||
glViewport(0, 0, _glWidget->width(), _glWidget->height());
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
updateProjectionMatrix(_myCamera, updateViewFrustum);
|
||||
renderRearViewMirror();
|
||||
|
||||
} else if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) {
|
||||
_rearMirrorTools->render(true);
|
||||
}
|
||||
|
@ -2743,6 +2678,14 @@ void Application::setupWorldLight() {
|
|||
glMateriali(GL_FRONT, GL_SHININESS, 96);
|
||||
}
|
||||
|
||||
QImage Application::renderAvatarBillboard() {
|
||||
renderRearViewMirror(true);
|
||||
|
||||
QImage image(_glWidget->width(), _glWidget->height(), QImage::Format_ARGB32);
|
||||
glReadPixels(0, 0, _glWidget->width(), _glWidget->height(), GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
|
||||
return image;
|
||||
}
|
||||
|
||||
void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()");
|
||||
// transform by eye offset
|
||||
|
@ -3660,6 +3603,77 @@ void Application::renderCoverageMapsRecursively(CoverageMap* map) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::renderRearViewMirror(bool billboard) {
|
||||
bool eyeRelativeCamera = false;
|
||||
if (_rearMirrorTools->getZoomLevel() == BODY && !billboard) {
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_BODY_DISTANCE * _myAvatar->getScale());
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getChestPosition());
|
||||
} else { // HEAD zoom level
|
||||
_mirrorCamera.setDistance(MIRROR_REARVIEW_DISTANCE * _myAvatar->getScale());
|
||||
if (_myAvatar->getSkeletonModel().isActive() && _myAvatar->getHead()->getFaceModel().isActive()) {
|
||||
// as a hack until we have a better way of dealing with coordinate precision issues, reposition the
|
||||
// face/body so that the average eye position lies at the origin
|
||||
eyeRelativeCamera = true;
|
||||
_mirrorCamera.setTargetPosition(glm::vec3());
|
||||
|
||||
} else {
|
||||
_mirrorCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
|
||||
}
|
||||
}
|
||||
|
||||
_mirrorCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PIf, 0.0f)));
|
||||
_mirrorCamera.update(1.0f/_fps);
|
||||
|
||||
// set the bounds of rear mirror view
|
||||
glViewport(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(),
|
||||
_mirrorViewRect.width(), _mirrorViewRect.height());
|
||||
glScissor(_mirrorViewRect.x(), _glWidget->height() - _mirrorViewRect.y() - _mirrorViewRect.height(),
|
||||
_mirrorViewRect.width(), _mirrorViewRect.height());
|
||||
bool updateViewFrustum = false;
|
||||
updateProjectionMatrix(_mirrorCamera, updateViewFrustum);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// render rear mirror view
|
||||
glPushMatrix();
|
||||
if (eyeRelativeCamera) {
|
||||
// save absolute translations
|
||||
glm::vec3 absoluteSkeletonTranslation = _myAvatar->getSkeletonModel().getTranslation();
|
||||
glm::vec3 absoluteFaceTranslation = _myAvatar->getHead()->getFaceModel().getTranslation();
|
||||
|
||||
// get the eye positions relative to the neck and use them to set the face translation
|
||||
glm::vec3 leftEyePosition, rightEyePosition;
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(glm::vec3());
|
||||
_myAvatar->getHead()->getFaceModel().getEyePositions(leftEyePosition, rightEyePosition);
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation((leftEyePosition + rightEyePosition) * -0.5f);
|
||||
|
||||
// get the neck position relative to the body and use it to set the skeleton translation
|
||||
glm::vec3 neckPosition;
|
||||
_myAvatar->getSkeletonModel().setTranslation(glm::vec3());
|
||||
_myAvatar->getSkeletonModel().getNeckPosition(neckPosition);
|
||||
_myAvatar->getSkeletonModel().setTranslation(_myAvatar->getHead()->getFaceModel().getTranslation() -
|
||||
neckPosition);
|
||||
|
||||
displaySide(_mirrorCamera, true);
|
||||
|
||||
// restore absolute translations
|
||||
_myAvatar->getSkeletonModel().setTranslation(absoluteSkeletonTranslation);
|
||||
_myAvatar->getHead()->getFaceModel().setTranslation(absoluteFaceTranslation);
|
||||
} else {
|
||||
displaySide(_mirrorCamera, true);
|
||||
}
|
||||
glPopMatrix();
|
||||
|
||||
if (!billboard) {
|
||||
_rearMirrorTools->render(false);
|
||||
}
|
||||
|
||||
// reset Viewport and projection matrix
|
||||
glViewport(0, 0, _glWidget->width(), _glWidget->height());
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
updateProjectionMatrix(_myCamera, updateViewFrustum);
|
||||
}
|
||||
|
||||
// renderViewFrustum()
|
||||
//
|
||||
// Description: this will render the view frustum bounds for EITHER the head
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <QApplication>
|
||||
#include <QAction>
|
||||
#include <QImage>
|
||||
#include <QSettings>
|
||||
#include <QTouchEvent>
|
||||
#include <QList>
|
||||
|
@ -185,6 +186,8 @@ public:
|
|||
|
||||
void setupWorldLight();
|
||||
|
||||
QImage renderAvatarBillboard();
|
||||
|
||||
void displaySide(Camera& whichCamera, bool selfAvatarOnly = false);
|
||||
|
||||
/// Loads a view matrix that incorporates the specified model translation without the precision issues that can
|
||||
|
@ -200,6 +203,8 @@ public:
|
|||
void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
|
||||
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
|
||||
|
||||
|
||||
|
||||
VoxelShader& getVoxelShader() { return _voxelShader; }
|
||||
PointShader& getPointShader() { return _pointShader; }
|
||||
FileLogger* getLogger() { return _logger; }
|
||||
|
@ -328,7 +333,7 @@ private:
|
|||
void displayStats();
|
||||
void checkStatsClick();
|
||||
void toggleStatsExpanded();
|
||||
void renderAvatars(bool forceRenderHead, bool selfAvatarOnly = false);
|
||||
void renderRearViewMirror(bool billboard = false);
|
||||
void renderViewFrustum(ViewFrustum& viewFrustum);
|
||||
|
||||
void checkBandwidthMeterClick();
|
||||
|
|
|
@ -57,7 +57,8 @@ MyAvatar::MyAvatar() :
|
|||
_thrustMultiplier(1.0f),
|
||||
_moveTarget(0,0,0),
|
||||
_moveTargetStepCounter(0),
|
||||
_lookAtTargetAvatar()
|
||||
_lookAtTargetAvatar(),
|
||||
_billboardValid(false)
|
||||
{
|
||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||
_driveKeys[i] = 0.0f;
|
||||
|
@ -332,7 +333,13 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
|
||||
// Zero thrust out now that we've added it to velocity in this frame
|
||||
_thrust = glm::vec3(0, 0, 0);
|
||||
|
||||
|
||||
// consider updating our billboard
|
||||
if (!_billboardValid && _skeletonModel.isLoadedWithTextures() && getHead()->getFaceModel().isLoadedWithTextures()) {
|
||||
QImage image = Application::getInstance()->renderAvatarBillboard();
|
||||
image.save("test.png");
|
||||
_billboardValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
const float MAX_PITCH = 90.0f;
|
||||
|
@ -712,6 +719,16 @@ glm::vec3 MyAvatar::getUprightHeadPosition() const {
|
|||
return _position + getWorldAlignedOrientation() * glm::vec3(0.0f, getPelvisToHeadLength(), 0.0f);
|
||||
}
|
||||
|
||||
void MyAvatar::setFaceModelURL(const QUrl& faceModelURL) {
|
||||
Avatar::setFaceModelURL(faceModelURL);
|
||||
_billboardValid = false;
|
||||
}
|
||||
|
||||
void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||
Avatar::setSkeletonModelURL(skeletonModelURL);
|
||||
_billboardValid = false;
|
||||
}
|
||||
|
||||
void MyAvatar::renderBody(bool forceRenderHead) {
|
||||
// Render the body's voxels and head
|
||||
_skeletonModel.render(1.0f);
|
||||
|
|
|
@ -84,6 +84,9 @@ public:
|
|||
void updateLookAtTargetAvatar(glm::vec3& eyePosition);
|
||||
void clearLookAtTargetAvatar();
|
||||
|
||||
virtual void setFaceModelURL(const QUrl& faceModelURL);
|
||||
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
|
||||
|
||||
public slots:
|
||||
void goHome();
|
||||
void increaseSize();
|
||||
|
@ -119,6 +122,8 @@ private:
|
|||
glm::vec3 _transmitterPickStart;
|
||||
glm::vec3 _transmitterPickEnd;
|
||||
|
||||
bool _billboardValid;
|
||||
|
||||
// private methods
|
||||
void renderBody(bool forceRenderHead);
|
||||
void updateThrust(float deltaTime);
|
||||
|
|
|
@ -46,6 +46,21 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati
|
|||
program.release();
|
||||
}
|
||||
|
||||
bool Model::isLoadedWithTextures() const {
|
||||
if (!isActive()) {
|
||||
return false;
|
||||
}
|
||||
foreach (const NetworkMesh& mesh, _geometry->getMeshes()) {
|
||||
foreach (const NetworkMeshPart& part, mesh.parts) {
|
||||
if (part.diffuseTexture && !part.diffuseTexture->isLoaded() ||
|
||||
part.normalTexture && !part.normalTexture->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Model::init() {
|
||||
if (!_program.isLinked()) {
|
||||
switchToResourcesParentIfRequired();
|
||||
|
|
|
@ -46,6 +46,8 @@ public:
|
|||
|
||||
bool isActive() const { return _geometry && _geometry->isLoaded(); }
|
||||
|
||||
bool isLoadedWithTextures() const;
|
||||
|
||||
void init();
|
||||
void reset();
|
||||
void simulate(float deltaTime);
|
||||
|
|
|
@ -258,9 +258,11 @@ NetworkTexture::NetworkTexture(const QUrl& url, bool normalMap) :
|
|||
_reply(NULL),
|
||||
_attempts(0),
|
||||
_averageColor(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
_translucent(false) {
|
||||
_translucent(false),
|
||||
_loaded(false) {
|
||||
|
||||
if (!url.isValid()) {
|
||||
_loaded = true;
|
||||
return;
|
||||
}
|
||||
_request.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferCache);
|
||||
|
@ -298,6 +300,7 @@ void NetworkTexture::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTo
|
|||
_reply->disconnect(this);
|
||||
_reply->deleteLater();
|
||||
_reply = NULL;
|
||||
_loaded = true;
|
||||
|
||||
QImage image = QImage::fromData(entirety).convertToFormat(QImage::Format_ARGB32);
|
||||
|
||||
|
@ -345,6 +348,8 @@ void NetworkTexture::handleReplyError() {
|
|||
QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(makeRequest()));
|
||||
debug << " -- retrying...";
|
||||
|
||||
} else {
|
||||
_loaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,8 @@ public:
|
|||
NetworkTexture(const QUrl& url, bool normalMap);
|
||||
~NetworkTexture();
|
||||
|
||||
bool isLoaded() const { return _loaded; }
|
||||
|
||||
/// Returns the average color over the entire texture.
|
||||
const glm::vec4& getAverageColor() const { return _averageColor; }
|
||||
|
||||
|
@ -142,6 +144,7 @@ private:
|
|||
int _attempts;
|
||||
glm::vec4 _averageColor;
|
||||
bool _translucent;
|
||||
bool _loaded;
|
||||
};
|
||||
|
||||
/// Caches derived, dilated textures.
|
||||
|
|
Loading…
Reference in a new issue