From 94e81da5575aa2aa9a3b3cb48053426404f8e5b7 Mon Sep 17 00:00:00 2001 From: TonyPeng Date: Tue, 8 Jul 2014 09:44:28 -0700 Subject: [PATCH] Added local lights to avatar. Added haze to voxel. --- interface/resources/shaders/model.frag | 19 ++- interface/resources/shaders/model.vert | 9 ++ .../resources/shaders/model_normal_map.frag | 7 +- interface/resources/shaders/skin_model.vert | 11 ++ interface/src/avatar/Avatar.cpp | 35 +++++- interface/src/avatar/Avatar.h | 14 ++- interface/src/renderer/Model.cpp | 1 + interface/src/voxels/VoxelSystem.cpp | 118 +++++++++++++++++- interface/src/voxels/VoxelSystem.h | 14 ++- 9 files changed, 218 insertions(+), 10 deletions(-) diff --git a/interface/resources/shaders/model.frag b/interface/resources/shaders/model.frag index 488736abf9..86bc10179c 100644 --- a/interface/resources/shaders/model.frag +++ b/interface/resources/shaders/model.frag @@ -11,6 +11,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +const int MAX_LOCAL_LIGHTS = 4; + // the diffuse texture uniform sampler2D diffuseMap; @@ -20,13 +22,27 @@ varying vec4 position; // the interpolated normal varying vec4 normal; +// static local light position +varying vec4 localLightPos[MAX_LOCAL_LIGHTS]; + void main(void) { // compute the base color based on OpenGL lighting model vec4 normalizedNormal = normalize(normal); float diffuse = dot(normalizedNormal, gl_LightSource[0].position); float facingLight = step(0.0, diffuse); + + // the local light that is always present + vec4 totalLocalLight = vec4(0.0, 0.0, 0.0, 1.0); + for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) { + float localDiffuse = dot(normalizedNormal, localLightPos[i]); + float localLight = step(0.0, localDiffuse); + float localLightVal = localDiffuse * localLight; + + totalLocalLight += (localLightVal * gl_LightSource[i+1].diffuse); + } + vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + - gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight) + totalLocalLight); // compute the specular component (sans exponent) float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(position.xyz, 0.0))), @@ -35,4 +51,5 @@ void main(void) { // modulate texture by base color and add specular contribution gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st) + vec4(pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 0.0); + } diff --git a/interface/resources/shaders/model.vert b/interface/resources/shaders/model.vert index da7e9640d9..06ad8a3300 100644 --- a/interface/resources/shaders/model.vert +++ b/interface/resources/shaders/model.vert @@ -11,12 +11,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +const int MAX_LOCAL_LIGHTS = 4; + // the interpolated position varying vec4 position; // the interpolated normal varying vec4 normal; +// local light position that is always present +varying vec4 localLightPos[MAX_LOCAL_LIGHTS]; + void main(void) { // transform and store the normal for interpolation @@ -36,4 +41,8 @@ void main(void) { // use standard pipeline transform gl_Position = ftransform(); + + for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) { + localLightPos[i] = gl_ModelViewMatrixInverse * gl_LightSource[i+1].position; + } } diff --git a/interface/resources/shaders/model_normal_map.frag b/interface/resources/shaders/model_normal_map.frag index 8444f2d6ea..ca0201f6ab 100644 --- a/interface/resources/shaders/model_normal_map.frag +++ b/interface/resources/shaders/model_normal_map.frag @@ -37,9 +37,14 @@ void main(void) { normalizedBitangent * localNormal.y + normalizedNormal * localNormal.z, 0.0); float diffuse = dot(viewNormal, gl_LightSource[0].position); float facingLight = step(0.0, diffuse); + float localDiffuse = dot(viewNormal, gl_LightSource[1].position); + float localLight = step(0.0, localDiffuse); vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + - gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); + gl_FrontLightProduct[0].diffuse * (diffuse * facingLight) + gl_FrontLightProduct[1].diffuse * (localDiffuse * localLight)); + + + // compute the specular component (sans exponent) float specular = facingLight * max(0.0, dot(normalize(gl_LightSource[0].position - normalize(vec4(vec3(interpolatedPosition), 0.0))), viewNormal)); diff --git a/interface/resources/shaders/skin_model.vert b/interface/resources/shaders/skin_model.vert index d68347d33d..44f33da3e2 100644 --- a/interface/resources/shaders/skin_model.vert +++ b/interface/resources/shaders/skin_model.vert @@ -13,6 +13,7 @@ const int MAX_CLUSTERS = 128; const int INDICES_PER_VERTEX = 4; +const int MAX_LOCAL_LIGHTS = 4; uniform mat4 clusterMatrices[MAX_CLUSTERS]; @@ -25,6 +26,9 @@ varying vec4 position; // the interpolated normal varying vec4 normal; +// static local light position (inverse from eye space) +varying vec4 localLightPos[MAX_LOCAL_LIGHTS]; + void main(void) { position = vec4(0.0, 0.0, 0.0, 0.0); normal = vec4(0.0, 0.0, 0.0, 0.0); @@ -34,6 +38,7 @@ void main(void) { position += clusterMatrix * gl_Vertex * clusterWeight; normal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight; } + position = gl_ModelViewMatrix * position; normal = normalize(gl_ModelViewMatrix * normal); @@ -47,4 +52,10 @@ void main(void) { gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0); gl_Position = gl_ProjectionMatrix * position; + + // inverse view to make the light source position static + for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) { + localLightPos[i] = gl_ModelViewMatrixInverse * gl_LightSource[i+1].position; + } + } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9b136980f4..38dbb02a14 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,16 @@ void Avatar::init() { _initialized = true; _shouldRenderBillboard = (getLODDistance() >= BILLBOARD_LOD_DISTANCE); initializeHair(); + + for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) { + _localLightColors[i] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f); + _localLightDirections[i] = glm::vec3(0.0f, 0.0f, 1.0f); + } + + // initialize first light + _localLightColors[0].r = 0.2f; _localLightColors[0].g = 0.2f, _localLightColors[0].b = 0.2f; + _localLightDirections[0].x = 1.0f; _localLightDirections[0].y = 0.0f; _localLightDirections[0].z = 0.0f; + } glm::vec3 Avatar::getChestPosition() const { @@ -219,7 +230,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { const float GLOW_DISTANCE = 20.0f; const float GLOW_MAX_LOUDNESS = 2500.0f; const float MAX_GLOW = 0.5f; - + float GLOW_FROM_AVERAGE_LOUDNESS = ((this == Application::getInstance()->getAvatar()) ? 0.0f : MAX_GLOW * getHeadData()->getAudioLoudness() / GLOW_MAX_LOUDNESS); @@ -230,7 +241,17 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { float glowLevel = _moving && distanceToTarget > GLOW_DISTANCE && renderMode == NORMAL_RENDER_MODE ? 1.0f : GLOW_FROM_AVERAGE_LOUDNESS; - + + + for (int i = 0; i < MAX_LOCAL_LIGHTS; i++) { + glm::vec3 normalized = glm::normalize(_localLightDirections[i]); + glm::vec4 localLight = glm::vec4(normalized, 1.0f); + + // local light parameters + glLightfv(GL_LIGHT1 + i, GL_POSITION, glm::value_ptr(localLight)); + glLightfv(GL_LIGHT1 + i, GL_DIFFUSE, glm::value_ptr(_localLightColors[i])); + } + // render body if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) { renderBody(renderMode, glowLevel); @@ -1107,3 +1128,13 @@ void Avatar::setShowDisplayName(bool showDisplayName) { } +void Avatar::setLocalLightDirection(const glm::vec3& direction, int lightIndex) { + _localLightDirections[lightIndex] = direction; + qDebug( "set light %d direction ( %f, %f, %f )\n", lightIndex, direction.x, direction.y, direction.z ); +} + +void Avatar::setLocalLightColor(const glm::vec4& color, int lightIndex) { + _localLightColors[lightIndex] = color; + qDebug( "set light %d color ( %f, %f, %f )\n", lightIndex, color.x, color.y, color.z ); +} + diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index f20db1019d..059264d43a 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -36,6 +36,8 @@ const int HAIR_STRANDS = 150; // Number of strands of hair const int HAIR_LINKS = 10; // Number of links in a hair strand const int HAIR_MAX_CONSTRAINTS = 2; // Hair verlet is connected to at most how many others +const int MAX_LOCAL_LIGHTS = 6; + enum DriveKeys { FWD = 0, BACK, @@ -154,7 +156,9 @@ public: public slots: void updateCollisionGroups(); - + void setLocalLightDirection(const glm::vec3& direction, int lightIndex); + void setLocalLightColor(const glm::vec4& color, int lightIndex); + signals: void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision); @@ -174,9 +178,13 @@ protected: glm::vec3 _mouseRayDirection; float _stringLength; bool _moving; ///< set when position is changing - + quint32 _collisionGroups; - + + // always-present local lighting for the avatar + glm::vec3 _localLightDirections[MAX_LOCAL_LIGHTS]; + glm::vec4 _localLightColors[MAX_LOCAL_LIGHTS]; + // protected methods... glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 723297f6b4..6fe57ea705 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1488,6 +1488,7 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re if (cascadedShadows) { program->setUniform(skinLocations->shadowDistances, Application::getInstance()->getShadowDistances()); } + } else { glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); program->bind(); diff --git a/interface/src/voxels/VoxelSystem.cpp b/interface/src/voxels/VoxelSystem.cpp index ca79967109..109d561306 100644 --- a/interface/src/voxels/VoxelSystem.cpp +++ b/interface/src/voxels/VoxelSystem.cpp @@ -21,6 +21,8 @@ #include #include +#include + #include "Application.h" #include "InterfaceConfig.h" #include "Menu.h" @@ -67,7 +69,13 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels, VoxelTree* tree) _inOcclusions(false), _showCulledSharedFaces(false), _usePrimitiveRenderer(false), - _renderer(0) + _renderer(0), + _drawHaze(true), + _updateHaze(false), + _farHazeDistance(300.0f), + _hazeColor(0.24f, 0.27f, 0.34f), + _lastHazeCameraPosition(0.0f, 0.0f, 0.0f), + _lastYawAngle(0.0f) { _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; @@ -108,6 +116,9 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels, VoxelTree* tree) _lastKnownVoxelSizeScale = DEFAULT_OCTREE_SIZE_SCALE; _lastKnownBoundaryLevelAdjust = 0; + + _voxelColors = NULL; + _voxelPositions = NULL; } void VoxelSystem::elementDeleted(OctreeElement* element) { @@ -373,6 +384,9 @@ void VoxelSystem::cleanupVoxelMemory() { delete[] _readVoxelDirtyArray; _writeVoxelDirtyArray = _readVoxelDirtyArray = NULL; _readArraysLock.unlock(); + + delete[] _voxelColors; + delete[] _voxelPositions; } } @@ -521,11 +535,17 @@ void VoxelSystem::initVoxelMemory() { _shadowDistancesLocation = _cascadedShadowMapProgram.uniformLocation("shadowDistances"); _cascadedShadowMapProgram.release(); } + } _renderer = new PrimitiveRenderer(_maxVoxels); _initialized = true; + _voxelColors = new xColor[_maxVoxels]; + memset(_voxelColors, 0, sizeof(xColor) *_maxVoxels); + + _voxelPositions = new glm::vec3[_maxVoxels]; + _writeArraysLock.unlock(); _readArraysLock.unlock(); } @@ -1114,6 +1134,7 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo node->setBufferIndex(nodeIndex); node->setVoxelSystem(this); } + // populate the array with points for the 8 vertices and RGB color for each added vertex updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); } @@ -1132,10 +1153,24 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo void VoxelSystem::updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex, float voxelScale, const nodeColor& color) { +// if (nodeIndex < 0 || nodeIndex > 1000) { +// return; +// } + if (_initialized && nodeIndex <= _maxVoxels) { _writeVoxelDirtyArray[nodeIndex] = true; - + + // cache the colors and position + _voxelColors[nodeIndex].red = color[0]; + _voxelColors[nodeIndex].green = color[1]; + _voxelColors[nodeIndex].blue = color[2]; + + // scaled voxel position + _voxelPositions[nodeIndex] = startVertex * (float)TREE_SCALE; + if (_useVoxelShader) { + // write in position, scale, and color for the voxel + if (_writeVoxelShaderData) { VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex]; writeVerticesAt->x = startVertex.x * TREE_SCALE; @@ -1157,9 +1192,85 @@ void VoxelSystem::updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& } } } + + // want new color for haze + if (_drawHaze) { + _updateHaze = true; + } } } +void VoxelSystem::updateHazeColors() { + + // only update when player moves + if (_lastHazeCameraPosition != Application::getInstance()->getAvatar()->getPosition()) { + _updateHaze = true; + _lastHazeCameraPosition = Application::getInstance()->getAvatar()->getPosition(); + } + + // update when yaw angle changes + float avatarYaw = Application::getInstance()->getAvatar()->getBodyYaw(); + if (_lastYawAngle != avatarYaw) { + _updateHaze = true; + _lastYawAngle = avatarYaw; + } + + if (!_updateHaze) { + return; + } + + glm::vec3 cameraPosition = Application::getInstance()->getAvatar()->getPosition(); + float* hazeColor = glm::value_ptr(_hazeColor); + GLubyte* writeColorsAt = _writeColorsArray; + + // update voxel color + int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; + for (int i = 0; i < _voxelsInWriteArrays; i++) { + + float distanceToCamera = glm::length(_voxelPositions[i] - cameraPosition); + if(distanceToCamera > _farHazeDistance) { + distanceToCamera = _farHazeDistance; + } + + // how much haze there is at the distance + float hazeStrength = 1.0f - distanceToCamera / _farHazeDistance; + + // [0, 1] clamp + if (hazeStrength > 1.0f) { + hazeStrength = 1.0f; + } + else if (hazeStrength < 0.0f) { + hazeStrength = 0.0f; + } + + // color [0.0, 1.0] + float floatColor[] = {(float)_voxelColors[i].red / 255.0f, (float)_voxelColors[i].green / 255.0f, (float)_voxelColors[i].blue / 255.0f }; + assert(i >= 0 && i < _maxVoxels); + + // color * haze_strength + haze_color * (1.0 - haze_strength) + float oneMinusHazeStrength = 1.0f - hazeStrength; + nodeColor colorWithHaze = { + (unsigned char)((floatColor[0] * hazeStrength + hazeColor[0] * oneMinusHazeStrength) * 255.0f), + (unsigned char)((floatColor[1] * hazeStrength + hazeColor[1] * oneMinusHazeStrength) * 255.0f), + (unsigned char)((floatColor[2] * hazeStrength + hazeColor[2] * oneMinusHazeStrength) * 255.0f), + }; + + for (int j = 0; j < vertexPointsPerVoxel/3; j++ ) { + *(writeColorsAt + j*3) = colorWithHaze[0]; + *(writeColorsAt + j*3+1) = colorWithHaze[1]; + *(writeColorsAt + j*3+2) = colorWithHaze[2]; + } + + writeColorsAt += vertexPointsPerVoxel; + } + + copyWrittenDataToReadArraysFullVBOs(); + _voxelsDirty = true; + _readRenderFullVBO = true; + _updateHaze = false; + +} + glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const { const float* identityVertex = identityVertices + index * 3; return startVertex + glm::vec3(identityVertex[0], identityVertex[1], identityVertex[2]) * voxelScale; @@ -1340,6 +1451,9 @@ void VoxelSystem::render() { return; } + if (!_useVoxelShader && _drawHaze) { + updateHazeColors(); + } updateVBOs(); // if not don't... then do... diff --git a/interface/src/voxels/VoxelSystem.h b/interface/src/voxels/VoxelSystem.h index ae8752605a..08f44a4d92 100644 --- a/interface/src/voxels/VoxelSystem.h +++ b/interface/src/voxels/VoxelSystem.h @@ -273,7 +273,19 @@ private: static unsigned short _sSwizzledOcclusionBits[64]; ///< Swizzle value of bit pairs of the value of index static unsigned char _sOctantIndexToBitMask[8]; ///< Map octant index to partition mask static unsigned char _sOctantIndexToSharedBitMask[8][8]; ///< Map octant indices to shared partition mask - + + // haze + xColor* _voxelColors; ///< Cached Voxel Colors + glm::vec3* _voxelPositions; ///< Cached Voxel Positions + bool _drawHaze; + bool _updateHaze; + float _farHazeDistance; + glm::vec3 _hazeColor; + glm::vec3 _lastHazeCameraPosition; + float _lastYawAngle; + + + void updateHazeColors(); }; #endif // hifi_VoxelSystem_h