More work on voxeltars; basic skinning works.

This commit is contained in:
Andrzej Kapolka 2013-06-02 19:55:51 -07:00
parent 35ae08def0
commit 8d757e148f
8 changed files with 168 additions and 73 deletions

View file

@ -172,8 +172,6 @@ Avatar::~Avatar() {
void Avatar::init() { void Avatar::init() {
_voxels.init(); _voxels.init();
_voxels.createVoxel(0.0f, 0.0f, 0.0f, 1.0f, 255, 0, 255);
} }
void Avatar::reset() { void Avatar::reset() {
@ -953,8 +951,11 @@ void Avatar::updateBodyBalls(float deltaTime) {
} }
*/ */
//update position by velocity... // update position by velocity...
_bodyBall[b].position += _bodyBall[b].velocity * deltaTime; _bodyBall[b].position += _bodyBall[b].velocity * deltaTime;
// update rotation
_bodyBall[b].rotation = _skeleton.joint[b].rotation;
} }
} }
@ -1016,14 +1017,7 @@ void Avatar::renderBody(bool lookingInMirror) {
const float RENDER_TRANSLUCENT_BEYOND = 0.5f; const float RENDER_TRANSLUCENT_BEYOND = 0.5f;
// Render the body's voxels // Render the body's voxels
glPushMatrix();
const glm::vec3& voxelPosition = _joint[AVATAR_JOINT_PELVIS].springyPosition;
glTranslatef(voxelPosition.x, voxelPosition.y, voxelPosition.z);
glm::quat rotation = getOrientation();
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
_voxels.render(false); _voxels.render(false);
glPopMatrix();
// Render the body as balls and cones // Render the body as balls and cones
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
@ -1130,6 +1124,11 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity
} }
} }
void Avatar::getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const {
position = _bodyBall[jointID].position;
rotation = _bodyBall[jointID].rotation;
}
void Avatar::writeAvatarDataToFile() { void Avatar::writeAvatarDataToFile() {
Application::getInstance()->setSetting("avatarPos", _position); Application::getInstance()->setSetting("avatarPos", _position);
Application::getInstance()->setSetting("avatarRotation", glm::vec3(_bodyYaw, _bodyPitch, _bodyRoll)); Application::getInstance()->setSetting("avatarRotation", glm::vec3(_bodyYaw, _bodyPitch, _bodyRoll));

View file

@ -66,7 +66,7 @@ public:
void setOrientation (const glm::quat& orientation); void setOrientation (const glm::quat& orientation);
//getters //getters
const Skeleton& getSkeleton () const { return _skeleton;}
float getHeadYawRate () const { return _head.yawRate;} float getHeadYawRate () const { return _head.yawRate;}
float getBodyYaw () const { return _bodyYaw;} float getBodyYaw () const { return _bodyYaw;}
bool getIsNearInteractingOther() const { return _avatarTouch.getAbleToReachOtherAvatar();} bool getIsNearInteractingOther() const { return _avatarTouch.getAbleToReachOtherAvatar();}
@ -97,6 +97,9 @@ public:
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
glm::vec3 getThrust() { return _thrust; }; glm::vec3 getThrust() { return _thrust; };
// Get the position/rotation of a single body ball
void getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const;
//read/write avatar data //read/write avatar data
void writeAvatarDataToFile(); void writeAvatarDataToFile();
void readAvatarDataFromFile(); void readAvatarDataFromFile();
@ -108,7 +111,8 @@ private:
struct AvatarBall struct AvatarBall
{ {
glm::vec3 position; glm::vec3 position;
glm::quat rotation;
glm::vec3 velocity; glm::vec3 velocity;
float jointTightness; float jointTightness;
float radius; float radius;

View file

@ -7,15 +7,15 @@
#include <cstring> #include <cstring>
#include <QtDebug>
#include "Avatar.h"
#include "AvatarVoxelSystem.h" #include "AvatarVoxelSystem.h"
#include "renderer/ProgramObject.h" #include "renderer/ProgramObject.h"
const float AVATAR_TREE_SCALE = 1.0f; const float AVATAR_TREE_SCALE = 1.0f;
const int MAX_VOXELS_PER_AVATAR = 2000; const int MAX_VOXELS_PER_AVATAR = 2000;
const int BONE_INDEX_ELEMENTS_PER_VERTEX = 4; const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL;
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(Avatar* avatar) : AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) :
VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR),
@ -38,21 +38,31 @@ void AvatarVoxelSystem::init() {
VoxelSystem::init(); VoxelSystem::init();
// prep the data structures for incoming voxel data // prep the data structures for incoming voxel data
_writeBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; _writeBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels];
_readBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; _readBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels];
_writeBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; _writeBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels];
_readBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; _readBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels];
// VBO for the boneIndicesArray // VBO for the boneIndicesArray
glGenBuffers(1, &_vboBoneIndicesID); glGenBuffers(1, &_vboBoneIndicesID);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID);
glBufferData(GL_ARRAY_BUFFER, BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
// VBO for the boneWeightsArray // VBO for the boneWeightsArray
glGenBuffers(1, &_vboBoneWeightsID); glGenBuffers(1, &_vboBoneWeightsID);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID);
glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW);
for (int i = 0; i < 150; i++) {
int power = pow(2, randIntInRange(6, 8));
float size = 1.0f / power;
_tree->createVoxel(
randIntInRange(0, power - 1) * size,
randIntInRange(0, power - 1) * size,
randIntInRange(0, power - 1) * size, size, 255, 0, 255, true);
}
setupNewVoxelsForDrawing();
// load our skin program if this is the first avatar system to initialize // load our skin program if this is the first avatar system to initialize
if (_skinProgram != 0) { if (_skinProgram != 0) {
@ -75,14 +85,15 @@ void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::v
float voxelScale, const nodeColor& color) { float voxelScale, const nodeColor& color) {
VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color);
GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL);
GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL);
for (int i = 0; i < VERTICES_PER_VOXEL; i++) { for (int i = 0; i < VERTICES_PER_VOXEL; i++) {
GLubyte boneIndices[] = { 0, 0, 0, 0}; BoneIndices boneIndices;
glm::vec4 boneWeights = glm::vec4(1.0f, 0.0f, 0.0f, 0.0f); glm::vec4 boneWeights;
for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VERTEX; j++) { computeBoneIndicesAndWeights(computeVoxelVertex(startVertex, voxelScale, i), boneIndices, boneWeights);
*(writeBoneIndicesAt + i * BONE_INDEX_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) {
*(writeBoneWeightsAt + i * BONE_WEIGHT_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; *(writeBoneIndicesAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneIndices[j];
*(writeBoneWeightsAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneWeights[j];
} }
} }
} }
@ -91,16 +102,16 @@ void AvatarVoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segment
VoxelSystem::copyWrittenDataSegmentToReadArrays(segmentStart, segmentEnd); VoxelSystem::copyWrittenDataSegmentToReadArrays(segmentStart, segmentEnd);
int segmentLength = (segmentEnd - segmentStart) + 1; int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte);
GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
memcpy(readBoneIndicesAt, writeBoneIndicesAt, segmentSizeBytes); memcpy(readBoneIndicesAt, writeBoneIndicesAt, segmentSizeBytes);
segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat);
segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
memcpy(readBoneWeightsAt, writeBoneWeightsAt, segmentSizeBytes); memcpy(readBoneWeightsAt, writeBoneWeightsAt, segmentSizeBytes);
} }
@ -108,38 +119,94 @@ void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferInd
VoxelSystem::updateVBOSegment(segmentStart, segmentEnd); VoxelSystem::updateVBOSegment(segmentStart, segmentEnd);
int segmentLength = (segmentEnd - segmentStart) + 1; int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte);
GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte);
GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneIndicesFrom); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneIndicesFrom);
segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat);
segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat);
GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom);
} }
void AvatarVoxelSystem::bindProgram(bool texture) { void AvatarVoxelSystem::applyScaleAndBindProgram(bool texture) {
_skinProgram->bind(); _skinProgram->bind();
QMatrix4x4 boneMatrices[1]; // the base matrix includes centering and scale
QMatrix4x4 baseMatrix;
baseMatrix.scale(_treeScale);
baseMatrix.translate(-0.5f, -0.5f, -0.5f);
_skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, sizeof(boneMatrices) / sizeof(boneMatrices[0])); // bone matrices include joint transforms
QMatrix4x4 boneMatrices[NUM_AVATAR_JOINTS];
for (int i = 0; i < NUM_AVATAR_JOINTS; i++) {
glm::vec3 position;
glm::quat orientation;
_avatar->getBodyBallTransform((AvatarJointID)i, position, orientation);
boneMatrices[i].translate(position.x, position.y, position.z);
boneMatrices[i].rotate(QQuaternion(orientation.w, orientation.x, orientation.y, orientation.z));
const glm::vec3& defaultPosition = _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition;
boneMatrices[i].translate(-defaultPosition.x, -defaultPosition.y, -defaultPosition.z);
boneMatrices[i] *= baseMatrix;
}
_skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, NUM_AVATAR_JOINTS);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID);
_skinProgram->setAttributeBuffer(_boneIndicesLocation, GL_UNSIGNED_BYTE, 0, BONE_INDEX_ELEMENTS_PER_VERTEX); glVertexAttribPointer(_boneIndicesLocation, BONE_ELEMENTS_PER_VERTEX, GL_UNSIGNED_BYTE, false, 0, 0);
_skinProgram->enableAttributeArray(_boneIndicesLocation); _skinProgram->enableAttributeArray(_boneIndicesLocation);
glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID);
_skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_WEIGHT_ELEMENTS_PER_VERTEX); _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_ELEMENTS_PER_VERTEX);
_skinProgram->enableAttributeArray(_boneWeightsLocation); _skinProgram->enableAttributeArray(_boneWeightsLocation);
} }
void AvatarVoxelSystem::releaseProgram(bool texture) { void AvatarVoxelSystem::removeScaleAndReleaseProgram(bool texture) {
_skinProgram->release(); _skinProgram->release();
_skinProgram->disableAttributeArray(_boneIndicesLocation); _skinProgram->disableAttributeArray(_boneIndicesLocation);
_skinProgram->disableAttributeArray(_boneWeightsLocation); _skinProgram->disableAttributeArray(_boneWeightsLocation);
} }
class IndexDistance {
public:
IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { }
GLubyte index;
float distance;
};
void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const {
// transform into joint space
glm::vec3 jointVertex = (vertex - glm::vec3(0.5f, 0.5f, 0.5f)) * AVATAR_TREE_SCALE;
// find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up)
IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX];
for (int i = 0; i < NUM_AVATAR_JOINTS; i++) {
float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition);
for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) {
if (distance < nearest[j].distance) {
// move the rest of the indices down
for (int k = BONE_ELEMENTS_PER_VERTEX - 1; k > j; k--) {
nearest[k] = nearest[k - 1];
}
nearest[j] = IndexDistance(i, distance);
break;
}
}
}
// compute the weights based on inverse distance
float totalWeight = 0.0f;
for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) {
indices[i] = nearest[i].index;
weights[i] = (i == 0) ? 1.0f : 0.0f; // 1.0f / glm::max(nearest[i].distance, EPSILON);
totalWeight += weights[i];
}
// normalize the weights
for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) {
weights[i] /= totalWeight;
}
}

View file

@ -11,6 +11,9 @@
#include "VoxelSystem.h" #include "VoxelSystem.h"
const int BONE_ELEMENTS_PER_VERTEX = 4;
typedef GLubyte BoneIndices[BONE_ELEMENTS_PER_VERTEX];
class Avatar; class Avatar;
class AvatarVoxelSystem : public VoxelSystem { class AvatarVoxelSystem : public VoxelSystem {
@ -28,11 +31,13 @@ protected:
float voxelScale, const nodeColor& color); float voxelScale, const nodeColor& color);
virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd);
virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd);
virtual void bindProgram(bool texture); virtual void applyScaleAndBindProgram(bool texture);
virtual void releaseProgram(bool texture); virtual void removeScaleAndReleaseProgram(bool texture);
private: private:
void computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const;
Avatar* _avatar; Avatar* _avatar;
GLubyte* _readBoneIndicesArray; GLubyte* _readBoneIndicesArray;

View file

@ -18,7 +18,7 @@ void Skeleton::initialize() {
joint[b].parent = AVATAR_JOINT_NULL; joint[b].parent = AVATAR_JOINT_NULL;
joint[b].position = glm::vec3(0.0, 0.0, 0.0); joint[b].position = glm::vec3(0.0, 0.0, 0.0);
joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0); joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0);
joint[b].rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f); joint[b].rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
joint[b].length = 0.0; joint[b].length = 0.0;
} }
@ -77,9 +77,18 @@ void Skeleton::initialize() {
joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( -0.01, -0.22, 0.08 ); joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( -0.01, -0.22, 0.08 );
joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 );
// calculate bone length // calculate bone length, absolute positions
for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { for (int b = 0; b < NUM_AVATAR_JOINTS; b++) {
joint[b].length = glm::length(joint[b].defaultPosePosition); joint[b].length = glm::length(joint[b].defaultPosePosition);
if (joint[b].parent == AVATAR_JOINT_NULL) {
joint[b].absoluteDefaultPosePosition = glm::vec3(0.0f, 0.0f, 0.0f);
} else {
joint[b].absoluteDefaultPosePosition = joint[ joint[b].parent ].absoluteDefaultPosePosition;
}
glm::vec3 rotatedJointVector = joint[b].defaultPosePosition;
joint[b].absoluteDefaultPosePosition += rotatedJointVector;
} }
} }

View file

@ -58,11 +58,12 @@ public:
struct AvatarJoint struct AvatarJoint
{ {
AvatarJointID parent; // which joint is this joint connected to? AvatarJointID parent; // which joint is this joint connected to?
glm::vec3 position; // the position at the "end" of the joint - in global space glm::vec3 position; // the position at the "end" of the joint - in global space
glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose"
glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion glm::vec3 absoluteDefaultPosePosition; // the absolute position when the avatar is in the "T-pose"
float length; // the length of vector connecting the joint and its parent glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion
float length; // the length of vector connecting the joint and its parent
}; };
AvatarJoint joint[ NUM_AVATAR_JOINTS ]; AvatarJoint joint[ NUM_AVATAR_JOINTS ];

View file

@ -415,6 +415,11 @@ void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& s
} }
} }
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;
}
ProgramObject* VoxelSystem::_perlinModulateProgram = 0; ProgramObject* VoxelSystem::_perlinModulateProgram = 0;
GLuint VoxelSystem::_permutationNormalTextureID = 0; GLuint VoxelSystem::_permutationNormalTextureID = 0;
@ -609,8 +614,8 @@ void VoxelSystem::render(bool texture) {
// get the lock so that the update thread won't change anything // get the lock so that the update thread won't change anything
pthread_mutex_lock(&_bufferWriteLock); pthread_mutex_lock(&_bufferWriteLock);
glPushMatrix();
updateVBOs(); updateVBOs();
// tell OpenGL where to find vertex and color information // tell OpenGL where to find vertex and color information
glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_NORMAL_ARRAY);
@ -625,7 +630,7 @@ void VoxelSystem::render(bool texture) {
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
bindProgram(texture); applyScaleAndBindProgram(texture);
// for performance, disable blending and enable backface culling // for performance, disable blending and enable backface culling
glDisable(GL_BLEND); glDisable(GL_BLEND);
@ -633,14 +638,13 @@ void VoxelSystem::render(bool texture) {
// draw the number of voxels we have // draw the number of voxels we have
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID);
glScalef(_treeScale, _treeScale, _treeScale);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
releaseProgram(texture); removeScaleAndReleaseProgram(texture);
// deactivate vertex and color arrays after drawing // deactivate vertex and color arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
@ -650,21 +654,24 @@ void VoxelSystem::render(bool texture) {
// bind with 0 to switch back to normal operation // bind with 0 to switch back to normal operation
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// scale back down to 1 so heads aren't massive
glPopMatrix();
pthread_mutex_unlock(&_bufferWriteLock); pthread_mutex_unlock(&_bufferWriteLock);
} }
void VoxelSystem::bindProgram(bool texture) { void VoxelSystem::applyScaleAndBindProgram(bool texture) {
glPushMatrix();
glScalef(_treeScale, _treeScale, _treeScale);
if (texture) { if (texture) {
_perlinModulateProgram->bind(); _perlinModulateProgram->bind();
glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID);
} }
} }
void VoxelSystem::releaseProgram(bool texture) { void VoxelSystem::removeScaleAndReleaseProgram(bool texture) {
// scale back down to 1 so heads aren't massive
glPopMatrix();
if (texture) { if (texture) {
_perlinModulateProgram->release(); _perlinModulateProgram->release();
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);

View file

@ -81,14 +81,20 @@ public:
protected: protected:
int _maxVoxels; float _treeScale;
int _maxVoxels;
VoxelTree* _tree;
glm::vec3 computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const;
void setupNewVoxelsForDrawing();
virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex,
float voxelScale, const nodeColor& color); float voxelScale, const nodeColor& color);
virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd);
virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd);
virtual void bindProgram(bool texture); virtual void applyScaleAndBindProgram(bool texture);
virtual void releaseProgram(bool texture); virtual void removeScaleAndReleaseProgram(bool texture);
private: private:
// disallow copying of VoxelSystem objects // disallow copying of VoxelSystem objects
@ -123,8 +129,6 @@ private:
static float _maxDistance; static float _maxDistance;
static float _minDistance; static float _minDistance;
float _treeScale;
VoxelTree* _tree;
GLfloat* _readVerticesArray; GLfloat* _readVerticesArray;
GLubyte* _readColorsArray; GLubyte* _readColorsArray;
GLfloat* _writeVerticesArray; GLfloat* _writeVerticesArray;
@ -157,7 +161,6 @@ private:
int newTreeToArrays(VoxelNode *currentNode); int newTreeToArrays(VoxelNode *currentNode);
void cleanupRemovedVoxels(); void cleanupRemovedVoxels();
void setupNewVoxelsForDrawing();
void copyWrittenDataToReadArrays(bool fullVBOs); void copyWrittenDataToReadArrays(bool fullVBOs);
void updateFullVBOs(); // all voxels in the VBO void updateFullVBOs(); // all voxels in the VBO