mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 14:33:31 +02:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
b4fa1dc7c2
9 changed files with 163 additions and 18 deletions
BIN
interface/resources/images/eye.png
Normal file
BIN
interface/resources/images/eye.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 862 KiB |
28
interface/resources/shaders/eye.vert
Normal file
28
interface/resources/shaders/eye.vert
Normal 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();
|
||||
}
|
|
@ -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),
|
||||
|
|
|
@ -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__) */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -46,6 +46,7 @@ public:
|
|||
QVector<int> triangleIndices;
|
||||
QVector<glm::vec3> vertices;
|
||||
QVector<glm::vec3> normals;
|
||||
QVector<glm::vec2> texCoords;
|
||||
|
||||
glm::vec3 pivot;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue