Merge pull request #1284 from ey6es/shadowplay

First pass at shadow maps of avatars on voxels.
This commit is contained in:
ZappoMan 2013-11-21 15:25:27 -08:00
commit 60f5681a76
17 changed files with 255 additions and 83 deletions

View file

@ -0,0 +1,16 @@
#version 120
//
// shadow_map.frag
// fragment shader
//
// Created by Andrzej Kapolka on 11/21/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
uniform sampler2DShadow shadowMap;
void main(void) {
gl_FragColor = gl_Color * mix(vec4(0.8, 0.8, 0.8, 1.0), vec4(1.0, 1.0, 1.0, 1.0),
shadow2D(shadowMap, gl_TexCoord[0].stp));
}

View file

@ -424,12 +424,15 @@ void Application::paintGL() {
whichCamera = _viewFrustumOffsetCamera;
}
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
updateShadowMap();
}
if (OculusManager::isConnected()) {
displayOculus(whichCamera);
} else {
_glowEffect.prepare();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
@ -1873,7 +1876,7 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) {
return false;
}
void Application::renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera) {
void Application::renderLookatIndicator(glm::vec3 pointOfInterest) {
const float DISTANCE_FROM_HEAD_SPHERE = 0.1f * _lookatIndicatorScale;
const float INDICATOR_RADIUS = 0.1f * _lookatIndicatorScale;
@ -2764,6 +2767,80 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
viewFrustum.calculate();
}
glm::vec3 Application::getSunDirection() {
return glm::normalize(_environment.getClosestData(_myCamera.getPosition()).getSunLocation() - _myCamera.getPosition());
}
void Application::updateShadowMap() {
QOpenGLFramebufferObject* fbo = _textureCache.getShadowFramebufferObject();
fbo->bind();
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, fbo->width(), fbo->height());
glm::vec3 lightDirection = -getSunDirection();
glm::quat rotation = glm::inverse(rotationBetween(IDENTITY_FRONT, lightDirection));
glm::vec3 translation = glm::vec3();
float nearScale = 0.0f;
const float MAX_SHADOW_DISTANCE = 2.0f;
float farScale = (MAX_SHADOW_DISTANCE - _viewFrustum.getNearClip()) / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip());
loadViewFrustum(_myCamera, _viewFrustum);
glm::vec3 points[] = {
rotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale) + translation),
rotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale) + translation),
rotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale) + translation),
rotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale) + translation),
rotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale) + translation),
rotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale) + translation),
rotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale) + translation),
rotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) + translation) };
glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX), maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int i = 0; i < sizeof(points) / sizeof(points[0]); i++) {
minima = glm::min(minima, points[i]);
maxima = glm::max(maxima, points[i]);
}
// stretch out our extents in z so that we get all of the avatars
minima.z -= _viewFrustum.getFarClip() * 0.5f;
maxima.z += _viewFrustum.getFarClip() * 0.5f;
// save the combined matrix for rendering
_shadowMatrix = glm::transpose(glm::translate(0.5f, 0.5f, 0.5f) * glm::scale(0.5f, 0.5f, 0.5f) *
glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) *
glm::mat4_cast(rotation) * glm::translate(translation));
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
// store view matrix without translation, which we'll use for precision-sensitive objects
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);
_viewMatrixTranslation = translation;
glTranslatef(translation.x, translation.y, translation.z);
renderAvatars(true);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
fbo->release();
glViewport(0, 0, _glWidget->width(), _glWidget->height());
}
// this shader is an adaptation (HLSL -> GLSL, removed conditional) of the one in the Oculus sample
// code (Samples/OculusRoomTiny/RenderTiny_D3D1X_Device.cpp), which is under the Apache license
// (http://www.apache.org/licenses/LICENSE-2.0)
@ -2906,15 +2983,14 @@ void Application::displayOculus(Camera& whichCamera) {
const GLfloat WHITE_SPECULAR_COLOR[] = { 1.0f, 1.0f, 1.0f, 1.0f };
const GLfloat NO_SPECULAR_COLOR[] = { 0.0f, 0.0f, 0.0f, 1.0f };
void Application::setupWorldLight(Camera& whichCamera) {
void Application::setupWorldLight() {
// Setup 3D lights (after the camera transform, so that they are positioned in world space)
glEnable(GL_COLOR_MATERIAL);
glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
glm::vec3 relativeSunLoc = glm::normalize(_environment.getClosestData(whichCamera.getPosition()).getSunLocation() -
whichCamera.getPosition());
GLfloat light_position0[] = { relativeSunLoc.x, relativeSunLoc.y, relativeSunLoc.z, 0.0 };
glm::vec3 sunDirection = getSunDirection();
GLfloat light_position0[] = { sunDirection.x, sunDirection.y, sunDirection.z, 0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
GLfloat ambient_color[] = { 0.7, 0.7, 0.8 };
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient_color);
@ -2972,7 +3048,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z);
// Setup 3D lights (after the camera transform, so that they are positioned in world space)
setupWorldLight(whichCamera);
setupWorldLight();
if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
@ -3109,44 +3185,11 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
}
}
_myAvatar.renderScreenTint(SCREEN_TINT_BEFORE_AVATARS, whichCamera);
_myAvatar.renderScreenTint(SCREEN_TINT_BEFORE_AVATARS);
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... Avatars...");
renderAvatars(whichCamera.getMode() == CAMERA_MODE_MIRROR, selfAvatarOnly);
if (!selfAvatarOnly) {
// Render avatars of other nodes
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
node->lock();
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
Avatar *avatar = (Avatar *)node->getLinkedData();
if (!avatar->isInitialized()) {
avatar->init();
}
avatar->render(false, Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls));
avatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
}
node->unlock();
}
}
// Render my own Avatar
_myAvatar.render(whichCamera.getMode() == CAMERA_MODE_MIRROR,
Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls));
_myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
if (Menu::getInstance()->isOptionChecked(MenuOption::LookAtIndicator) && _lookatTargetAvatar) {
renderLookatIndicator(_lookatOtherPosition, whichCamera);
}
}
_myAvatar.renderScreenTint(SCREEN_TINT_AFTER_AVATARS, whichCamera);
_myAvatar.renderScreenTint(SCREEN_TINT_AFTER_AVATARS);
if (!selfAvatarOnly) {
// Render the world box
@ -3768,7 +3811,41 @@ void Application::renderCoverageMapsRecursively(CoverageMap* map) {
}
}
void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) {
if (!Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
return;
}
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::displaySide() ... Avatars...");
if (!selfAvatarOnly) {
// Render avatars of other nodes
NodeList* nodeList = NodeList::getInstance();
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
node->lock();
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
Avatar *avatar = (Avatar *)node->getLinkedData();
if (!avatar->isInitialized()) {
avatar->init();
}
avatar->render(false, Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls));
avatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
}
node->unlock();
}
}
// Render my own Avatar
_myAvatar.render(forceRenderHead, Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls));
_myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors));
if (Menu::getInstance()->isOptionChecked(MenuOption::LookAtIndicator) && _lookatTargetAvatar) {
renderLookatIndicator(_lookatOtherPosition);
}
}
// renderViewFrustum()
//

View file

@ -153,12 +153,14 @@ public:
static void controlledBroadcastToNodes(unsigned char* broadcastData, size_t dataBytes,
const char* nodeTypes, int numNodeTypes);
void setupWorldLight(Camera& whichCamera);
void setupWorldLight();
/// Loads a view matrix that incorporates the specified model translation without the precision issues that can
/// result from matrix multiplication at high translation magnitudes.
void loadTranslatedViewMatrix(const glm::vec3& translation);
const glm::mat4& getShadowMatrix() const { return _shadowMatrix; }
/// Computes the off-axis frustum parameters for the view frustum, taking mirroring into account.
void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& near,
float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
@ -260,17 +262,21 @@ private:
glm::vec3& eyePosition, QUuid &nodeUUID);
bool isLookingAtMyAvatar(Avatar* avatar);
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
void renderLookatIndicator(glm::vec3 pointOfInterest);
void renderFollowIndicator();
void updateAvatar(float deltaTime);
void updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection);
void queryVoxels();
void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
glm::vec3 getSunDirection();
void updateShadowMap();
void displayOculus(Camera& whichCamera);
void displaySide(Camera& whichCamera, bool selfAvatarOnly = false);
void displayOverlay();
void displayStats();
void renderAvatars(bool forceRenderHead, bool selfAvatarOnly = false);
void renderViewFrustum(ViewFrustum& viewFrustum);
void checkBandwidthMeterClick();
@ -352,6 +358,8 @@ private:
glm::mat4 _untranslatedViewMatrix;
glm::vec3 _viewMatrixTranslation;
glm::mat4 _shadowMatrix;
Environment _environment;
int _headMouseX, _headMouseY;

View file

@ -272,6 +272,7 @@ Menu::Menu() :
SLOT(cycleRenderMode()));
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::ParticleCloud, 0, false);
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Shadows, 0, false);
QMenu* voxelOptionsMenu = developerMenu->addMenu("Voxel Options");

View file

@ -229,6 +229,7 @@ namespace MenuOption {
const QString RunTimingTests = "Run Timing Tests";
const QString SendVoxelColors = "Colored Voxels";
const QString SettingsImport = "Import Settings";
const QString Shadows = "Shadows";
const QString SettingsExport = "Export Settings";
const QString ShowAllLocalVoxels = "Show All Local Voxels";
const QString ShowTrueColors = "Show TRUE Colors";

View file

@ -519,6 +519,13 @@ void VoxelSystem::initVoxelMemory() {
_perlinModulateProgram.bind();
_perlinModulateProgram.setUniformValue("permutationNormalTexture", 0);
_perlinModulateProgram.release();
_shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/shadow_map.frag");
_shadowMapProgram.link();
_shadowMapProgram.bind();
_shadowMapProgram.setUniformValue("shadowMap", 0);
_shadowMapProgram.release();
}
}
@ -1080,6 +1087,7 @@ glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float vo
}
ProgramObject VoxelSystem::_perlinModulateProgram;
ProgramObject VoxelSystem::_shadowMapProgram;
void VoxelSystem::init() {
if (_initialized) {
@ -1386,20 +1394,41 @@ void VoxelSystem::render(bool texture) {
}
void VoxelSystem::applyScaleAndBindProgram(bool texture) {
glPushMatrix();
glScalef(_treeScale, _treeScale, _treeScale);
if (texture) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
_shadowMapProgram.bind();
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID());
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);
glEnable(GL_TEXTURE_GEN_R);
glEnable(GL_TEXTURE_2D);
glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]);
glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]);
glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]);
} else if (texture) {
_perlinModulateProgram.bind();
glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID());
}
glPushMatrix();
glScalef(_treeScale, _treeScale, _treeScale);
}
void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
// scale back down to 1 so heads aren't massive
glPopMatrix();
if (texture) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) {
_shadowMapProgram.release();
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
glDisable(GL_TEXTURE_GEN_R);
glDisable(GL_TEXTURE_2D);
} else if (texture) {
_perlinModulateProgram.release();
glBindTexture(GL_TEXTURE_2D, 0);
}

View file

@ -282,6 +282,7 @@ private:
bool _voxelsDirty;
static ProgramObject _perlinModulateProgram;
static ProgramObject _shadowMapProgram;
int _hookID;
std::vector<glBufferIndex> _freeIndexes;

View file

@ -439,7 +439,7 @@ static TextRenderer* textRenderer() {
return renderer;
}
void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) {
void Avatar::render(bool forceRenderHead, bool renderAvatarBalls) {
if (Application::getInstance()->getAvatar()->getHand().isRaveGloveActive()) {
_hand.setRaveLights(RAVE_LIGHTS_AVATAR);
@ -455,7 +455,7 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) {
Glower glower(_moving && glm::length(toTarget) > GLOW_DISTANCE ? 1.0f : 0.0f);
// render body
renderBody(lookingInMirror, renderAvatarBalls);
renderBody(forceRenderHead, renderAvatarBalls);
// render sphere when far away
const float MAX_ANGLE = 10.f;
@ -709,15 +709,15 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
return glm::angleAxis(angle * proportion, axis);
}
float Avatar::getBallRenderAlpha(int ball, bool lookingInMirror) const {
float Avatar::getBallRenderAlpha(int ball, bool forceRenderHead) const {
return 1.0f;
}
void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
void Avatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) {
if (_head.getVideoFace().isFullFrame()) {
// Render the full-frame video
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror);
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, forceRenderHead);
if (alpha > 0.0f) {
_head.getVideoFace().render(1.0f);
}
@ -726,7 +726,7 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
glm::vec3 skinColor, darkSkinColor;
getSkinColors(skinColor, darkSkinColor);
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
float alpha = getBallRenderAlpha(b, lookingInMirror);
float alpha = getBallRenderAlpha(b, forceRenderHead);
// When we have leap hands, hide part of the arms.
if (_hand.getNumPalms() > 0) {
@ -779,7 +779,7 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
}
} else {
// Render the body's voxels and head
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror);
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, forceRenderHead);
if (alpha > 0.0f) {
if (!_skeletonModel.render(alpha)) {
_voxels.render(false);
@ -787,7 +787,7 @@ void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
_head.render(alpha, false);
}
}
_hand.render(lookingInMirror);
_hand.render();
}
void Avatar::getSkinColors(glm::vec3& lighter, glm::vec3& darker) {

View file

@ -141,7 +141,7 @@ public:
void init();
void simulate(float deltaTime, Transmitter* transmitter);
void follow(Avatar* leadingAvatar);
void render(bool lookingInMirror, bool renderAvatarBalls);
void render(bool forceRenderHead, bool renderAvatarBalls);
//setters
void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors); }
@ -255,8 +255,8 @@ private:
// private methods...
glm::vec3 calculateAverageEyePosition() { return _head.calculateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat)
float getBallRenderAlpha(int ball, bool lookingInMirror) const;
void renderBody(bool lookingInMirror, bool renderAvatarBalls);
float getBallRenderAlpha(int ball, bool forceRenderHead) const;
void renderBody(bool forceRenderHead, bool renderAvatarBalls);
void initializeBodyBalls();
void resetBodyBalls();
void updateHandMovementAndTouching(float deltaTime, bool enableHandMovement);

View file

@ -24,7 +24,6 @@ Hand::Hand(Avatar* owningAvatar) :
_raveGloveInitialized(false),
_owningAvatar(owningAvatar),
_renderAlpha(1.0),
_lookingInMirror(false),
_ballColor(0.0, 0.0, 0.4)
{
// initialize all finger particle emitters with an invalid id as default
@ -133,10 +132,9 @@ void Hand::setRaveGloveEffectsMode(QKeyEvent* event) {
};
}
void Hand::render(bool lookingInMirror) {
void Hand::render() {
_renderAlpha = 1.0;
_lookingInMirror = lookingInMirror;
if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayLeapHands)) {
if (!isRaveGloveActive()) {

View file

@ -50,7 +50,7 @@ public:
void init();
void reset();
void simulate(float deltaTime, bool isMine);
void render(bool lookingInMirror);
void render();
void renderRaveGloveStage();
void setRaveLights(RaveLightsSetting setting);
@ -75,7 +75,6 @@ private:
Avatar* _owningAvatar;
float _renderAlpha;
bool _lookingInMirror;
glm::vec3 _ballColor;
std::vector<HandBall> _leapFingerTipBalls;
std::vector<HandBall> _leapFingerRootBalls;

View file

@ -485,7 +485,7 @@ static TextRenderer* textRenderer() {
return renderer;
}
void MyAvatar::render(bool lookingInMirror, bool renderAvatarBalls) {
void MyAvatar::render(bool forceRenderHead, bool renderAvatarBalls) {
if (Application::getInstance()->getAvatar()->getHand().isRaveGloveActive()) {
_hand.setRaveLights(RAVE_LIGHTS_AVATAR);
@ -495,7 +495,7 @@ void MyAvatar::render(bool lookingInMirror, bool renderAvatarBalls) {
renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f), _scale * 0.1f, 0.2f);
// render body
renderBody(lookingInMirror, renderAvatarBalls);
renderBody(forceRenderHead, renderAvatarBalls);
// if this is my avatar, then render my interactions with the other avatar
_avatarTouch.render(Application::getInstance()->getCamera()->getPosition());
@ -550,7 +550,7 @@ void MyAvatar::render(bool lookingInMirror, bool renderAvatarBalls) {
}
}
void MyAvatar::renderScreenTint(ScreenTintLayer layer, Camera& whichCamera) {
void MyAvatar::renderScreenTint(ScreenTintLayer layer) {
if (layer == SCREEN_TINT_BEFORE_AVATARS) {
if (_hand.isRaveGloveActive()) {
@ -560,7 +560,7 @@ void MyAvatar::renderScreenTint(ScreenTintLayer layer, Camera& whichCamera) {
else if (layer == SCREEN_TINT_BEFORE_AVATARS) {
if (_hand.isRaveGloveActive()) {
// Restore the world lighting
Application::getInstance()->setupWorldLight(whichCamera);
Application::getInstance()->setupWorldLight();
}
}
}
@ -623,19 +623,19 @@ glm::vec3 MyAvatar::getEyeLevelPosition() const {
glm::vec3(0.0f, _pelvisToHeadLength + _scale * BODY_BALL_RADIUS_HEAD_BASE * EYE_UP_OFFSET, 0.0f);
}
float MyAvatar::getBallRenderAlpha(int ball, bool lookingInMirror) const {
float MyAvatar::getBallRenderAlpha(int ball, bool forceRenderHead) const {
const float RENDER_OPAQUE_OUTSIDE = _scale * 0.25f; // render opaque if greater than this distance
const float DO_NOT_RENDER_INSIDE = _scale * 0.25f; // do not render if less than this distance
float distanceToCamera = glm::length(Application::getInstance()->getCamera()->getPosition() - _bodyBall[ball].position);
return (lookingInMirror) ? 1.0f : glm::clamp(
return (forceRenderHead) ? 1.0f : glm::clamp(
(distanceToCamera - DO_NOT_RENDER_INSIDE) / (RENDER_OPAQUE_OUTSIDE - DO_NOT_RENDER_INSIDE), 0.f, 1.f);
}
void MyAvatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
void MyAvatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) {
if (_head.getVideoFace().isFullFrame()) {
// Render the full-frame video
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror);
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, forceRenderHead);
if (alpha > 0.0f) {
_head.getVideoFace().render(1.0f);
}
@ -644,7 +644,7 @@ void MyAvatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
glm::vec3 skinColor, darkSkinColor;
getSkinColors(skinColor, darkSkinColor);
for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) {
float alpha = getBallRenderAlpha(b, lookingInMirror);
float alpha = getBallRenderAlpha(b, forceRenderHead);
// When we have leap hands, hide part of the arms.
if (_hand.getNumPalms() > 0) {
@ -710,12 +710,12 @@ void MyAvatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
if (!_skeletonModel.render(1.0f)) {
_voxels.render(false);
}
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror);
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, forceRenderHead);
if (alpha > 0.0f) {
_head.render(alpha, true);
}
}
_hand.render(lookingInMirror);
_hand.render();
}
void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) {

View file

@ -20,8 +20,8 @@ public:
void reset();
void simulate(float deltaTime, Transmitter* transmitter);
void updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHead);
void render(bool lookingInMirror, bool renderAvatarBalls);
void renderScreenTint(ScreenTintLayer layer, Camera& whichCamera);
void render(bool forceRenderHead, bool renderAvatarBalls);
void renderScreenTint(ScreenTintLayer layer);
// setters
void setMousePressed(bool mousePressed) { _mousePressed = mousePressed; }
@ -84,8 +84,8 @@ private:
int _moveTargetStepCounter;
// private methods
float getBallRenderAlpha(int ball, bool lookingInMirror) const;
void renderBody(bool lookingInMirror, bool renderAvatarBalls);
float getBallRenderAlpha(int ball, bool forceRenderHead) const;
void renderBody(bool forceRenderHead, bool renderAvatarBalls);
void updateThrust(float deltaTime, Transmitter * transmitter);
void updateHandMovementAndTouching(float deltaTime, bool enableHandMovement);
void updateAvatarCollisions(float deltaTime);

View file

@ -271,7 +271,7 @@ void LeapManager::nextFrame() {
hand.updateFingerTrails();
// if Leap drive is enabled, drive avatar based on Leap input
if (!Menu::getInstance()->isOptionChecked(MenuOption::LeapDrive)) {
if (!(Menu::getInstance()->isOptionChecked(MenuOption::LeapDrive) && gotRealData)) {
return;
}
glm::vec3 relativePosition;

View file

@ -447,7 +447,7 @@ bool Model::render(float alpha) {
glBindTexture(GL_TEXTURE_2D, 0);
// restore all the default material settings
Application::getInstance()->setupWorldLight(*Application::getInstance()->getCamera());
Application::getInstance()->setupWorldLight();
return true;
}

View file

@ -23,7 +23,8 @@ TextureCache::TextureCache() :
_blueTextureID(0),
_primaryFramebufferObject(NULL),
_secondaryFramebufferObject(NULL),
_tertiaryFramebufferObject(NULL)
_tertiaryFramebufferObject(NULL),
_shadowFramebufferObject(NULL)
{
}
@ -179,6 +180,38 @@ QOpenGLFramebufferObject* TextureCache::getTertiaryFramebufferObject() {
return _tertiaryFramebufferObject;
}
QOpenGLFramebufferObject* TextureCache::getShadowFramebufferObject() {
if (_shadowFramebufferObject == NULL) {
const int SHADOW_MAP_SIZE = 2048;
_shadowFramebufferObject = new QOpenGLFramebufferObject(SHADOW_MAP_SIZE, SHADOW_MAP_SIZE,
QOpenGLFramebufferObject::NoAttachment, GL_TEXTURE_2D, GL_RGB);
glGenTextures(1, &_shadowDepthTextureID);
glBindTexture(GL_TEXTURE_2D, _shadowDepthTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, SHADOW_MAP_SIZE, SHADOW_MAP_SIZE,
0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
const float DISTANT_BORDER[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, DISTANT_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
glBindTexture(GL_TEXTURE_2D, 0);
_shadowFramebufferObject->bind();
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _shadowDepthTextureID, 0);
_shadowFramebufferObject->release();
}
return _shadowFramebufferObject;
}
GLuint TextureCache::getShadowDepthTextureID() {
// ensure that the shadow framebuffer object is initialized before returning the depth texture id
getShadowFramebufferObject();
return _shadowDepthTextureID;
}
bool TextureCache::eventFilter(QObject* watched, QEvent* event) {
if (event->type() == QEvent::Resize) {
QSize size = static_cast<QResizeEvent*>(event)->size();

View file

@ -64,6 +64,12 @@ public:
/// screen effects.
QOpenGLFramebufferObject* getTertiaryFramebufferObject();
/// Returns a pointer to the framebuffer object used to render shadow maps.
QOpenGLFramebufferObject* getShadowFramebufferObject();
/// Returns the ID of the shadow framebuffer object's depth texture.
GLuint getShadowDepthTextureID();
virtual bool eventFilter(QObject* watched, QEvent* event);
private:
@ -83,6 +89,9 @@ private:
QOpenGLFramebufferObject* _primaryFramebufferObject;
QOpenGLFramebufferObject* _secondaryFramebufferObject;
QOpenGLFramebufferObject* _tertiaryFramebufferObject;
QOpenGLFramebufferObject* _shadowFramebufferObject;
GLuint _shadowDepthTextureID;
};
/// A simple object wrapper for an OpenGL texture.