Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Freddy 2013-09-25 16:49:04 -07:00
commit b4fa1dc7c2
9 changed files with 163 additions and 18 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 KiB

View file

@ -0,0 +1,28 @@
#version 120
//
// eye.vert
// vertex shader
//
// Created by Andrzej Kapolka on 9/25/13.
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
// the interpolated normal
varying vec4 normal;
void main(void) {
// transform and store the normal for interpolation
normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
// compute standard diffuse lighting per-vertex
gl_FrontColor = vec4(gl_Color.rgb * (gl_LightModel.ambient.rgb + gl_LightSource[0].ambient.rgb +
gl_LightSource[0].diffuse.rgb * max(0.0, dot(normal, gl_LightSource[0].position))), gl_Color.a);
// pass along the texture coordinate
gl_TexCoord[0] = gl_MultiTexCoord0;
// use standard pipeline transform
gl_Position = ftransform();
}

View file

@ -27,6 +27,27 @@ BlendFace::~BlendFace() {
deleteGeometry();
}
ProgramObject BlendFace::_eyeProgram;
GLuint BlendFace::_eyeTextureID;
void BlendFace::init() {
if (!_eyeProgram.isLinked()) {
switchToResourcesParentIfRequired();
_eyeProgram.addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/eye.vert");
_eyeProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/iris.frag");
_eyeProgram.link();
_eyeProgram.bind();
_eyeProgram.setUniformValue("texture", 0);
_eyeProgram.release();
_eyeTextureID = Application::getInstance()->getTextureCache()->getFileTextureID("resources/images/eye.png");
}
}
const glm::vec3 MODEL_TRANSLATION(0.0f, -0.025f, -0.025f); // temporary fudge factor
const float MODEL_SCALE = 0.0006f;
bool BlendFace::render(float alpha) {
if (_meshIDs.isEmpty()) {
return false;
@ -36,11 +57,9 @@ bool BlendFace::render(float alpha) {
glTranslatef(_owningHead->getPosition().x, _owningHead->getPosition().y, _owningHead->getPosition().z);
glm::quat orientation = _owningHead->getOrientation();
glm::vec3 axis = glm::axis(orientation);
glRotatef(glm::angle(orientation), axis.x, axis.y, axis.z);
const glm::vec3 MODEL_TRANSLATION(0.0f, -0.025f, -0.025f); // temporary fudge factor
glRotatef(glm::angle(orientation), axis.x, axis.y, axis.z);
glTranslatef(MODEL_TRANSLATION.x, MODEL_TRANSLATION.y, MODEL_TRANSLATION.z);
const float MODEL_SCALE = 0.0006f;
glm::vec3 scale(_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE,
glm::vec3 scale(-_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE,
-_owningHead->getScale() * MODEL_SCALE);
glScalef(scale.x, scale.y, scale.z);
@ -67,8 +86,16 @@ bool BlendFace::render(float alpha) {
glm::quat rotation = glm::inverse(orientation) * _owningHead->getEyeRotation(orientation *
(mesh.pivot * scale + MODEL_TRANSLATION) + _owningHead->getPosition());
glm::vec3 rotationAxis = glm::axis(rotation);
glRotatef(glm::angle(rotation), rotationAxis.x, rotationAxis.y, rotationAxis.z);
glRotatef(glm::angle(rotation), -rotationAxis.x, rotationAxis.y, -rotationAxis.z);
glTranslatef(-mesh.pivot.x, -mesh.pivot.y, -mesh.pivot.z);
// use texture coordinates only for the eye, for now
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D, _eyeTextureID);
glEnable(GL_TEXTURE_2D);
_eyeProgram.bind();
}
// all meshes after the first are white
@ -107,11 +134,16 @@ bool BlendFace::render(float alpha) {
glVertexPointer(3, GL_FLOAT, 0, 0);
glNormalPointer(GL_FLOAT, 0, (void*)(vertexCount * sizeof(glm::vec3)));
glTexCoordPointer(2, GL_FLOAT, 0, (void*)(vertexCount * 2 * sizeof(glm::vec3)));
glDrawRangeElementsEXT(GL_QUADS, 0, vertexCount - 1, mesh.quadIndices.size(), GL_UNSIGNED_INT, 0);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertexCount - 1, mesh.triangleIndices.size(),
GL_UNSIGNED_INT, (void*)(mesh.quadIndices.size() * sizeof(int)));
if (mesh.isEye) {
_eyeProgram.release();
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glPopMatrix();
}
}
@ -131,6 +163,25 @@ bool BlendFace::render(float alpha) {
return true;
}
void BlendFace::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
glm::quat orientation = _owningHead->getOrientation();
glm::vec3 scale(-_owningHead->getScale() * MODEL_SCALE, _owningHead->getScale() * MODEL_SCALE,
-_owningHead->getScale() * MODEL_SCALE);
bool foundFirst = false;
foreach (const FBXMesh& mesh, _geometry.meshes) {
if (mesh.isEye) {
glm::vec3 position = orientation * (mesh.pivot * scale + MODEL_TRANSLATION) + _owningHead->getPosition();
if (foundFirst) {
secondEyePosition = position;
return;
}
firstEyePosition = position;
foundFirst = true;
}
}
}
void BlendFace::setModelURL(const QUrl& url) {
// don't restart the download if it's the same URL
if (_modelURL == url) {
@ -213,11 +264,13 @@ void BlendFace::setGeometry(const FBXGeometry& geometry) {
glBindBuffer(GL_ARRAY_BUFFER, ids.second);
if (mesh.blendshapes.isEmpty()) {
glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3),
NULL, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3) +
mesh.texCoords.size() * sizeof(glm::vec2), NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, mesh.vertices.size() * sizeof(glm::vec3), mesh.vertices.constData());
glBufferSubData(GL_ARRAY_BUFFER, mesh.vertices.size() * sizeof(glm::vec3),
mesh.normals.size() * sizeof(glm::vec3), mesh.normals.constData());
glBufferSubData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3),
mesh.texCoords.size() * sizeof(glm::vec2), mesh.texCoords.constData());
} else {
glBufferData(GL_ARRAY_BUFFER, (mesh.vertices.size() + mesh.normals.size()) * sizeof(glm::vec3),

View file

@ -14,6 +14,7 @@
#include "InterfaceConfig.h"
#include "renderer/FBXReader.h"
#include "renderer/ProgramObject.h"
class QNetworkReply;
@ -30,11 +31,14 @@ public:
bool isActive() const { return !_meshIDs.isEmpty(); }
void init();
bool render(float alpha);
Q_INVOKABLE void setModelURL(const QUrl& url);
const QUrl& getModelURL() const { return _modelURL; }
void getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
private slots:
void handleModelDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
@ -57,6 +61,9 @@ private:
FBXGeometry _geometry;
QVector<glm::vec3> _blendedVertices;
QVector<glm::vec3> _blendedNormals;
static ProgramObject _eyeProgram;
static GLuint _eyeTextureID;
};
#endif /* defined(__interface__BlendFace__) */

View file

@ -6,8 +6,6 @@
#include <glm/gtx/quaternion.hpp>
#include <QImage>
#include <NodeList.h>
#include "Application.h"
@ -105,16 +103,14 @@ void Head::init() {
_irisProgram.setUniformValue("texture", 0);
_eyePositionLocation = _irisProgram.uniformLocation("eyePosition");
QImage image = QImage(IRIS_TEXTURE_FILENAME).convertToFormat(QImage::Format_ARGB32);
glGenTextures(1, &_irisTextureID);
_irisTextureID = Application::getInstance()->getTextureCache()->getFileTextureID(IRIS_TEXTURE_FILENAME);
glBindTexture(GL_TEXTURE_2D, _irisTextureID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1, GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glBindTexture(GL_TEXTURE_2D, 0);
}
_blendFace.init();
}
void Head::reset() {
@ -347,7 +343,13 @@ void Head::render(float alpha, bool isMine) {
}
if (_renderLookatVectors) {
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
glm::vec3 firstEyePosition = _leftEyePosition;
glm::vec3 secondEyePosition = _rightEyePosition;
if (_blendFace.isActive()) {
// the blend face may have custom eye meshes
_blendFace.getEyePositions(firstEyePosition, secondEyePosition);
}
renderLookatVectors(firstEyePosition, secondEyePosition, _lookAtPosition);
}
}

View file

@ -197,6 +197,16 @@ QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) {
return values;
}
QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) {
QVector<glm::vec2> values;
for (const double* it = doubleVector.constData(), *end = it + doubleVector.size(); it != end; ) {
float s = *it++;
float t = *it++;
values.append(glm::vec2(s, t));
}
return values;
}
const char* FACESHIFT_BLENDSHAPES[] = {
"EyeBlink_L",
"EyeBlink_R",
@ -285,8 +295,10 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) {
if (object.properties.at(2) == "Mesh") {
FBXMesh mesh;
QVector<glm::vec3> normals;
QVector<int> polygonIndices;
QVector<glm::vec3> normals;
QVector<glm::vec2> texCoords;
QVector<int> texCoordIndices;
foreach (const FBXNode& data, object.children) {
if (data.name == "Vertices") {
mesh.vertices = createVec3Vector(data.properties.at(0).value<QVector<double> >());
@ -300,14 +312,29 @@ FBXGeometry extractFBXGeometry(const FBXNode& node) {
normals = createVec3Vector(subdata.properties.at(0).value<QVector<double> >());
}
}
} else if (data.name == "LayerElementUV" && data.properties.at(0).toInt() == 0) {
foreach (const FBXNode& subdata, data.children) {
if (subdata.name == "UV") {
texCoords = createVec2Vector(subdata.properties.at(0).value<QVector<double> >());
} else if (subdata.name == "UVIndex") {
texCoordIndices = subdata.properties.at(0).value<QVector<int> >();
}
}
}
}
// the (base) normals correspond to the polygon indices, for some reason
// the (base) normals and tex coords correspond to the polygon indices, for some reason
mesh.normals.resize(mesh.vertices.size());
mesh.texCoords.resize(mesh.vertices.size());
for (int i = 0, n = polygonIndices.size(); i < n; i++) {
int index = polygonIndices.at(i);
mesh.normals[index < 0 ? (-index - 1) : index] = normals[i];
index = (index < 0) ? (-index - 1) : index;
mesh.normals[index] = normals.at(i);
int texCoordIndex = texCoordIndices.at(i);
if (texCoordIndex >= 0) {
mesh.texCoords[index] = texCoords.at(texCoordIndex);
}
}
// convert the polygons to quads and triangles

View file

@ -46,6 +46,7 @@ public:
QVector<int> triangleIndices;
QVector<glm::vec3> vertices;
QVector<glm::vec3> normals;
QVector<glm::vec2> texCoords;
glm::vec3 pivot;

View file

@ -24,6 +24,9 @@ TextureCache::~TextureCache() {
if (_permutationNormalTextureID != 0) {
glDeleteTextures(1, &_permutationNormalTextureID);
}
foreach (GLuint id, _fileTextureIDs) {
glDeleteTextures(1, &id);
}
if (_primaryFramebufferObject != NULL) {
delete _primaryFramebufferObject;
glDeleteTextures(1, &_primaryDepthTextureID);
@ -62,6 +65,24 @@ GLuint TextureCache::getPermutationNormalTextureID() {
return _permutationNormalTextureID;
}
GLuint TextureCache::getFileTextureID(const QString& filename) {
GLuint id = _fileTextureIDs.value(filename);
if (id == 0) {
switchToResourcesParentIfRequired();
QImage image = QImage(filename).convertToFormat(QImage::Format_ARGB32);
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1,
GL_BGRA, GL_UNSIGNED_BYTE, image.constBits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
_fileTextureIDs.insert(filename, id);
}
return id;
}
QOpenGLFramebufferObject* TextureCache::getPrimaryFramebufferObject() {
if (_primaryFramebufferObject == NULL) {
_primaryFramebufferObject = createFramebufferObject();

View file

@ -9,6 +9,7 @@
#ifndef __interface__TextureCache__
#define __interface__TextureCache__
#include <QHash>
#include <QObject>
#include "InterfaceConfig.h"
@ -27,6 +28,9 @@ public:
/// the second, a set of random unit vectors to be used as noise gradients.
GLuint getPermutationNormalTextureID();
/// Returns the ID of a texture containing the contents of the specified file, loading it if necessary.
GLuint getFileTextureID(const QString& filename);
/// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is
/// used for scene rendering.
QOpenGLFramebufferObject* getPrimaryFramebufferObject();
@ -50,6 +54,8 @@ private:
GLuint _permutationNormalTextureID;
QHash<QString, GLuint> _fileTextureIDs;
GLuint _primaryDepthTextureID;
QOpenGLFramebufferObject* _primaryFramebufferObject;
QOpenGLFramebufferObject* _secondaryFramebufferObject;