mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 12:08:54 +02:00
More work on voxeltars; basic skinning works.
This commit is contained in:
parent
35ae08def0
commit
8d757e148f
8 changed files with 168 additions and 73 deletions
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 ];
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue