Redistributing the files to create the model-networking lib and separate that from the redner-utils

This commit is contained in:
samcake 2015-09-21 13:21:35 -07:00
parent 2875cb99bb
commit d3b1bcb86d
36 changed files with 1055 additions and 748 deletions

View file

@ -113,7 +113,7 @@ endif()
target_link_libraries(${TARGET_NAME} ${BULLET_LIBRARIES})
# link required hifi libraries
link_hifi_libraries(shared octree environment gpu gpu-networking procedural model render fbx networking entities avatars
link_hifi_libraries(shared octree environment gpu procedural model render fbx networking model-networking entities avatars
audio audio-client animation script-engine physics
render-utils entities-renderer ui auto-updater
plugins display-plugins input-plugins)

View file

@ -278,6 +278,7 @@ bool setupEssentials(int& argc, char** argv) {
auto addressManager = DependencyManager::set<AddressManager>();
auto nodeList = DependencyManager::set<NodeList>(NodeType::Agent, listenPort);
auto geometryCache = DependencyManager::set<GeometryCache>();
auto modelCache = DependencyManager::set<ModelCache>();
auto scriptCache = DependencyManager::set<ScriptCache>();
auto soundCache = DependencyManager::set<SoundCache>();
auto faceshift = DependencyManager::set<Faceshift>();
@ -418,12 +419,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// put the NodeList and datagram processing on the node thread
nodeList->moveToThread(nodeThread);
// geometry background downloads need to happen on the Datagram Processor Thread. The idle loop will
// emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background
// Model background downloads need to happen on the Datagram Processor Thread. The idle loop will
// emit checkBackgroundDownloads to cause the ModelCache to check it's queue for requested background
// downloads.
QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>();
ResourceCache* geometryCache = geometryCacheP.data();
connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets);
QSharedPointer<ModelCache> modelCacheP = DependencyManager::get<ModelCache>();
ResourceCache* modelCache = modelCacheP.data();
connect(this, &Application::checkBackgroundDownloads, modelCache, &ResourceCache::checkAsynchronousGets);
// put the audio processing on a separate thread
QThread* audioThread = new QThread();
@ -892,6 +893,7 @@ Application::~Application() {
DependencyManager::destroy<AnimationCache>();
DependencyManager::destroy<FramebufferCache>();
DependencyManager::destroy<TextureCache>();
DependencyManager::destroy<ModelCache>();
DependencyManager::destroy<GeometryCache>();
DependencyManager::destroy<ScriptCache>();
DependencyManager::destroy<SoundCache>();
@ -2718,7 +2720,7 @@ void Application::reloadResourceCaches() {
emptyLocalCache();
DependencyManager::get<AnimationCache>()->refreshAll();
DependencyManager::get<GeometryCache>()->refreshAll();
DependencyManager::get<ModelCache>()->refreshAll();
DependencyManager::get<SoundCache>()->refreshAll();
DependencyManager::get<TextureCache>()->refreshAll();
}

View file

@ -188,8 +188,10 @@ void Stars::render(RenderArgs* renderArgs, float alpha) {
colorElement = streamFormat->getAttributes().at(gpu::Stream::COLOR)._element;
});
auto geometryCache = DependencyManager::get<GeometryCache>();
auto modelCache = DependencyManager::get<ModelCache>();
auto textureCache = DependencyManager::get<TextureCache>();
auto geometryCache = DependencyManager::get<GeometryCache>();
gpu::Batch& batch = *renderArgs->_batch;
batch.setViewTransform(Transform());

View file

@ -56,7 +56,7 @@ CachesSizeDialog::CachesSizeDialog(QWidget* parent) :
void CachesSizeDialog::confirmClicked(bool checked) {
DependencyManager::get<AnimationCache>()->setUnusedResourceCacheSize(_animations->value() * BYTES_PER_MEGABYTES);
DependencyManager::get<GeometryCache>()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES);
DependencyManager::get<ModelCache>()->setUnusedResourceCacheSize(_geometries->value() * BYTES_PER_MEGABYTES);
DependencyManager::get<SoundCache>()->setUnusedResourceCacheSize(_sounds->value() * BYTES_PER_MEGABYTES);
DependencyManager::get<TextureCache>()->setUnusedResourceCacheSize(_textures->value() * BYTES_PER_MEGABYTES);
@ -65,7 +65,7 @@ void CachesSizeDialog::confirmClicked(bool checked) {
void CachesSizeDialog::resetClicked(bool checked) {
_animations->setValue(DependencyManager::get<AnimationCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
_geometries->setValue(DependencyManager::get<GeometryCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
_geometries->setValue(DependencyManager::get<ModelCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
_sounds->setValue(DependencyManager::get<SoundCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
_textures->setValue(DependencyManager::get<TextureCache>()->getUnusedResourceCacheSize() / BYTES_PER_MEGABYTES);
}

View file

@ -26,4 +26,4 @@ find_package(PolyVox REQUIRED)
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES})
link_hifi_libraries(shared gpu gpu-networking procedural script-engine render render-utils)
link_hifi_libraries(shared gpu procedural model model-networking script-engine render render-utils)

View file

@ -71,3 +71,28 @@ bool Shader::makeProgram(Shader& shader, const Shader::BindingSet& bindings) {
}
return false;
}
// ShaderSource
ShaderSource::ShaderSource() {
}
ShaderSource::~ShaderSource() {
}
void ShaderSource::reset(const QUrl& url) {
_shaderUrl = url;
_gpuShader.reset();
}
void ShaderSource::resetShader(gpu::Shader* shader) {
_gpuShader.reset(shader);
}
bool ShaderSource::isDefined() const {
if (_gpuShader) {
return true;
} else {
return false;
}
}

View file

@ -15,6 +15,8 @@
#include <string>
#include <memory>
#include <set>
#include <QUrl>
namespace gpu {
@ -187,6 +189,27 @@ protected:
typedef Shader::Pointer ShaderPointer;
typedef std::vector< ShaderPointer > Shaders;
// ShaderSource is the bridge between a URL or a a way to produce the final gpu::Shader that will be used to render it.
class ShaderSource {
public:
ShaderSource();
~ShaderSource();
const QUrl& getUrl() const { return _shaderUrl; }
const gpu::ShaderPointer getGPUShader() const { return _gpuShader; }
void reset(const QUrl& url);
void resetShader(gpu::Shader* texture);
bool isDefined() const;
protected:
gpu::ShaderPointer _gpuShader;
QUrl _shaderUrl;
};
typedef std::shared_ptr< ShaderSource > ShaderSourcePointer;
};

View file

@ -768,3 +768,28 @@ void SphericalHarmonics::evalFromTexture(const Texture& texture) {
L22 = coefs[8];
}
}
// TextureSource
TextureSource::TextureSource() {
}
TextureSource::~TextureSource() {
}
void TextureSource::reset(const QUrl& url) {
_imageUrl = url;
}
void TextureSource::resetTexture(gpu::Texture* texture) {
_gpuTexture.reset(texture);
}
bool TextureSource::isDefined() const {
if (_gpuTexture) {
return _gpuTexture->isDefined();
} else {
return false;
}
}

View file

@ -15,6 +15,8 @@
#include <algorithm> //min max and more
#include <QUrl>
namespace gpu {
// THe spherical harmonics is a nice tool for cubemap, so if required, the irradiance SH can be automatically generated
@ -441,6 +443,28 @@ public:
};
typedef std::vector<TextureView> TextureViews;
// TextureSource is the bridge between a URL or a a way to produce an image and the final gpu::Texture that will be used to render it.
// It provides the mechanism to create a texture using a customizable TextureLoader
class TextureSource {
public:
TextureSource();
~TextureSource();
const QUrl& getUrl() const { return _imageUrl; }
const gpu::TexturePointer getGPUTexture() const { return _gpuTexture; }
void reset(const QUrl& url);
void resetTexture(gpu::Texture* texture);
bool isDefined() const;
protected:
gpu::TexturePointer _gpuTexture;
QUrl _imageUrl;
};
typedef std::shared_ptr< TextureSource > TextureSourcePointer;
};

View file

@ -1,4 +1,4 @@
set(TARGET_NAME gpu-networking)
set(TARGET_NAME model-networking)
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
setup_hifi_library()

View file

@ -0,0 +1,506 @@
//
// ModelCache.cpp
// interface/src/renderer
//
// Created by Andrzej Kapolka on 6/21/13.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ModelCache.h"
#include <cmath>
#include <QNetworkReply>
#include <QThreadPool>
#include <FSTReader.h>
#include <NumericalConstants.h>
#include "TextureCache.h"
#include "ModelNetworkingLogging.h"
#include "gpu/StandardShaderLib.h"
#include "model/TextureMap.h"
//#define WANT_DEBUG
ModelCache::ModelCache()
{
const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;
setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE);
}
ModelCache::~ModelCache() {
}
QSharedPointer<Resource> ModelCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
bool delayLoad, const void* extra) {
// NetworkGeometry is no longer a subclass of Resource, but requires this method because, it is pure virtual.
assert(false);
return QSharedPointer<Resource>();
}
GeometryReader::GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping) :
_url(url),
_data(data),
_mapping(mapping) {
}
void GeometryReader::run() {
try {
if (_data.isEmpty()) {
throw QString("Reply is NULL ?!");
}
QString urlname = _url.path().toLower();
bool urlValid = true;
urlValid &= !urlname.isEmpty();
urlValid &= !_url.path().isEmpty();
urlValid &= _url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj");
if (urlValid) {
// Let's read the binaries from the network
FBXGeometry* fbxgeo = nullptr;
if (_url.path().toLower().endsWith(".fbx")) {
const bool grabLightmaps = true;
const float lightmapLevel = 1.0f;
fbxgeo = readFBX(_data, _mapping, _url.path(), grabLightmaps, lightmapLevel);
} else if (_url.path().toLower().endsWith(".obj")) {
fbxgeo = OBJReader().readOBJ(_data, _mapping, _url);
} else {
QString errorStr("usupported format");
emit onError(NetworkGeometry::ModelParseError, errorStr);
}
emit onSuccess(fbxgeo);
} else {
throw QString("url is invalid");
}
} catch (const QString& error) {
qCDebug(modelnetworking) << "Error reading " << _url << ": " << error;
emit onError(NetworkGeometry::ModelParseError, error);
}
}
NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
_url(url),
_mapping(mapping),
_textureBaseUrl(textureBaseUrl.isValid() ? textureBaseUrl : url) {
if (delayLoad) {
_state = DelayState;
} else {
attemptRequestInternal();
}
}
NetworkGeometry::~NetworkGeometry() {
if (_resource) {
_resource->deleteLater();
}
}
void NetworkGeometry::attemptRequest() {
if (_state == DelayState) {
attemptRequestInternal();
}
}
void NetworkGeometry::attemptRequestInternal() {
if (_url.path().toLower().endsWith(".fst")) {
_mappingUrl = _url;
requestMapping(_url);
} else {
_modelUrl = _url;
requestModel(_url);
}
}
bool NetworkGeometry::isLoaded() const {
return _state == SuccessState;
}
bool NetworkGeometry::isLoadedWithTextures() const {
if (!isLoaded()) {
return false;
}
if (!_isLoadedWithTextures) {
for (auto&& material : _materials) {
if ((material->diffuseTexture && !material->diffuseTexture->isLoaded()) ||
(material->normalTexture && !material->normalTexture->isLoaded()) ||
(material->specularTexture && !material->specularTexture->isLoaded()) ||
(material->emissiveTexture && !material->emissiveTexture->isLoaded())) {
return false;
}
}
_isLoadedWithTextures = true;
}
return true;
}
void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) {
if (_meshes.size() > 0) {
auto textureCache = DependencyManager::get<TextureCache>();
for (auto&& material : _materials) {
QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();
if (material->diffuseTextureName == name) {
material->diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE);
} else if (material->normalTextureName == name) {
material->normalTexture = textureCache->getTexture(url);
} else if (material->specularTextureName == name) {
material->specularTexture = textureCache->getTexture(url);
} else if (material->emissiveTextureName == name) {
material->emissiveTexture = textureCache->getTexture(url);
}
}
} else {
qCWarning(modelnetworking) << "Ignoring setTextureWirthNameToURL() geometry not ready." << name << url;
}
_isLoadedWithTextures = false;
}
QStringList NetworkGeometry::getTextureNames() const {
QStringList result;
for (auto&& material : _materials) {
if (!material->diffuseTextureName.isEmpty() && material->diffuseTexture) {
QString textureURL = material->diffuseTexture->getURL().toString();
result << material->diffuseTextureName + ":" + textureURL;
}
if (!material->normalTextureName.isEmpty() && material->normalTexture) {
QString textureURL = material->normalTexture->getURL().toString();
result << material->normalTextureName + ":" + textureURL;
}
if (!material->specularTextureName.isEmpty() && material->specularTexture) {
QString textureURL = material->specularTexture->getURL().toString();
result << material->specularTextureName + ":" + textureURL;
}
if (!material->emissiveTextureName.isEmpty() && material->emissiveTexture) {
QString textureURL = material->emissiveTexture->getURL().toString();
result << material->emissiveTextureName + ":" + textureURL;
}
}
return result;
}
void NetworkGeometry::requestMapping(const QUrl& url) {
_state = RequestMappingState;
if (_resource) {
_resource->deleteLater();
}
_resource = new Resource(url, false);
connect(_resource, &Resource::loaded, this, &NetworkGeometry::mappingRequestDone);
connect(_resource, &Resource::failed, this, &NetworkGeometry::mappingRequestError);
}
void NetworkGeometry::requestModel(const QUrl& url) {
_state = RequestModelState;
if (_resource) {
_resource->deleteLater();
}
_modelUrl = url;
_resource = new Resource(url, false);
connect(_resource, &Resource::loaded, this, &NetworkGeometry::modelRequestDone);
connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError);
}
void NetworkGeometry::mappingRequestDone(const QByteArray& data) {
assert(_state == RequestMappingState);
// parse the mapping file
_mapping = FSTReader::readMapping(data);
QUrl replyUrl = _mappingUrl;
QString modelUrlStr = _mapping.value("filename").toString();
if (modelUrlStr.isNull()) {
qCDebug(modelnetworking) << "Mapping file " << _url << "has no \"filename\" entry";
emit onFailure(*this, MissingFilenameInMapping);
} else {
// read _textureBase from mapping file, if present
QString texdir = _mapping.value("texdir").toString();
if (!texdir.isNull()) {
if (!texdir.endsWith('/')) {
texdir += '/';
}
_textureBaseUrl = replyUrl.resolved(texdir);
}
_modelUrl = replyUrl.resolved(modelUrlStr);
requestModel(_modelUrl);
}
}
void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) {
assert(_state == RequestMappingState);
_state = ErrorState;
emit onFailure(*this, MappingRequestError);
}
void NetworkGeometry::modelRequestDone(const QByteArray& data) {
assert(_state == RequestModelState);
_state = ParsingModelState;
// asynchronously parse the model file.
GeometryReader* geometryReader = new GeometryReader(_modelUrl, data, _mapping);
connect(geometryReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(modelParseSuccess(FBXGeometry*)));
connect(geometryReader, SIGNAL(onError(int, QString)), SLOT(modelParseError(int, QString)));
QThreadPool::globalInstance()->start(geometryReader);
}
void NetworkGeometry::modelRequestError(QNetworkReply::NetworkError error) {
assert(_state == RequestModelState);
_state = ErrorState;
emit onFailure(*this, ModelRequestError);
}
static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBaseUrl) {
auto textureCache = DependencyManager::get<TextureCache>();
NetworkMesh* networkMesh = new NetworkMesh();
int totalIndices = 0;
bool checkForTexcoordLightmap = false;
// process network parts
foreach (const FBXMeshPart& part, mesh.parts) {
totalIndices += (part.quadIndices.size() + part.triangleIndices.size());
}
// initialize index buffer
{
networkMesh->_indexBuffer = std::make_shared<gpu::Buffer>();
networkMesh->_indexBuffer->resize(totalIndices * sizeof(int));
int offset = 0;
foreach(const FBXMeshPart& part, mesh.parts) {
networkMesh->_indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),
(gpu::Byte*) part.quadIndices.constData());
offset += part.quadIndices.size() * sizeof(int);
networkMesh->_indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),
(gpu::Byte*) part.triangleIndices.constData());
offset += part.triangleIndices.size() * sizeof(int);
}
}
// initialize vertex buffer
{
networkMesh->_vertexBuffer = std::make_shared<gpu::Buffer>();
// if we don't need to do any blending, the positions/normals can be static
if (mesh.blendshapes.isEmpty()) {
int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2);
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
networkMesh->_vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData());
networkMesh->_vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData());
networkMesh->_vertexBuffer->setSubData(tangentsOffset,
mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
networkMesh->_vertexBuffer->setSubData(texCoords1Offset,
mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords1.constData());
networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
// otherwise, at least the cluster indices/weights can be static
networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
if (mesh.normals.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, normalsOffset, sizeof(glm::vec3));
if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, tangentsOffset, sizeof(glm::vec3));
if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
if (mesh.texCoords1.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoords1Offset, sizeof(glm::vec2));
if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
int channelNum = 0;
networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
if (mesh.texCoords1.size()) {
networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
// } else if (checkForTexcoordLightmap && mesh.texCoords.size()) {
} else if (mesh.texCoords.size()) {
// need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel
networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
}
if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
}
else {
int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
networkMesh->_vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
int channelNum = 0;
networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
}
}
return networkMesh;
}
static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) {
auto textureCache = DependencyManager::get<TextureCache>();
NetworkMaterial* networkMaterial = new NetworkMaterial();
int totalIndices = 0;
bool checkForTexcoordLightmap = false;
networkMaterial->_material = material._material;
if (!material.diffuseTexture.filename.isEmpty()) {
networkMaterial->diffuseTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.diffuseTexture.filename)), DEFAULT_TEXTURE, material.diffuseTexture.content);
networkMaterial->diffuseTextureName = material.diffuseTexture.name;
auto diffuseMap = model::TextureMapPointer(new model::TextureMap());
diffuseMap->setTextureSource(networkMaterial->diffuseTexture->_textureSource);
diffuseMap->setTextureTransform(material.diffuseTexture.transform);
material._material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap);
}
if (!material.normalTexture.filename.isEmpty()) {
networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content);
networkMaterial->normalTextureName = material.normalTexture.name;
auto normalMap = model::TextureMapPointer(new model::TextureMap());
normalMap->setTextureSource(networkMaterial->normalTexture->_textureSource);
material._material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap);
}
if (!material.specularTexture.filename.isEmpty()) {
networkMaterial->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content);
networkMaterial->specularTextureName = material.specularTexture.name;
auto glossMap = model::TextureMapPointer(new model::TextureMap());
glossMap->setTextureSource(networkMaterial->specularTexture->_textureSource);
material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap);
}
if (!material.emissiveTexture.filename.isEmpty()) {
networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content);
networkMaterial->emissiveTextureName = material.emissiveTexture.name;
checkForTexcoordLightmap = true;
auto lightmapMap = model::TextureMapPointer(new model::TextureMap());
lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource);
lightmapMap->setTextureTransform(material.emissiveTexture.transform);
lightmapMap->setLightmapOffsetScale(material.emissiveParams.x, material.emissiveParams.y);
material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap);
}
return networkMaterial;
}
void NetworkGeometry::modelParseSuccess(FBXGeometry* geometry) {
// assume owner ship of geometry pointer
_geometry.reset(geometry);
foreach(const FBXMesh& mesh, _geometry->meshes) {
_meshes.emplace_back(buildNetworkMesh(mesh, _textureBaseUrl));
}
QHash<QString, int> fbxMatIDToMatID;
foreach(const FBXMaterial& material, _geometry->materials) {
fbxMatIDToMatID[material.materialID] = _materials.size();
_materials.emplace_back(buildNetworkMaterial(material, _textureBaseUrl));
}
int meshID = 0;
foreach(const FBXMesh& mesh, _geometry->meshes) {
int partID = 0;
foreach (const FBXMeshPart& part, mesh.parts) {
NetworkShape* networkShape = new NetworkShape();
networkShape->_meshID = meshID;
networkShape->_partID = partID;
networkShape->_materialID = fbxMatIDToMatID[part.materialID];
_shapes.emplace_back(networkShape);
partID++;
}
meshID++;
}
_state = SuccessState;
emit onSuccess(*this, *_geometry.get());
delete _resource;
_resource = nullptr;
}
void NetworkGeometry::modelParseError(int error, QString str) {
_state = ErrorState;
emit onFailure(*this, (NetworkGeometry::Error)error);
delete _resource;
_resource = nullptr;
}
const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) {
if ((shapeID >= 0) && (shapeID < _shapes.size())) {
int materialID = _shapes[shapeID]->_materialID;
if ((materialID >= 0) && (materialID < _materials.size())) {
return _materials[materialID].get();
} else {
return 0;
}
} else {
return 0;
}
}

View file

@ -0,0 +1,205 @@
//
// ModelCache.h
// libraries/model-networking/src/model-networking
//
// Created by Sam Gateau on 9/21/15.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_ModelCache_h
#define hifi_ModelCache_h
#include <QMap>
#include <QRunnable>
#include <DependencyManager.h>
#include <ResourceCache.h>
#include "FBXReader.h"
#include "OBJReader.h"
#include <gpu/Batch.h>
#include <gpu/Stream.h>
#include <model/Material.h>
#include <model/Asset.h>
class NetworkGeometry;
class NetworkMesh;
class NetworkTexture;
class NetworkMaterial;
class NetworkShape;
/// Stores cached geometry.
class ModelCache : public ResourceCache, public Dependency {
Q_OBJECT
SINGLETON_DEPENDENCY
public:
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
bool delayLoad, const void* extra);
/// Loads geometry from the specified URL.
/// \param fallback a fallback URL to load if the desired one is unavailable
/// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false);
/// Set a batch to the simple pipeline, returning the previous pipeline
void useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend = false);
private:
ModelCache();
virtual ~ModelCache();
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
};
class NetworkGeometry : public QObject {
Q_OBJECT
public:
// mapping is only used if url is a .fbx or .obj file, it is essentially the content of an fst file.
// if delayLoad is true, the url will not be immediately downloaded.
// use the attemptRequest method to initiate the download.
NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl = QUrl());
~NetworkGeometry();
const QUrl& getURL() const { return _url; }
void attemptRequest();
// true when the geometry is loaded (but maybe not it's associated textures)
bool isLoaded() const;
// true when the requested geometry and its textures are loaded.
bool isLoadedWithTextures() const;
// WARNING: only valid when isLoaded returns true.
const FBXGeometry& getFBXGeometry() const { return *_geometry; }
const std::vector<std::unique_ptr<NetworkMesh>>& getMeshes() const { return _meshes; }
// const model::AssetPointer getAsset() const { return _asset; }
// model::MeshPointer getShapeMesh(int shapeID);
// int getShapePart(int shapeID);
// This would be the final verison
// model::MaterialPointer getShapeMaterial(int shapeID);
const NetworkMaterial* getShapeMaterial(int shapeID);
void setTextureWithNameToURL(const QString& name, const QUrl& url);
QStringList getTextureNames() const;
enum Error {
MissingFilenameInMapping = 0,
MappingRequestError,
ModelRequestError,
ModelParseError
};
signals:
// Fired when everything has downloaded and parsed successfully.
void onSuccess(NetworkGeometry& networkGeometry, FBXGeometry& fbxGeometry);
// Fired when something went wrong.
void onFailure(NetworkGeometry& networkGeometry, Error error);
protected slots:
void mappingRequestDone(const QByteArray& data);
void mappingRequestError(QNetworkReply::NetworkError error);
void modelRequestDone(const QByteArray& data);
void modelRequestError(QNetworkReply::NetworkError error);
void modelParseSuccess(FBXGeometry* geometry);
void modelParseError(int error, QString str);
protected:
void attemptRequestInternal();
void requestMapping(const QUrl& url);
void requestModel(const QUrl& url);
enum State { DelayState,
RequestMappingState,
RequestModelState,
ParsingModelState,
SuccessState,
ErrorState };
State _state;
QUrl _url;
QUrl _mappingUrl;
QUrl _modelUrl;
QVariantHash _mapping;
QUrl _textureBaseUrl;
Resource* _resource = nullptr;
std::unique_ptr<FBXGeometry> _geometry; // This should go away evenutally once we can put everything we need in the model::AssetPointer
std::vector<std::unique_ptr<NetworkMesh>> _meshes;
std::vector<std::unique_ptr<NetworkMaterial>> _materials;
std::vector<std::unique_ptr<NetworkShape>> _shapes;
// The model asset created from this NetworkGeometry
// model::AssetPointer _asset;
// cache for isLoadedWithTextures()
mutable bool _isLoadedWithTextures = false;
};
/// Reads geometry in a worker thread.
class GeometryReader : public QObject, public QRunnable {
Q_OBJECT
public:
GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping);
virtual void run();
signals:
void onSuccess(FBXGeometry* geometry);
void onError(int error, QString str);
private:
QUrl _url;
QByteArray _data;
QVariantHash _mapping;
};
class NetworkShape {
public:
int _meshID{ -1 };
int _partID{ -1 };
int _materialID{ -1 };
};
class NetworkMaterial {
public:
model::MaterialPointer _material;
QString diffuseTextureName;
QSharedPointer<NetworkTexture> diffuseTexture;
QString normalTextureName;
QSharedPointer<NetworkTexture> normalTexture;
QString specularTextureName;
QSharedPointer<NetworkTexture> specularTexture;
QString emissiveTextureName;
QSharedPointer<NetworkTexture> emissiveTexture;
};
/// The state associated with a single mesh.
class NetworkMesh {
public:
gpu::BufferPointer _indexBuffer;
gpu::BufferPointer _vertexBuffer;
gpu::BufferStreamPointer _vertexStream;
gpu::Stream::FormatPointer _vertexFormat;
int getTranslucentPartCount(const FBXMesh& fbxMesh) const;
bool isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const;
};
#endif // hifi_GeometryCache_h

View file

@ -6,6 +6,6 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "GpuNetworkingLogging.h"
#include "ModelNetworkingLogging.h"
Q_LOGGING_CATEGORY(gpunetwork, "hifi.gpu-network")
Q_LOGGING_CATEGORY(modelnetworking, "hifi.gpu-network")

View file

@ -8,4 +8,4 @@
#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(gpunetwork)
Q_DECLARE_LOGGING_CATEGORY(modelnetworking)

View file

@ -1,6 +1,6 @@
//
// TextureCache.cpp
// libraries/gpu-networking/src
// libraries/model-networking/src
//
// Created by Andrzej Kapolka on 8/6/13.
// Copyright 2013 High Fidelity, Inc.
@ -25,7 +25,7 @@
#include <gpu/Batch.h>
#include "GpuNetworkingLogging.h"
#include "ModelNetworkingLogging.h"
TextureCache::TextureCache() {
const qint64 TEXTURE_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;
@ -185,7 +185,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, TextureType type, const QByteArr
_width(0),
_height(0) {
_textureSource.reset(new model::TextureSource());
_textureSource.reset(new gpu::TextureSource());
if (!url.isValid()) {
_loaded = true;
@ -206,7 +206,7 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture
_width(0),
_height(0) {
_textureSource.reset(new model::TextureSource());
_textureSource.reset(new gpu::TextureSource());
if (!url.isValid()) {
_loaded = true;
@ -223,11 +223,11 @@ NetworkTexture::NetworkTexture(const QUrl& url, const TextureLoaderFunc& texture
NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
switch (_type) {
case CUBE_TEXTURE: {
return TextureLoaderFunc(model::TextureSource::createCubeTextureFromImage);
return TextureLoaderFunc(model::TextureUsage::createCubeTextureFromImage);
break;
}
case BUMP_TEXTURE: {
return TextureLoaderFunc(model::TextureSource::createNormalTextureFromBumpImage);
return TextureLoaderFunc(model::TextureUsage::createNormalTextureFromBumpImage);
break;
}
case CUSTOM_TEXTURE: {
@ -239,7 +239,7 @@ NetworkTexture::TextureLoaderFunc NetworkTexture::getTextureLoader() const {
case SPECULAR_TEXTURE:
case EMISSIVE_TEXTURE:
default: {
return TextureLoaderFunc(model::TextureSource::create2DTextureFromImage);
return TextureLoaderFunc(model::TextureUsage::create2DTextureFromImage);
break;
}
}
@ -288,7 +288,7 @@ void listSupportedImageFormats() {
foreach(const QByteArray& f, supportedFormats) {
formats += QString(f) + ",";
}
qCDebug(gpunetwork) << "List of supported Image formats:" << formats;
qCDebug(modelnetworking) << "List of supported Image formats:" << formats;
});
}
@ -313,9 +313,9 @@ void ImageReader::run() {
if (originalWidth == 0 || originalHeight == 0 || imageFormat == QImage::Format_Invalid) {
if (filenameExtension.empty()) {
qCDebug(gpunetwork) << "QImage failed to create from content, no file extension:" << _url;
qCDebug(modelnetworking) << "QImage failed to create from content, no file extension:" << _url;
} else {
qCDebug(gpunetwork) << "QImage failed to create from content" << _url;
qCDebug(modelnetworking) << "QImage failed to create from content" << _url;
}
return;
}

View file

@ -1,6 +1,6 @@
//
// TextureCache.h
// libraries/gpu-networking/src
// libraries/model-networking/src
//
// Created by Andrzej Kapolka on 8/6/13.
// Copyright 2013 High Fidelity, Inc.
@ -98,7 +98,7 @@ public:
~Texture();
const gpu::TexturePointer getGPUTexture() const { return _textureSource->getGPUTexture(); }
model::TextureSourcePointer _textureSource;
gpu::TextureSourcePointer _textureSource;
protected:

View file

@ -9,4 +9,4 @@ add_dependency_external_projects(glm)
find_package(GLM REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
link_hifi_libraries(shared networking gpu octree)
link_hifi_libraries(shared gpu)

View file

@ -13,7 +13,6 @@
#include <gpu/Batch.h>
#include <gpu/Context.h>
// #include <procedural/Procedural.h>
#include <ViewFrustum.h>
#include "Skybox_vert.h"
@ -39,16 +38,7 @@ Skybox::Skybox() {
void Skybox::setColor(const Color& color) {
_color = color;
}
/*
void Skybox::setProcedural(QSharedPointer<Procedural> procedural) {
_procedural = procedural;
if (_procedural) {
_procedural->_vertexSource = Skybox_vert;
_procedural->_fragmentSource = Skybox_frag;
// No pipeline state customization
}
}
*/
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
_cubemap = cubemap;
}
@ -58,7 +48,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
static gpu::BufferPointer theBuffer;
static gpu::Stream::FormatPointer theFormat;
if (/*skybox._procedural || */skybox.getCubemap()) {
if (skybox._procedural || skybox.getCubemap()) {
if (!theBuffer) {
const float CLIP = 1.0f;
const glm::vec2 vertices[4] = { { -CLIP, -CLIP }, { CLIP, -CLIP }, { -CLIP, CLIP }, { CLIP, CLIP } };
@ -78,14 +68,7 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
batch.setInputFormat(theFormat);
/*if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) {
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
batch.setResourceTexture(0, skybox.getCubemap());
}
skybox._procedural->prepare(batch, glm::vec3(1));
batch.draw(gpu::TRIANGLE_STRIP, 4);
} else*/ if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
static gpu::BufferPointer theConstants;
static gpu::PipelinePointer thePipeline;
static int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader

View file

@ -11,13 +11,14 @@
#ifndef hifi_model_Skybox_h
#define hifi_model_Skybox_h
//#include <QtCore/QSharedPointer>
#include <gpu/Texture.h>
#include "Light.h"
class ViewFrustum;
struct Procedural;
typedef std::shared_ptr<Procedural> ProceduralPointer;
namespace gpu { class Batch; }
namespace model {
@ -36,13 +37,13 @@ public:
void setCubemap(const gpu::TexturePointer& cubemap);
const gpu::TexturePointer& getCubemap() const { return _cubemap; }
// void setProcedural(QSharedPointer<Procedural> procedural);
void setProcedural(const ProceduralPointer& procedural);
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox);
protected:
gpu::TexturePointer _cubemap;
// QSharedPointer<Procedural> _procedural;
ProceduralPointer _procedural;
Color _color{1.0f, 1.0f, 1.0f};
};
typedef std::shared_ptr< Skybox > SkyboxPointer;

View file

@ -19,35 +19,9 @@
using namespace model;
using namespace gpu;
// TextureSource
TextureSource::TextureSource()
{/* : Texture::Storage()//,
// _gpuTexture(Texture::createFromStorage(this))*/
}
TextureSource::~TextureSource() {
}
void TextureSource::reset(const QUrl& url, const TextureUsage& usage) {
_imageUrl = url;
_usage = usage;
}
void TextureSource::resetTexture(gpu::Texture* texture) {
_gpuTexture.reset(texture);
}
bool TextureSource::isDefined() const {
if (_gpuTexture) {
return _gpuTexture->isDefined();
} else {
return false;
}
}
void TextureMap::setTextureSource(TextureSourcePointer& texStorage) {
_textureSource = texStorage;
void TextureMap::setTextureSource(TextureSourcePointer& textureSource) {
_textureSource = textureSource;
}
bool TextureMap::isDefined() const {
@ -78,7 +52,7 @@ void TextureMap::setLightmapOffsetScale(float offset, float scale) {
gpu::Texture* TextureSource::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = srcImage;
int imageArea = image.width() * image.height();
@ -175,7 +149,7 @@ double mapComponent(double sobelValue) {
return (sobelValue + 1.0) * factor;
}
gpu::Texture* TextureSource::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) {
gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = srcImage;
// PR 5540 by AlessandroSigna
@ -285,7 +259,7 @@ public:
_faceZNeg(fZN) {}
};
gpu::Texture* TextureSource::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
QImage image = srcImage;
int imageArea = image.width() * image.height();

View file

@ -30,36 +30,11 @@ public:
Material::MapFlags _materialUsage{ MaterialKey::DIFFUSE_MAP };
int _environmentUsage = 0;
};
// TextureSource is a specialized version of the gpu::Texture::Storage
// It provides the mechanism to create a texture from a Url and the intended usage
// that guides the internal format used
class TextureSource {
public:
TextureSource();
~TextureSource();
const QUrl& getUrl() const { return _imageUrl; }
gpu::Texture::Type getType() const { return _usage._type; }
const gpu::TexturePointer getGPUTexture() const { return _gpuTexture; }
void reset(const QUrl& url, const TextureUsage& usage);
void resetTexture(gpu::Texture* texture);
bool isDefined() const;
static gpu::Texture* create2DTextureFromImage(const QImage& image, const std::string& srcImageName);
static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName);
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
protected:
gpu::TexturePointer _gpuTexture;
TextureUsage _usage;
QUrl _imageUrl;
};
typedef std::shared_ptr< TextureSource > TextureSourcePointer;
@ -67,7 +42,7 @@ class TextureMap {
public:
TextureMap() {}
void setTextureSource(TextureSourcePointer& texStorage);
void setTextureSource(gpu::TextureSourcePointer& textureSource);
bool isDefined() const;
gpu::TextureView getTextureView() const;
@ -79,7 +54,7 @@ public:
const glm::vec2& getLightmapOffsetScale() const { return _lightmapOffsetScale; }
protected:
TextureSourcePointer _textureSource;
gpu::TextureSourcePointer _textureSource;
Transform _texcoordTransform;
glm::vec2 _lightmapOffsetScale{ 0.0f, 1.0f };

View file

@ -1,5 +1,7 @@
set(TARGET_NAME procedural)
AUTOSCRIBE_SHADER_LIB(gpu model)
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
setup_hifi_library()
@ -7,4 +9,4 @@ add_dependency_external_projects(glm)
find_package(GLM REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
link_hifi_libraries(shared gpu networking gpu-networking)
link_hifi_libraries(shared gpu model model-networking)

View file

@ -14,7 +14,6 @@
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <gpu-networking/ShaderCache.h>
#include <gpu/Batch.h>
#include <SharedUtil.h>
#include <NumericalConstants.h>

View file

@ -18,8 +18,7 @@
#include <gpu/Shader.h>
#include <gpu/Pipeline.h>
#include <gpu/Batch.h>
#include <gpu-networking/ShaderCache.h>
#include <model-networking/ShaderCache.h>
// FIXME better encapsulation
// FIXME better mechanism for extending to things rendered using shaders other than simple.slv

View file

@ -0,0 +1,71 @@
//
// ProceduralSkybox.cpp
// libraries/procedural/src/procedural
//
// Created by Sam Gateau on 9/21/2015.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "ProceduralSkybox.h"
#include <gpu/Batch.h>
#include <gpu/Context.h>
#include <ViewFrustum.h>
#include "ProceduralSkybox_vert.h"
#include "ProceduralSkybox_frag.h"
ProceduralSkybox::ProceduralSkybox() : model::Skybox() {
}
void ProceduralSkybox::setProcedural(const ProceduralPointer& procedural) {
_procedural = procedural;
if (_procedural) {
_procedural->_vertexSource = ProceduralSkybox_vert;
_procedural->_fragmentSource = ProceduralSkybox_frag;
// No pipeline state customization
}
}
void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const ProceduralSkybox& skybox) {
static gpu::BufferPointer theBuffer;
static gpu::Stream::FormatPointer theFormat;
if (skybox._procedural || skybox.getCubemap()) {
if (!theBuffer) {
const float CLIP = 1.0f;
const glm::vec2 vertices[4] = { { -CLIP, -CLIP }, { CLIP, -CLIP }, { -CLIP, CLIP }, { CLIP, CLIP } };
theBuffer = std::make_shared<gpu::Buffer>(sizeof(vertices), (const gpu::Byte*) vertices);
theFormat = std::make_shared<gpu::Stream::Format>();
theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
}
glm::mat4 projMat;
viewFrustum.evalProjectionMatrix(projMat);
Transform viewTransform;
viewFrustum.evalViewTransform(viewTransform);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewTransform);
batch.setModelTransform(Transform()); // only for Mac
batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
batch.setInputFormat(theFormat);
if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) {
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
batch.setResourceTexture(0, skybox.getCubemap());
}
skybox._procedural->prepare(batch, glm::vec3(1));
batch.draw(gpu::TRIANGLE_STRIP, 4);
}
} else {
// skybox has no cubemap, just clear the color buffer
auto color = skybox.getColor();
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.0f, 0, true);
}
}

View file

@ -0,0 +1,35 @@
//
// ProceduralSkybox.h
// libraries/procedural/src/procedural
//
// Created by Sam Gateau on 9/21/15.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_ProceduralSkybox_h
#define hifi_ProceduralSkybox_h
#include <model/Skybox.h>
#include "Procedural.h"
class ProceduralSkybox: public model::Skybox {
public:
ProceduralSkybox();
ProceduralSkybox& operator= (const ProceduralSkybox& skybox);
virtual ~ProceduralSkybox() {};
void setProcedural(const ProceduralPointer& procedural);
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const ProceduralSkybox& skybox);
protected:
ProceduralPointer _procedural;
};
typedef std::shared_ptr< ProceduralSkybox > ProceduralSkyboxPointer;
#endif

View file

@ -0,0 +1,50 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// skybox.frag
// fragment shader
//
// Created by Sam Gateau on 5/5/2015.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
uniform samplerCube cubeMap;
struct Skybox {
vec4 _color;
};
uniform skyboxBuffer {
Skybox _skybox;
};
in vec3 _normal;
out vec4 _fragColor;
//PROCEDURAL_COMMON_BLOCK
#line 1001
//PROCEDURAL_BLOCK
#line 2033
void main(void) {
#ifdef PROCEDURAL
vec3 color = getSkyboxColor();
_fragColor = vec4(color, 0.0);
#else
vec3 coord = normalize(_normal);
vec3 texel = texture(cubeMap, coord).rgb;
vec3 color = texel * _skybox._color.rgb;
vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction
_fragColor = vec4(pixel, 0.0);
#endif
}

View file

@ -0,0 +1,34 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// skybox.vert
// vertex shader
//
// Created by Sam Gateau on 5/5/2015.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Inputs.slh@>
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
out vec3 _normal;
void main(void) {
// standard transform
TransformCamera cam = getTransformCamera();
vec3 clipDir = vec3(inPosition.xy, 0.0);
vec3 eyeDir;
<$transformClipToEyeDir(cam, clipDir, eyeDir)$>
<$transformEyeToWorldDir(cam, eyeDir, _normal)$>
// Position is supposed to come in clip space
gl_Position = vec4(inPosition.xy, 0.0, 1.0);
}

View file

@ -40,4 +40,4 @@ add_dependency_external_projects(oglplus)
find_package(OGLPLUS REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${OGLPLUS_INCLUDE_DIRS})
link_hifi_libraries(shared gpu gpu-networking procedural model render environment animation fbx)
link_hifi_libraries(shared gpu procedural model model-networking render environment animation fbx)

View file

@ -38,8 +38,6 @@ const int GeometryCache::UNKNOWN_ID = -1;
GeometryCache::GeometryCache() :
_nextID(0)
{
const qint64 GEOMETRY_DEFAULT_UNUSED_MAX_SIZE = DEFAULT_UNUSED_MAX_SIZE;
setUnusedResourceCacheSize(GEOMETRY_DEFAULT_UNUSED_MAX_SIZE);
}
GeometryCache::~GeometryCache() {
@ -51,13 +49,6 @@ GeometryCache::~GeometryCache() {
#endif //def WANT_DEBUG
}
QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
bool delayLoad, const void* extra) {
// NetworkGeometry is no longer a subclass of Resource, but requires this method because, it is pure virtual.
assert(false);
return QSharedPointer<Resource>();
}
const int NUM_VERTICES_PER_TRIANGLE = 3;
const int NUM_TRIANGLES_PER_QUAD = 2;
const int NUM_VERTICES_PER_TRIANGULATED_QUAD = NUM_VERTICES_PER_TRIANGLE * NUM_TRIANGLES_PER_QUAD;
@ -1713,463 +1704,3 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) {
batch.setPipeline(_standardDrawPipeline);
}
}
GeometryReader::GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping) :
_url(url),
_data(data),
_mapping(mapping) {
}
void GeometryReader::run() {
try {
if (_data.isEmpty()) {
throw QString("Reply is NULL ?!");
}
QString urlname = _url.path().toLower();
bool urlValid = true;
urlValid &= !urlname.isEmpty();
urlValid &= !_url.path().isEmpty();
urlValid &= _url.path().toLower().endsWith(".fbx") || _url.path().toLower().endsWith(".obj");
if (urlValid) {
// Let's read the binaries from the network
FBXGeometry* fbxgeo = nullptr;
if (_url.path().toLower().endsWith(".fbx")) {
const bool grabLightmaps = true;
const float lightmapLevel = 1.0f;
fbxgeo = readFBX(_data, _mapping, _url.path(), grabLightmaps, lightmapLevel);
} else if (_url.path().toLower().endsWith(".obj")) {
fbxgeo = OBJReader().readOBJ(_data, _mapping, _url);
} else {
QString errorStr("usupported format");
emit onError(NetworkGeometry::ModelParseError, errorStr);
}
emit onSuccess(fbxgeo);
} else {
throw QString("url is invalid");
}
} catch (const QString& error) {
qCDebug(renderutils) << "Error reading " << _url << ": " << error;
emit onError(NetworkGeometry::ModelParseError, error);
}
}
NetworkGeometry::NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl) :
_url(url),
_mapping(mapping),
_textureBaseUrl(textureBaseUrl.isValid() ? textureBaseUrl : url) {
if (delayLoad) {
_state = DelayState;
} else {
attemptRequestInternal();
}
}
NetworkGeometry::~NetworkGeometry() {
if (_resource) {
_resource->deleteLater();
}
}
void NetworkGeometry::attemptRequest() {
if (_state == DelayState) {
attemptRequestInternal();
}
}
void NetworkGeometry::attemptRequestInternal() {
if (_url.path().toLower().endsWith(".fst")) {
_mappingUrl = _url;
requestMapping(_url);
} else {
_modelUrl = _url;
requestModel(_url);
}
}
bool NetworkGeometry::isLoaded() const {
return _state == SuccessState;
}
bool NetworkGeometry::isLoadedWithTextures() const {
if (!isLoaded()) {
return false;
}
if (!_isLoadedWithTextures) {
for (auto&& material : _materials) {
if ((material->diffuseTexture && !material->diffuseTexture->isLoaded()) ||
(material->normalTexture && !material->normalTexture->isLoaded()) ||
(material->specularTexture && !material->specularTexture->isLoaded()) ||
(material->emissiveTexture && !material->emissiveTexture->isLoaded())) {
return false;
}
}
_isLoadedWithTextures = true;
}
return true;
}
void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) {
if (_meshes.size() > 0) {
auto textureCache = DependencyManager::get<TextureCache>();
for (auto&& material : _materials) {
QSharedPointer<NetworkTexture> matchingTexture = QSharedPointer<NetworkTexture>();
if (material->diffuseTextureName == name) {
material->diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE);
} else if (material->normalTextureName == name) {
material->normalTexture = textureCache->getTexture(url);
} else if (material->specularTextureName == name) {
material->specularTexture = textureCache->getTexture(url);
} else if (material->emissiveTextureName == name) {
material->emissiveTexture = textureCache->getTexture(url);
}
}
} else {
qCWarning(renderutils) << "Ignoring setTextureWirthNameToURL() geometry not ready." << name << url;
}
_isLoadedWithTextures = false;
}
QStringList NetworkGeometry::getTextureNames() const {
QStringList result;
for (auto&& material : _materials) {
if (!material->diffuseTextureName.isEmpty() && material->diffuseTexture) {
QString textureURL = material->diffuseTexture->getURL().toString();
result << material->diffuseTextureName + ":" + textureURL;
}
if (!material->normalTextureName.isEmpty() && material->normalTexture) {
QString textureURL = material->normalTexture->getURL().toString();
result << material->normalTextureName + ":" + textureURL;
}
if (!material->specularTextureName.isEmpty() && material->specularTexture) {
QString textureURL = material->specularTexture->getURL().toString();
result << material->specularTextureName + ":" + textureURL;
}
if (!material->emissiveTextureName.isEmpty() && material->emissiveTexture) {
QString textureURL = material->emissiveTexture->getURL().toString();
result << material->emissiveTextureName + ":" + textureURL;
}
}
return result;
}
void NetworkGeometry::requestMapping(const QUrl& url) {
_state = RequestMappingState;
if (_resource) {
_resource->deleteLater();
}
_resource = new Resource(url, false);
connect(_resource, &Resource::loaded, this, &NetworkGeometry::mappingRequestDone);
connect(_resource, &Resource::failed, this, &NetworkGeometry::mappingRequestError);
}
void NetworkGeometry::requestModel(const QUrl& url) {
_state = RequestModelState;
if (_resource) {
_resource->deleteLater();
}
_modelUrl = url;
_resource = new Resource(url, false);
connect(_resource, &Resource::loaded, this, &NetworkGeometry::modelRequestDone);
connect(_resource, &Resource::failed, this, &NetworkGeometry::modelRequestError);
}
void NetworkGeometry::mappingRequestDone(const QByteArray& data) {
assert(_state == RequestMappingState);
// parse the mapping file
_mapping = FSTReader::readMapping(data);
QUrl replyUrl = _mappingUrl;
QString modelUrlStr = _mapping.value("filename").toString();
if (modelUrlStr.isNull()) {
qCDebug(renderutils) << "Mapping file " << _url << "has no \"filename\" entry";
emit onFailure(*this, MissingFilenameInMapping);
} else {
// read _textureBase from mapping file, if present
QString texdir = _mapping.value("texdir").toString();
if (!texdir.isNull()) {
if (!texdir.endsWith('/')) {
texdir += '/';
}
_textureBaseUrl = replyUrl.resolved(texdir);
}
_modelUrl = replyUrl.resolved(modelUrlStr);
requestModel(_modelUrl);
}
}
void NetworkGeometry::mappingRequestError(QNetworkReply::NetworkError error) {
assert(_state == RequestMappingState);
_state = ErrorState;
emit onFailure(*this, MappingRequestError);
}
void NetworkGeometry::modelRequestDone(const QByteArray& data) {
assert(_state == RequestModelState);
_state = ParsingModelState;
// asynchronously parse the model file.
GeometryReader* geometryReader = new GeometryReader(_modelUrl, data, _mapping);
connect(geometryReader, SIGNAL(onSuccess(FBXGeometry*)), SLOT(modelParseSuccess(FBXGeometry*)));
connect(geometryReader, SIGNAL(onError(int, QString)), SLOT(modelParseError(int, QString)));
QThreadPool::globalInstance()->start(geometryReader);
}
void NetworkGeometry::modelRequestError(QNetworkReply::NetworkError error) {
assert(_state == RequestModelState);
_state = ErrorState;
emit onFailure(*this, ModelRequestError);
}
static NetworkMesh* buildNetworkMesh(const FBXMesh& mesh, const QUrl& textureBaseUrl) {
auto textureCache = DependencyManager::get<TextureCache>();
NetworkMesh* networkMesh = new NetworkMesh();
int totalIndices = 0;
bool checkForTexcoordLightmap = false;
// process network parts
foreach (const FBXMeshPart& part, mesh.parts) {
totalIndices += (part.quadIndices.size() + part.triangleIndices.size());
}
// initialize index buffer
{
networkMesh->_indexBuffer = std::make_shared<gpu::Buffer>();
networkMesh->_indexBuffer->resize(totalIndices * sizeof(int));
int offset = 0;
foreach(const FBXMeshPart& part, mesh.parts) {
networkMesh->_indexBuffer->setSubData(offset, part.quadIndices.size() * sizeof(int),
(gpu::Byte*) part.quadIndices.constData());
offset += part.quadIndices.size() * sizeof(int);
networkMesh->_indexBuffer->setSubData(offset, part.triangleIndices.size() * sizeof(int),
(gpu::Byte*) part.triangleIndices.constData());
offset += part.triangleIndices.size() * sizeof(int);
}
}
// initialize vertex buffer
{
networkMesh->_vertexBuffer = std::make_shared<gpu::Buffer>();
// if we don't need to do any blending, the positions/normals can be static
if (mesh.blendshapes.isEmpty()) {
int normalsOffset = mesh.vertices.size() * sizeof(glm::vec3);
int tangentsOffset = normalsOffset + mesh.normals.size() * sizeof(glm::vec3);
int colorsOffset = tangentsOffset + mesh.tangents.size() * sizeof(glm::vec3);
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
int texCoords1Offset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
int clusterIndicesOffset = texCoords1Offset + mesh.texCoords1.size() * sizeof(glm::vec2);
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
networkMesh->_vertexBuffer->setSubData(0, mesh.vertices.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.vertices.constData());
networkMesh->_vertexBuffer->setSubData(normalsOffset, mesh.normals.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.normals.constData());
networkMesh->_vertexBuffer->setSubData(tangentsOffset,
mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
networkMesh->_vertexBuffer->setSubData(texCoords1Offset,
mesh.texCoords1.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords1.constData());
networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
// otherwise, at least the cluster indices/weights can be static
networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
if (mesh.normals.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, normalsOffset, sizeof(glm::vec3));
if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, tangentsOffset, sizeof(glm::vec3));
if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
if (mesh.texCoords1.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoords1Offset, sizeof(glm::vec2));
if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
int channelNum = 0;
networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
if (mesh.texCoords1.size()) {
networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
// } else if (checkForTexcoordLightmap && mesh.texCoords.size()) {
} else if (mesh.texCoords.size()) {
// need lightmap texcoord UV but doesn't have uv#1 so just reuse the same channel
networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, channelNum - 1, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
}
if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
}
else {
int colorsOffset = mesh.tangents.size() * sizeof(glm::vec3);
int texCoordsOffset = colorsOffset + mesh.colors.size() * sizeof(glm::vec3);
int clusterIndicesOffset = texCoordsOffset + mesh.texCoords.size() * sizeof(glm::vec2);
int clusterWeightsOffset = clusterIndicesOffset + mesh.clusterIndices.size() * sizeof(glm::vec4);
networkMesh->_vertexBuffer->resize(clusterWeightsOffset + mesh.clusterWeights.size() * sizeof(glm::vec4));
networkMesh->_vertexBuffer->setSubData(0, mesh.tangents.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.tangents.constData());
networkMesh->_vertexBuffer->setSubData(colorsOffset, mesh.colors.size() * sizeof(glm::vec3), (gpu::Byte*) mesh.colors.constData());
networkMesh->_vertexBuffer->setSubData(texCoordsOffset,
mesh.texCoords.size() * sizeof(glm::vec2), (gpu::Byte*) mesh.texCoords.constData());
networkMesh->_vertexBuffer->setSubData(clusterIndicesOffset,
mesh.clusterIndices.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterIndices.constData());
networkMesh->_vertexBuffer->setSubData(clusterWeightsOffset,
mesh.clusterWeights.size() * sizeof(glm::vec4), (gpu::Byte*) mesh.clusterWeights.constData());
networkMesh->_vertexStream = std::make_shared<gpu::BufferStream>();
if (mesh.tangents.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, 0, sizeof(glm::vec3));
if (mesh.colors.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, colorsOffset, sizeof(glm::vec3));
if (mesh.texCoords.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, texCoordsOffset, sizeof(glm::vec2));
if (mesh.clusterIndices.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterIndicesOffset, sizeof(glm::vec4));
if (mesh.clusterWeights.size()) networkMesh->_vertexStream->addBuffer(networkMesh->_vertexBuffer, clusterWeightsOffset, sizeof(glm::vec4));
int channelNum = 0;
networkMesh->_vertexFormat = std::make_shared<gpu::Stream::Format>();
networkMesh->_vertexFormat->setAttribute(gpu::Stream::POSITION, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.normals.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::NORMAL, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.tangents.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TANGENT, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ));
if (mesh.colors.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::COLOR, channelNum++, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::RGB));
if (mesh.texCoords.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, channelNum++, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV));
if (mesh.clusterIndices.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
if (mesh.clusterWeights.size()) networkMesh->_vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, channelNum++, gpu::Element(gpu::VEC4, gpu::NFLOAT, gpu::XYZW));
}
}
return networkMesh;
}
static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) {
auto textureCache = DependencyManager::get<TextureCache>();
NetworkMaterial* networkMaterial = new NetworkMaterial();
int totalIndices = 0;
bool checkForTexcoordLightmap = false;
networkMaterial->_material = material._material;
if (!material.diffuseTexture.filename.isEmpty()) {
networkMaterial->diffuseTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.diffuseTexture.filename)), DEFAULT_TEXTURE, material.diffuseTexture.content);
networkMaterial->diffuseTextureName = material.diffuseTexture.name;
auto diffuseMap = model::TextureMapPointer(new model::TextureMap());
diffuseMap->setTextureSource(networkMaterial->diffuseTexture->_textureSource);
diffuseMap->setTextureTransform(material.diffuseTexture.transform);
material._material->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap);
}
if (!material.normalTexture.filename.isEmpty()) {
networkMaterial->normalTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.normalTexture.filename)), (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), material.normalTexture.content);
networkMaterial->normalTextureName = material.normalTexture.name;
auto normalMap = model::TextureMapPointer(new model::TextureMap());
normalMap->setTextureSource(networkMaterial->normalTexture->_textureSource);
material._material->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap);
}
if (!material.specularTexture.filename.isEmpty()) {
networkMaterial->specularTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.specularTexture.filename)), SPECULAR_TEXTURE, material.specularTexture.content);
networkMaterial->specularTextureName = material.specularTexture.name;
auto glossMap = model::TextureMapPointer(new model::TextureMap());
glossMap->setTextureSource(networkMaterial->specularTexture->_textureSource);
material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap);
}
if (!material.emissiveTexture.filename.isEmpty()) {
networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content);
networkMaterial->emissiveTextureName = material.emissiveTexture.name;
checkForTexcoordLightmap = true;
auto lightmapMap = model::TextureMapPointer(new model::TextureMap());
lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource);
lightmapMap->setTextureTransform(material.emissiveTexture.transform);
lightmapMap->setLightmapOffsetScale(material.emissiveParams.x, material.emissiveParams.y);
material._material->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap);
}
return networkMaterial;
}
void NetworkGeometry::modelParseSuccess(FBXGeometry* geometry) {
// assume owner ship of geometry pointer
_geometry.reset(geometry);
foreach(const FBXMesh& mesh, _geometry->meshes) {
_meshes.emplace_back(buildNetworkMesh(mesh, _textureBaseUrl));
}
QHash<QString, int> fbxMatIDToMatID;
foreach(const FBXMaterial& material, _geometry->materials) {
fbxMatIDToMatID[material.materialID] = _materials.size();
_materials.emplace_back(buildNetworkMaterial(material, _textureBaseUrl));
}
int meshID = 0;
foreach(const FBXMesh& mesh, _geometry->meshes) {
int partID = 0;
foreach (const FBXMeshPart& part, mesh.parts) {
NetworkShape* networkShape = new NetworkShape();
networkShape->_meshID = meshID;
networkShape->_partID = partID;
networkShape->_materialID = fbxMatIDToMatID[part.materialID];
_shapes.emplace_back(networkShape);
partID++;
}
meshID++;
}
_state = SuccessState;
emit onSuccess(*this, *_geometry.get());
delete _resource;
_resource = nullptr;
}
void NetworkGeometry::modelParseError(int error, QString str) {
_state = ErrorState;
emit onFailure(*this, (NetworkGeometry::Error)error);
delete _resource;
_resource = nullptr;
}
const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) {
if ((shapeID >= 0) && (shapeID < _shapes.size())) {
int materialID = _shapes[shapeID]->_materialID;
if ((materialID >= 0) && (materialID < _materials.size())) {
return _materials[materialID].get();
} else {
return 0;
}
} else {
return 0;
}
}

View file

@ -12,14 +12,12 @@
#ifndef hifi_GeometryCache_h
#define hifi_GeometryCache_h
#include "model-networking/ModelCache.h"
#include <QMap>
#include <QRunnable>
#include <DependencyManager.h>
#include <ResourceCache.h>
#include "FBXReader.h"
#include "OBJReader.h"
#include <gpu/Batch.h>
#include <gpu/Stream.h>
@ -28,13 +26,6 @@
#include <model/Material.h>
#include <model/Asset.h>
class NetworkGeometry;
class NetworkMesh;
class NetworkTexture;
class NetworkMaterial;
class NetworkShape;
typedef glm::vec3 Vec3Key;
typedef QPair<glm::vec2, glm::vec2> Vec2Pair;
@ -125,17 +116,13 @@ inline uint qHash(const Vec4PairVec4Pair& v, uint seed) {
}
/// Stores cached geometry.
class GeometryCache : public ResourceCache, public Dependency {
Q_OBJECT
class GeometryCache : public Dependency {
SINGLETON_DEPENDENCY
public:
int allocateID() { return _nextID++; }
static const int UNKNOWN_ID;
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback,
bool delayLoad, const void* extra);
gpu::BufferPointer getCubeVertices(float size);
void setupCubeVertices(gpu::Batch& batch, gpu::BufferPointer& verticesBuffer);
@ -313,152 +300,6 @@ private:
QHash<Vec3Pair, gpu::BufferPointer> _sphereColors;
QHash<int, gpu::BufferPointer> _registeredSphereColors;
QHash<int, Vec3Pair> _lastRegisteredSphereColors;
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
};
class NetworkGeometry : public QObject {
Q_OBJECT
public:
// mapping is only used if url is a .fbx or .obj file, it is essentially the content of an fst file.
// if delayLoad is true, the url will not be immediately downloaded.
// use the attemptRequest method to initiate the download.
NetworkGeometry(const QUrl& url, bool delayLoad, const QVariantHash& mapping, const QUrl& textureBaseUrl = QUrl());
~NetworkGeometry();
const QUrl& getURL() const { return _url; }
void attemptRequest();
// true when the geometry is loaded (but maybe not it's associated textures)
bool isLoaded() const;
// true when the requested geometry and its textures are loaded.
bool isLoadedWithTextures() const;
// WARNING: only valid when isLoaded returns true.
const FBXGeometry& getFBXGeometry() const { return *_geometry; }
const std::vector<std::unique_ptr<NetworkMesh>>& getMeshes() const { return _meshes; }
// const model::AssetPointer getAsset() const { return _asset; }
// model::MeshPointer getShapeMesh(int shapeID);
// int getShapePart(int shapeID);
// This would be the final verison
// model::MaterialPointer getShapeMaterial(int shapeID);
const NetworkMaterial* getShapeMaterial(int shapeID);
void setTextureWithNameToURL(const QString& name, const QUrl& url);
QStringList getTextureNames() const;
enum Error {
MissingFilenameInMapping = 0,
MappingRequestError,
ModelRequestError,
ModelParseError
};
signals:
// Fired when everything has downloaded and parsed successfully.
void onSuccess(NetworkGeometry& networkGeometry, FBXGeometry& fbxGeometry);
// Fired when something went wrong.
void onFailure(NetworkGeometry& networkGeometry, Error error);
protected slots:
void mappingRequestDone(const QByteArray& data);
void mappingRequestError(QNetworkReply::NetworkError error);
void modelRequestDone(const QByteArray& data);
void modelRequestError(QNetworkReply::NetworkError error);
void modelParseSuccess(FBXGeometry* geometry);
void modelParseError(int error, QString str);
protected:
void attemptRequestInternal();
void requestMapping(const QUrl& url);
void requestModel(const QUrl& url);
enum State { DelayState,
RequestMappingState,
RequestModelState,
ParsingModelState,
SuccessState,
ErrorState };
State _state;
QUrl _url;
QUrl _mappingUrl;
QUrl _modelUrl;
QVariantHash _mapping;
QUrl _textureBaseUrl;
Resource* _resource = nullptr;
std::unique_ptr<FBXGeometry> _geometry; // This should go away evenutally once we can put everything we need in the model::AssetPointer
std::vector<std::unique_ptr<NetworkMesh>> _meshes;
std::vector<std::unique_ptr<NetworkMaterial>> _materials;
std::vector<std::unique_ptr<NetworkShape>> _shapes;
// The model asset created from this NetworkGeometry
// model::AssetPointer _asset;
// cache for isLoadedWithTextures()
mutable bool _isLoadedWithTextures = false;
};
/// Reads geometry in a worker thread.
class GeometryReader : public QObject, public QRunnable {
Q_OBJECT
public:
GeometryReader(const QUrl& url, const QByteArray& data, const QVariantHash& mapping);
virtual void run();
signals:
void onSuccess(FBXGeometry* geometry);
void onError(int error, QString str);
private:
QUrl _url;
QByteArray _data;
QVariantHash _mapping;
};
class NetworkShape {
public:
int _meshID{ -1 };
int _partID{ -1 };
int _materialID{ -1 };
};
class NetworkMaterial {
public:
model::MaterialPointer _material;
QString diffuseTextureName;
QSharedPointer<NetworkTexture> diffuseTexture;
QString normalTextureName;
QSharedPointer<NetworkTexture> normalTexture;
QString specularTextureName;
QSharedPointer<NetworkTexture> specularTexture;
QString emissiveTextureName;
QSharedPointer<NetworkTexture> emissiveTexture;
};
/// The state associated with a single mesh.
class NetworkMesh {
public:
gpu::BufferPointer _indexBuffer;
gpu::BufferPointer _vertexBuffer;
gpu::BufferStreamPointer _vertexStream;
gpu::Stream::FormatPointer _vertexFormat;
int getTranslucentPartCount(const FBXMesh& fbxMesh) const;
bool isPartTranslucent(const FBXMesh& fbxMesh, int partIndex) const;
};
#endif // hifi_GeometryCache_h

View file

@ -1,2 +1,2 @@
// Compatibility
#include <gpu-networking/TextureCache.h>
#include <model-networking/TextureCache.h>

View file

@ -7,4 +7,4 @@ add_dependency_external_projects(glm)
find_package(GLM REQUIRED)
target_include_directories(${TARGET_NAME} PUBLIC ${GLM_INCLUDE_DIRS})
link_hifi_libraries(shared networking octree gpu gpu-networking procedural model fbx entities animation audio physics)
link_hifi_libraries(shared networking octree gpu procedural model model-networking fbx entities animation audio physics)

View file

@ -10,6 +10,6 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
#include_oglplus()
# link in the shared libraries
link_hifi_libraries(networking gpu gpu-networking procedural shared fbx model animation script-engine render-utils )
link_hifi_libraries(networking gpu procedural shared fbx model model-networking animation script-engine render-utils )
copy_dlls_beside_windows_executable()