diff --git a/interface/resources/shaders/skin_voxels.vert b/interface/resources/shaders/skin_voxels.vert new file mode 100644 index 0000000000..c63b2e1b31 --- /dev/null +++ b/interface/resources/shaders/skin_voxels.vert @@ -0,0 +1,34 @@ +#version 120 + +// +// skin_voxels.vert +// vertex shader +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +const int MAX_BONES = 32; +const int INDICES_PER_VERTEX = 4; + +uniform mat4 boneMatrices[MAX_BONES]; + +attribute vec4 boneIndices; +attribute vec4 boneWeights; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + vec4 normal = vec4(0.0, 0.0, 0.0, 0.0); + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 boneMatrix = boneMatrices[int(boneIndices[i])]; + float boneWeight = boneWeights[i]; + position += boneMatrix * gl_Vertex * boneWeight; + normal += boneMatrix * vec4(gl_Normal, 0.0) * boneWeight; + } + position = gl_ModelViewProjectionMatrix * position; + normal = normalize(gl_ModelViewMatrix * normal); + + gl_FrontColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient + + gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); + gl_Position = position; +} diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 7198c0030c..6ee8cefb55 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -88,7 +88,8 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false) + _isMouseTurningRight(false), + _voxels(this) { // give the pointer to our head to inherited _headData variable from AvatarData diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 79f3f113b9..dcea2816ec 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -8,13 +8,18 @@ #include #include "AvatarVoxelSystem.h" +#include "renderer/ProgramObject.h" const float AVATAR_TREE_SCALE = 1.0f; const int MAX_VOXELS_PER_AVATAR = 2000; -const int BONE_INDEX_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; -const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; +const int BONE_INDEX_ELEMENTS_PER_VERTEX = 4; +const int BONE_INDEX_ELEMENTS_PER_VOXEL = BONE_INDEX_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; +const int BONE_WEIGHT_ELEMENTS_PER_VERTEX = 4; +const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = BONE_WEIGHT_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; -AvatarVoxelSystem::AvatarVoxelSystem() : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { +AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : + VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), + _avatar(avatar) { } AvatarVoxelSystem::~AvatarVoxelSystem() { @@ -24,6 +29,11 @@ AvatarVoxelSystem::~AvatarVoxelSystem() { delete[] _writeBoneWeightsArray; } +ProgramObject* AvatarVoxelSystem::_skinProgram = 0; +int AvatarVoxelSystem::_boneMatricesLocation; +int AvatarVoxelSystem::_boneIndicesLocation; +int AvatarVoxelSystem::_boneWeightsLocation; + void AvatarVoxelSystem::init() { VoxelSystem::init(); @@ -43,6 +53,18 @@ void AvatarVoxelSystem::init() { glGenBuffers(1, &_vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + + // load our skin program if this is the first avatar system to initialize + if (_skinProgram != 0) { + return; + } + _skinProgram = new ProgramObject(); + _skinProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_voxels.vert"); + _skinProgram->link(); + + _boneMatricesLocation = _skinProgram->uniformLocation("boneMatrices"); + _boneIndicesLocation = _skinProgram->attributeLocation("boneIndices"); + _boneWeightsLocation = _skinProgram->attributeLocation("boneWeights"); } void AvatarVoxelSystem::render(bool texture) { @@ -53,11 +75,15 @@ void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::v float voxelScale, const nodeColor& color) { VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); - for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VOXEL; j++) { - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); - *(writeBoneIndicesAt + j) = 0; - *(writeBoneWeightsAt + j) = 0.0f; + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + for (int i = 0; i < VERTICES_PER_VOXEL; i++) { + GLubyte boneIndices[] = { 0, 0, 0, 0}; + glm::vec4 boneWeights = glm::vec4(1.0f, 0.0f, 0.0f, 0.0f); + for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VERTEX; j++) { + *(writeBoneIndicesAt + i * BONE_INDEX_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; + *(writeBoneWeightsAt + i * BONE_WEIGHT_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; + } } } @@ -95,3 +121,25 @@ void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferInd glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); } +void AvatarVoxelSystem::bindProgram(bool texture) { + _skinProgram->bind(); + + QMatrix4x4 boneMatrices[1]; + + _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, sizeof(boneMatrices) / sizeof(boneMatrices[0])); + + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); + _skinProgram->setAttributeBuffer(_boneIndicesLocation, GL_UNSIGNED_BYTE, 0, BONE_INDEX_ELEMENTS_PER_VERTEX); + _skinProgram->enableAttributeArray(_boneIndicesLocation); + + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); + _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_WEIGHT_ELEMENTS_PER_VERTEX); + _skinProgram->enableAttributeArray(_boneWeightsLocation); +} + +void AvatarVoxelSystem::releaseProgram(bool texture) { + _skinProgram->release(); + _skinProgram->disableAttributeArray(_boneIndicesLocation); + _skinProgram->disableAttributeArray(_boneWeightsLocation); +} + diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index d129e046b9..1b28a1a60d 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -11,10 +11,12 @@ #include "VoxelSystem.h" +class Avatar; + class AvatarVoxelSystem : public VoxelSystem { public: - AvatarVoxelSystem(); + AvatarVoxelSystem(Avatar* avatar); virtual ~AvatarVoxelSystem(); virtual void init(); @@ -26,9 +28,13 @@ protected: float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void bindProgram(bool texture); + virtual void releaseProgram(bool texture); private: + Avatar* _avatar; + GLubyte* _readBoneIndicesArray; GLfloat* _readBoneWeightsArray; GLubyte* _writeBoneIndicesArray; @@ -37,7 +43,10 @@ private: GLuint _vboBoneIndicesID; GLuint _vboBoneWeightsID; - ProgramObject* _skinProgram; + static ProgramObject* _skinProgram; + static int _boneMatricesLocation; + static int _boneIndicesLocation; + static int _boneWeightsLocation; }; #endif /* defined(__interface__AvatarVoxelSystem__) */ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 7f5a926d28..c2d3de8da1 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -625,10 +625,7 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); - if (texture) { - _perlinModulateProgram->bind(); - glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); - } + bindProgram(texture); // for performance, disable blending and enable backface culling glDisable(GL_BLEND); @@ -643,10 +640,7 @@ void VoxelSystem::render(bool texture) { glEnable(GL_BLEND); glDisable(GL_CULL_FACE); - if (texture) { - _perlinModulateProgram->release(); - glBindTexture(GL_TEXTURE_2D, 0); - } + releaseProgram(texture); // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -663,6 +657,20 @@ void VoxelSystem::render(bool texture) { pthread_mutex_unlock(&_bufferWriteLock); } +void VoxelSystem::bindProgram(bool texture) { + if (texture) { + _perlinModulateProgram->bind(); + glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); + } +} + +void VoxelSystem::releaseProgram(bool texture) { + if (texture) { + _perlinModulateProgram->release(); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + int VoxelSystem::_nodeCount = 0; void VoxelSystem::killLocalVoxels() { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index a7824d8326..8c9337bbe5 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -87,6 +87,8 @@ protected: float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); + virtual void bindProgram(bool texture); + virtual void releaseProgram(bool texture); private: // disallow copying of VoxelSystem objects