From 124966d2e40a71e5e18fa120a8a9250f94ecb30a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 14 Oct 2013 18:39:19 -0700 Subject: [PATCH] More progress on skinning. --- .../resources/shaders/skin_blendface.vert | 39 +++++++++ interface/src/avatar/BlendFace.cpp | 82 ++++++++++++------- interface/src/avatar/BlendFace.h | 6 +- interface/src/avatar/Head.h | 1 + 4 files changed, 98 insertions(+), 30 deletions(-) create mode 100644 interface/resources/shaders/skin_blendface.vert diff --git a/interface/resources/shaders/skin_blendface.vert b/interface/resources/shaders/skin_blendface.vert new file mode 100644 index 0000000000..d3d833d6fe --- /dev/null +++ b/interface/resources/shaders/skin_blendface.vert @@ -0,0 +1,39 @@ +#version 120 + +// +// skin_blendface.vert +// vertex shader +// +// Created by Andrzej Kapolka on 10/14/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +const int MAX_CLUSTERS = 32; +const int INDICES_PER_VERTEX = 4; + +uniform mat4 clusterMatrices[MAX_CLUSTERS]; + +attribute vec4 clusterIndices; +attribute vec4 clusterWeights; + +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 clusterMatrix = clusterMatrices[int(clusterIndices[i])]; + float clusterWeight = clusterWeights[i]; + position += clusterMatrix * gl_Vertex * clusterWeight; + normal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight; + } + position = gl_ModelViewProjectionMatrix * position; + normal = normalize(gl_ModelViewMatrix * normal); + + // standard diffuse lighting + gl_FrontColor = (gl_LightModel.ambient + gl_LightSource[0].ambient + + gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); + + // pass along the texture coordinate + gl_TexCoord[0] = gl_MultiTexCoord0; + + gl_Position = position; +} diff --git a/interface/src/avatar/BlendFace.cpp b/interface/src/avatar/BlendFace.cpp index 1380703fe6..b438769f5e 100644 --- a/interface/src/avatar/BlendFace.cpp +++ b/interface/src/avatar/BlendFace.cpp @@ -29,6 +29,10 @@ BlendFace::~BlendFace() { } ProgramObject BlendFace::_eyeProgram; +ProgramObject BlendFace::_skinProgram; +int BlendFace::_clusterMatricesLocation; +int BlendFace::_clusterIndicesLocation; +int BlendFace::_clusterWeightsLocation; void BlendFace::init() { if (!_eyeProgram.isLinked()) { @@ -40,6 +44,15 @@ void BlendFace::init() { _eyeProgram.bind(); _eyeProgram.setUniformValue("texture", 0); _eyeProgram.release(); + + _skinProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_blendface.vert"); + _skinProgram.link(); + + _skinProgram.bind(); + _clusterMatricesLocation = _skinProgram.uniformLocation("clusterMatrices"); + _clusterIndicesLocation = _skinProgram.attributeLocation("clusterIndices"); + _clusterWeightsLocation = _skinProgram.attributeLocation("clusterWeights"); + _skinProgram.release(); } } @@ -66,7 +79,7 @@ void BlendFace::simulate(float deltaTime) { } foreach (const FBXMesh& mesh, geometry.meshes) { MeshState state; - state.jointMatrices.resize(mesh.clusters.size()); + state.clusterMatrices.resize(mesh.clusters.size()); if (mesh.springiness > 0.0f) { state.worldSpaceVertices.resize(mesh.vertices.size()); state.vertexVelocities.resize(mesh.vertices.size()); @@ -98,13 +111,14 @@ void BlendFace::simulate(float deltaTime) { glm::mat4_cast(state.rotation) * joint.postRotation; } else { - state.transform = _jointStates[joint.parentIndex].transform * joint.preRotation; + state.transform = _jointStates[joint.parentIndex].transform * joint.preRotation * + glm::mat4_cast(state.rotation) * joint.postRotation; if (i == geometry.leftEyeJointIndex || i == geometry.rightEyeJointIndex) { - // extract the translation component of the matrix - state.rotation = _owningHead->getEyeRotation(glm::vec3( - state.transform[3][0], state.transform[3][1], state.transform[3][2])); + // get the lookat position relative to the eye matrix + glm::vec3 lookat = glm::vec3(glm::inverse(state.transform) * + glm::vec4(_owningHead->getLookAtPosition() + _owningHead->getSaccade(), 1.0f)); + state.transform = state.transform * glm::mat4_cast(rotationBetween(glm::vec3(0.0f, 0.0f, 1.0f), lookat)); } - state.transform = state.transform * glm::mat4_cast(state.rotation) * joint.postRotation; } } @@ -113,7 +127,7 @@ void BlendFace::simulate(float deltaTime) { const FBXMesh& mesh = geometry.meshes.at(i); for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - state.jointMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix; + state.clusterMatrices[j] = _jointStates[cluster.jointIndex].transform * cluster.inverseBindMatrix; } int vertexCount = state.worldSpaceVertices.size(); if (vertexCount == 0) { @@ -141,7 +155,6 @@ void BlendFace::simulate(float deltaTime) { _blendedVertices[*index] += *vertex * coefficient; } } - sourceVertices = _blendedVertices.constData(); } glm::mat4 transform; @@ -153,20 +166,19 @@ void BlendFace::simulate(float deltaTime) { const glm::vec4* clusterWeights = mesh.clusterWeights.constData(); for (int j = 0; j < vertexCount; j++) { _blendedVertices[j] = - glm::vec3(state.jointMatrices[clusterIndices[j][0]] * + glm::vec3(state.clusterMatrices[clusterIndices[j][0]] * glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][0] + - glm::vec3(state.jointMatrices[clusterIndices[j][1]] * + glm::vec3(state.clusterMatrices[clusterIndices[j][1]] * glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][1] + - glm::vec3(state.jointMatrices[clusterIndices[j][2]] * + glm::vec3(state.clusterMatrices[clusterIndices[j][2]] * glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][2] + - glm::vec3(state.jointMatrices[clusterIndices[j][3]] * + glm::vec3(state.clusterMatrices[clusterIndices[j][3]] * glm::vec4(sourceVertices[j], 1.0f)) * clusterWeights[j][3]; } - sourceVertices = _blendedVertices.constData(); } else { - transform = state.jointMatrices[0]; + transform = state.clusterMatrices[0]; } if (_resetStates) { for (int j = 0; j < vertexCount; j++) { @@ -221,11 +233,6 @@ bool BlendFace::render(float alpha) { _dilatedTextures.resize(geometry.meshes.size()); } - glm::quat orientation = _owningHead->getOrientation(); - glm::vec3 scale(-_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE, - -_owningHead->getScale() * MODEL_SCALE); - glm::vec3 offset = MODEL_TRANSLATION - geometry.neckPivot; - glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); @@ -245,13 +252,9 @@ bool BlendFace::render(float alpha) { const FBXMesh& mesh = geometry.meshes.at(i); int vertexCount = mesh.vertices.size(); - glPushMatrix(); - // apply eye rotation if appropriate Texture* texture = networkMesh.diffuseTexture.data(); if (mesh.isEye) { - _eyeProgram.bind(); - if (texture != NULL) { texture = (_dilatedTextures[i] = static_cast(texture)->getDilatedTexture( _owningHead->getPupilDilation())).data(); @@ -266,14 +269,30 @@ bool BlendFace::render(float alpha) { glMaterialfv(GL_FRONT, GL_SPECULAR, (const float*)&specular); glMaterialf(GL_FRONT, GL_SHININESS, mesh.shininess); + glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID); + const MeshState& state = _meshStates.at(i); if (state.worldSpaceVertices.isEmpty()) { - glMultMatrixf((const GLfloat*)&state.jointMatrices[0]); + if (state.clusterMatrices.size() > 1) { + _skinProgram.bind(); + glUniformMatrix4fvARB(_clusterMatricesLocation, state.clusterMatrices.size(), false, + (const float*)state.clusterMatrices.constData()); + int offset = vertexCount * sizeof(glm::vec2) + (mesh.blendshapes.isEmpty() ? + vertexCount * 2 * sizeof(glm::vec3) : 0); + _skinProgram.setAttributeBuffer(_clusterIndicesLocation, GL_FLOAT, offset, 4); + _skinProgram.setAttributeBuffer(_clusterWeightsLocation, GL_FLOAT, + offset + vertexCount * sizeof(glm::vec4), 4); + _skinProgram.enableAttributeArray(_clusterIndicesLocation); + _skinProgram.enableAttributeArray(_clusterWeightsLocation); + + } else { + glPushMatrix(); + glMultMatrixf((const GLfloat*)&state.clusterMatrices[0]); + } } glBindTexture(GL_TEXTURE_2D, texture == NULL ? 0 : texture->getID()); - glBindBuffer(GL_ARRAY_BUFFER, networkMesh.vertexBufferID); if (mesh.blendshapes.isEmpty() && mesh.springiness == 0.0f) { glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3))); @@ -322,11 +341,16 @@ bool BlendFace::render(float alpha) { glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, mesh.triangleIndices.size(), GL_UNSIGNED_INT, (void*)(mesh.quadIndices.size() * sizeof(int))); - if (mesh.isEye) { - _eyeProgram.release(); + if (state.worldSpaceVertices.isEmpty()) { + if (state.clusterMatrices.size() > 1) { + _skinProgram.disableAttributeArray(_clusterIndicesLocation); + _skinProgram.disableAttributeArray(_clusterWeightsLocation); + _skinProgram.release(); + + } else { + glPopMatrix(); + } } - - glPopMatrix(); } glDisable(GL_NORMALIZE); diff --git a/interface/src/avatar/BlendFace.h b/interface/src/avatar/BlendFace.h index df944558b1..9a6d87f275 100644 --- a/interface/src/avatar/BlendFace.h +++ b/interface/src/avatar/BlendFace.h @@ -68,7 +68,7 @@ private: class MeshState { public: - QVector jointMatrices; + QVector clusterMatrices; QVector worldSpaceVertices; QVector vertexVelocities; QVector worldSpaceNormals; @@ -83,6 +83,10 @@ private: QVector _blendedNormals; static ProgramObject _eyeProgram; + static ProgramObject _skinProgram; + static int _clusterMatricesLocation; + static int _clusterIndicesLocation; + static int _clusterWeightsLocation; }; #endif /* defined(__interface__BlendFace__) */ diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index e8dc25d9da..c8dbbf0735 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -69,6 +69,7 @@ public: glm::vec3 getPosition() const { return _position; } const glm::vec3& getSkinColor() const { return _skinColor; } const glm::vec3& getEyePosition() const { return _eyePosition; } + const glm::vec3& getSaccade() const { return _saccade; } glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }