Move skinning shader features in its own slh and get ready for moving cluster matrices to uniform buffer

This commit is contained in:
samcake 2015-10-05 18:31:05 -07:00
parent 9e393ced46
commit 12fedb6ff0
12 changed files with 731 additions and 935 deletions

View file

@ -134,6 +134,7 @@ public:
BufferStream();
~BufferStream();
void clear() { _buffers.clear(); _offsets.clear(); _strides.clear(); }
void addBuffer(const BufferPointer& buffer, Offset offset, Offset stride);
const Buffers& getBuffers() const { return _buffers; }

View file

@ -64,6 +64,24 @@ void Mesh::evalVertexFormat() {
}
_vertexFormat.reset(vf);
evalVertexStream();
}
void Mesh::evalVertexStream() {
_vertexStream.clear();
int channelNum = 0;
if (hasVertexData()) {
_vertexStream.addBuffer(_vertexBuffer._buffer, _vertexBuffer._offset, _vertexFormat->getChannelStride(channelNum));
channelNum++;
}
for (auto attrib : _attributeBuffers) {
BufferView& view = attrib.second;
_vertexStream.addBuffer(view._buffer, view._offset, _vertexFormat->getChannelStride(channelNum));
channelNum++;
}
}
void Mesh::setIndexBuffer(const BufferView& buffer) {
@ -116,23 +134,6 @@ const Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const
return totalBound;
}
const gpu::BufferStream Mesh::makeBufferStream() const {
gpu::BufferStream stream;
int channelNum = 0;
if (hasVertexData()) {
stream.addBuffer(_vertexBuffer._buffer, _vertexBuffer._offset, _vertexFormat->getChannelStride(channelNum));
channelNum++;
}
for (auto attrib : _attributeBuffers) {
BufferView& view = attrib.second;
stream.addBuffer(view._buffer, view._offset, _vertexFormat->getChannelStride(channelNum));
channelNum++;
}
return stream;
}
Geometry::Geometry() {
}

View file

@ -57,6 +57,9 @@ public:
// Stream format
const gpu::Stream::FormatPointer getVertexFormat() const { return _vertexFormat; }
// BufferStream on the mesh vertices and attributes matching the vertex format
const gpu::BufferStream getVertexStream() const { return _vertexStream; }
// Index Buffer
void setIndexBuffer(const BufferView& buffer);
const BufferView& getIndexBuffer() const { return _indexBuffer; }
@ -109,15 +112,12 @@ public:
// the returned box is the bounding box of ALL the evaluated part bounds.
const Box evalPartBounds(int partStart, int partEnd, Boxes& bounds) const;
// Generate a BufferStream on the mesh vertices and attributes
const gpu::BufferStream makeBufferStream() const;
static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast<gpu::Primitive>(topo); }
protected:
gpu::Stream::FormatPointer _vertexFormat;
gpu::BufferStream _vertexStream;
BufferView _vertexBuffer;
BufferViewMap _attributeBuffers;
@ -127,6 +127,7 @@ protected:
BufferView _partBuffer;
void evalVertexFormat();
void evalVertexStream();
};
typedef std::shared_ptr< Mesh > MeshPointer;

View file

@ -887,7 +887,7 @@ model::MeshPointer DeferredLightingEffect::getSpotLightMesh() {
_spotLightMesh->setPartBuffer(gpu::BufferView(new gpu::Buffer(sizeof(part), (gpu::Byte*) &part), gpu::Element::PART_DRAWCALL));
_spotLightMesh->makeBufferStream();
_spotLightMesh->getVertexStream();
}
return _spotLightMesh;
}

View file

@ -27,26 +27,6 @@
#include "Model.h"
#include "ModelRenderPayload.h"
#include "model_vert.h"
#include "model_shadow_vert.h"
#include "model_normal_map_vert.h"
#include "model_lightmap_vert.h"
#include "model_lightmap_normal_map_vert.h"
#include "skin_model_vert.h"
#include "skin_model_shadow_vert.h"
#include "skin_model_normal_map_vert.h"
#include "model_frag.h"
#include "model_shadow_frag.h"
#include "model_normal_map_frag.h"
#include "model_normal_specular_map_frag.h"
#include "model_specular_map_frag.h"
#include "model_lightmap_frag.h"
#include "model_lightmap_normal_map_frag.h"
#include "model_lightmap_normal_specular_map_frag.h"
#include "model_lightmap_specular_map_frag.h"
#include "model_translucent_frag.h"
#include "RenderUtilsLogging.h"
using namespace std;
@ -92,112 +72,6 @@ Model::~Model() {
deleteGeometry();
}
Model::RenderPipelineLib Model::_renderPipelineLib;
const int MATERIAL_GPU_SLOT = 3;
const int DIFFUSE_MAP_SLOT = 0;
const int NORMAL_MAP_SLOT = 1;
const int SPECULAR_MAP_SLOT = 2;
const int LIGHTMAP_MAP_SLOT = 3;
const int LIGHT_BUFFER_SLOT = 4;
void Model::RenderPipelineLib::addRenderPipeline(Model::RenderKey key,
gpu::ShaderPointer& vertexShader,
gpu::ShaderPointer& pixelShader ) {
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), DIFFUSE_MAP_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), NORMAL_MAP_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), SPECULAR_MAP_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), LIGHTMAP_MAP_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_BUFFER_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT));
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader));
gpu::Shader::makeProgram(*program, slotBindings);
auto locations = std::make_shared<Locations>();
initLocations(program, *locations);
auto state = std::make_shared<gpu::State>();
// Backface on shadow
if (key.isShadow()) {
state->setCullMode(gpu::State::CULL_FRONT);
state->setDepthBias(1.0f);
state->setDepthBiasSlopeScale(4.0f);
} else {
state->setCullMode(gpu::State::CULL_BACK);
}
// Z test depends if transparent or not
state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL);
// Blend on transparent
state->setBlendFunction(key.isTranslucent(),
gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, // For transparent only, this keep the highlight intensity
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
// Good to go add the brand new pipeline
auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations)));
if (!key.isWireFrame()) {
RenderKey wireframeKey(key.getRaw() | RenderKey::IS_WIREFRAME);
auto wireframeState = std::make_shared<gpu::State>(state->getValues());
wireframeState->setFillMode(gpu::State::FILL_LINE);
// create a new RenderPipeline with the same shader side and the mirrorState
auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState));
insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations)));
}
// If not a shadow pass, create the mirror version from the same state, just change the FrontFace
if (!key.isShadow()) {
RenderKey mirrorKey(key.getRaw() | RenderKey::IS_MIRROR);
auto mirrorState = std::make_shared<gpu::State>(state->getValues());
// create a new RenderPipeline with the same shader side and the mirrorState
auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState));
insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations)));
if (!key.isWireFrame()) {
RenderKey wireframeKey(key.getRaw() | RenderKey::IS_MIRROR | RenderKey::IS_WIREFRAME);
auto wireframeState = std::make_shared<gpu::State>(state->getValues());
wireframeState->setFillMode(gpu::State::FILL_LINE);
// create a new RenderPipeline with the same shader side and the mirrorState
auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState));
insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations)));
}
}
}
void Model::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, Model::Locations& locations) {
locations.alphaThreshold = program->getUniforms().findLocation("alphaThreshold");
locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices");
locations.emissiveParams = program->getUniforms().findLocation("emissiveParams");
locations.glowIntensity = program->getUniforms().findLocation("glowIntensity");
locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
locations.diffuseTextureUnit = program->getTextures().findLocation("diffuseMap");
locations.normalTextureUnit = program->getTextures().findLocation("normalMap");
locations.specularTextureUnit = program->getTextures().findLocation("specularMap");
locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer");
locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices");
locations.clusterIndices = program->getInputs().findLocation("inSkinClusterIndex");
locations.clusterWeights = program->getInputs().findLocation("inSkinClusterWeight");
}
AbstractViewStateInterface* Model::_viewState = NULL;
void Model::setTranslation(const glm::vec3& translation) {
@ -255,128 +129,6 @@ void Model::initJointTransforms() {
}
void Model::init() {
if (_renderPipelineLib.empty()) {
// Vertex shaders
auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert)));
auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert)));
auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert)));
auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)));
auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert)));
auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert)));
auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)));
auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert)));
// Pixel shaders
auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag)));
auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag)));
auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag)));
auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)));
auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag)));
auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag)));
auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag)));
auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)));
auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)));
auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)));
// Fill the renderPipelineLib
_renderPipelineLib.addRenderPipeline(
RenderKey(0),
modelVertex, modelPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_TANGENTS),
modelNormalMapVertex, modelNormalMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_SPECULAR),
modelVertex, modelSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR),
modelNormalMapVertex, modelNormalSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_TRANSLUCENT),
modelVertex, modelTranslucentPixel);
// FIXME Ignore lightmap for translucents meshpart
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP),
modelVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT),
modelNormalMapVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
modelVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
modelNormalMapVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_LIGHTMAP),
modelLightmapVertex, modelLightmapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS),
modelLightmapNormalMapVertex, modelLightmapNormalMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_SPECULAR),
modelLightmapVertex, modelLightmapSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR),
modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED),
skinModelVertex, modelPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS),
skinModelNormalMapVertex, modelNormalMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR),
skinModelVertex, modelSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR),
skinModelNormalMapVertex, modelNormalSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT),
skinModelVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT),
skinModelNormalMapVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
skinModelVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
skinModelNormalMapVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW),
modelShadowVertex, modelShadowPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW),
skinModelShadowVertex, modelShadowPixel);
}
}
void Model::reset() {
@ -416,6 +168,9 @@ bool Model::updateGeometry() {
MeshState state;
state.clusterMatrices.resize(mesh.clusters.size());
state.cauterizedClusterMatrices.resize(mesh.clusters.size());
if (mesh.clusters.size() > 1) {
state.clusterBuffer = std::make_shared<gpu::Buffer>(mesh.clusters.size() * sizeof(glm::mat4), nullptr);
}
_meshStates.append(state);
auto buffer = std::make_shared<gpu::Buffer>();
@ -1237,6 +992,7 @@ void Model::updateClusterMatrices() {
for (int i = 0; i < _meshStates.size(); i++) {
MeshState& state = _meshStates[i];
const FBXMesh& mesh = geometry.meshes.at(i);
for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j);
auto jointMatrix = _rig->getJointTransform(cluster.jointIndex);
@ -1250,6 +1006,17 @@ void Model::updateClusterMatrices() {
state.cauterizedClusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix;
}
}
// Once computed the cluster matrices, update the buffer
if (state.clusterBuffer) {
const float* bones;
if (_cauterizeBones) {
bones = (const float*)state.cauterizedClusterMatrices.constData();
} else {
bones = (const float*)state.clusterMatrices.constData();
}
state.clusterBuffer->setSubData(0, state.clusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) bones);
}
}
// post the blender if we're not currently waiting for one to finish
@ -1385,12 +1152,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
gpu::Batch& batch = *(args->_batch);
auto mode = args->_renderMode;
// Capture the view matrix once for the rendering of this model
if (_transforms.empty()) {
_transforms.push_back(Transform());
}
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
const FBXGeometry& geometry = _geometry->getFBXGeometry();
@ -1420,9 +1181,22 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
const MeshState& state = _meshStates.at(meshIndex);
auto drawMesh = networkMesh._mesh;
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
// to false to rebuild out mesh groups.
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) {
_meshGroupsKnown = false; // regenerate these lists next time around.
_readyWhenAdded = false; // in case any of our users are using scenes
invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
return; // FIXME!
}
int vertexCount = mesh.vertices.size();
if (vertexCount == 0) {
// sanity check
return; // FIXME!
}
auto drawMaterialKey = material->getKey();
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
@ -1459,76 +1233,13 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
}
Locations* locations = nullptr;
pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
ModelRender::Locations* locations = nullptr;
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
args, locations);
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
// to false to rebuild out mesh groups.
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) {
_meshGroupsKnown = false; // regenerate these lists next time around.
_readyWhenAdded = false; // in case any of our users are using scenes
invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
return; // FIXME!
}
int vertexCount = mesh.vertices.size();
if (vertexCount == 0) {
// sanity check
return; // FIXME!
}
payload->bindTransform(batch, locations);
// Transform stage
if (_transforms.empty()) {
_transforms.push_back(Transform());
}
if (isSkinned) {
const float* bones;
if (_cauterizeBones) {
bones = (const float*)state.cauterizedClusterMatrices.constData();
} else {
bones = (const float*)state.clusterMatrices.constData();
}
batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, bones);
_transforms[0] = Transform();
_transforms[0].preTranslate(_translation);
} else {
if (_cauterizeBones) {
_transforms[0] = Transform(state.cauterizedClusterMatrices[0]);
} else {
_transforms[0] = Transform(state.clusterMatrices[0]);
}
_transforms[0].preTranslate(_translation);
}
batch.setModelTransform(_transforms[0]);
auto drawPart = drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
/*
if (mesh.blendshapes.isEmpty()) {
batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((drawMesh->getVertexFormat()));
auto inputStream = drawMesh->makeBufferStream();
batch.setInputStream(0, inputStream);
} else {
batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((drawMesh->getVertexFormat()));
batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3));
auto inputStream = drawMesh->makeBufferStream().makeRangedStream(2);
batch.setInputStream(2, inputStream);
}
if (mesh.colors.isEmpty()) {
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
*/
payload->bindMesh(batch);
// guard against partially loaded meshes
@ -1544,104 +1255,18 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
#endif
{
// apply material properties
if (mode != RenderArgs::SHADOW_RENDER_MODE) {
#ifdef WANT_DEBUG
qCDebug(renderutils) << "Material Changed ---------------------------------------------";
qCDebug(renderutils) << "part INDEX:" << partIndex;
qCDebug(renderutils) << "NEW part.materialID:" << part.materialID;
#endif //def WANT_DEBUG
if (locations->materialBufferUnit >= 0) {
batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer());
}
auto materialKey = material->getKey();
auto textureMaps = material->getTextureMaps();
glm::mat4 texcoordTransform[2];
// Diffuse
if (materialKey.isDiffuseMap()) {
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
if (diffuseMap && diffuseMap->isDefined()) {
batch.setResourceTexture(DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
if (!diffuseMap->getTextureTransform().isIdentity()) {
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
}
} else {
batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
}
} else {
batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
}
// Normal map
if ((locations->normalTextureUnit >= 0) && hasTangents) {
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
if (normalMap && normalMap->isDefined()) {
batch.setResourceTexture(NORMAL_MAP_SLOT, normalMap->getTextureView());
// texcoord are assumed to be the same has diffuse
} else {
batch.setResourceTexture(NORMAL_MAP_SLOT, textureCache->getBlueTexture());
}
} else {
batch.setResourceTexture(NORMAL_MAP_SLOT, nullptr);
}
// TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that
if ((locations->specularTextureUnit >= 0) && materialKey.isGlossMap()) {
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
if (specularMap && specularMap->isDefined()) {
batch.setResourceTexture(SPECULAR_MAP_SLOT, specularMap->getTextureView());
// texcoord are assumed to be the same has diffuse
} else {
batch.setResourceTexture(SPECULAR_MAP_SLOT, textureCache->getBlackTexture());
}
} else {
batch.setResourceTexture(SPECULAR_MAP_SLOT, nullptr);
}
// TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too
if ((locations->emissiveTextureUnit >= 0) && materialKey.isLightmapMap()) {
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
if (lightmapMap && lightmapMap->isDefined()) {
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView());
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
if (!lightmapMap->getTextureTransform().isIdentity()) {
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
}
}
else {
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture());
}
} else {
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, nullptr);
}
// Texcoord transforms ?
if (locations->texcoordMatrices >= 0) {
batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform);
}
// TODO: We should be able to do that just in the renderTransparentJob
if (translucentMesh && locations->lightBufferUnit >= 0) {
PerformanceTimer perfTimer("DLE->setupTransparent()");
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
}
payload->bindMaterial(batch, locations);
if (args) {
args->_details._materialSwitches++;
}
// TODO: We should be able to do that just in the renderTransparentJob
if (translucentMesh && locations->lightBufferUnit >= 0) {
PerformanceTimer perfTimer("DLE->setupTransparent()");
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
}
if (args) {
args->_details._materialSwitches++;
}
}
@ -1652,7 +1277,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
if (args) {
const int INDICES_PER_TRIANGLE = 3;
args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE;
args->_details._trianglesRendered += payload->_drawPart._numIndices / INDICES_PER_TRIANGLE;
}
}
@ -1684,46 +1309,6 @@ void Model::segregateMeshGroups() {
_meshGroupsKnown = true;
}
void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold,
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args,
Locations*& locations) {
PerformanceTimer perfTimer("Model::pickPrograms");
RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe);
if (mode == RenderArgs::MIRROR_RENDER_MODE) {
key = RenderKey(key.getRaw() | RenderKey::IS_MIRROR);
}
auto pipeline = _renderPipelineLib.find(key.getRaw());
if (pipeline == _renderPipelineLib.end()) {
qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw();
locations = 0;
return;
}
gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram();
locations = (*pipeline).second._locations.get();
// Setup the One pipeline
batch.setPipeline((*pipeline).second._pipeline);
if ((locations->alphaThreshold > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) {
batch._glUniform1f(locations->alphaThreshold, alphaThreshold);
}
if ((locations->glowIntensity > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) {
const float DEFAULT_GLOW_INTENSITY = 1.0f; // FIXME - glow is removed
batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY);
}
if ((locations->normalFittingMapUnit > -1)) {
batch.setResourceTexture(locations->normalFittingMapUnit,
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
}
}
bool Model::initWhenReady(render::ScenePointer scene) {
if (isActive() && isRenderable() && !_meshGroupsKnown && isLoaded()) {
segregateMeshGroups();

View file

@ -47,6 +47,7 @@ namespace render {
typedef unsigned int ItemID;
}
class MeshPartPayload;
class ModelRenderLocations;
inline uint qHash(const std::shared_ptr<MeshPartPayload>& a, uint seed) {
return qHash(a.get(), seed);
@ -257,6 +258,7 @@ protected:
public:
QVector<glm::mat4> clusterMatrices;
QVector<glm::mat4> cauterizedClusterMatrices;
gpu::BufferPointer clusterBuffer;
};
QVector<MeshState> _meshStates;
@ -323,8 +325,6 @@ private:
bool _isVisible;
gpu::Buffers _blendedVertexBuffers;
std::vector<Transform> _transforms;
gpu::Batch _renderBatch;
QVector<QVector<QSharedPointer<Texture> > > _dilatedTextures;
@ -332,25 +332,6 @@ private:
int _blendNumber;
int _appliedBlendNumber;
class Locations {
public:
int tangent;
int alphaThreshold;
int texcoordMatrices;
int diffuseTextureUnit;
int normalTextureUnit;
int specularTextureUnit;
int emissiveTextureUnit;
int emissiveParams;
int glowIntensity;
int normalFittingMapUnit;
int materialBufferUnit;
int clusterMatrices;
int clusterIndices;
int clusterWeights;
int lightBufferUnit;
};
QHash<QPair<int,int>, AABox> _calculatedMeshPartBoxes; // world coordinate AABoxes for all sub mesh part boxes
bool _calculatedMeshPartBoxesValid;
@ -373,118 +354,9 @@ private:
void renderDebugMeshBoxes(gpu::Batch& batch);
int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID;
// helper functions used by render() or renderInScene()
static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold,
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args,
Locations*& locations);
static AbstractViewStateInterface* _viewState;
class RenderKey {
public:
enum FlagBit {
IS_TRANSLUCENT_FLAG = 0,
HAS_LIGHTMAP_FLAG,
HAS_TANGENTS_FLAG,
HAS_SPECULAR_FLAG,
HAS_EMISSIVE_FLAG,
IS_SKINNED_FLAG,
IS_STEREO_FLAG,
IS_DEPTH_ONLY_FLAG,
IS_SHADOW_FLAG,
IS_MIRROR_FLAG, //THis means that the mesh is rendered mirrored, not the same as "Rear view mirror"
IS_WIREFRAME_FLAG,
NUM_FLAGS,
};
enum Flag {
IS_TRANSLUCENT = (1 << IS_TRANSLUCENT_FLAG),
HAS_LIGHTMAP = (1 << HAS_LIGHTMAP_FLAG),
HAS_TANGENTS = (1 << HAS_TANGENTS_FLAG),
HAS_SPECULAR = (1 << HAS_SPECULAR_FLAG),
HAS_EMISSIVE = (1 << HAS_EMISSIVE_FLAG),
IS_SKINNED = (1 << IS_SKINNED_FLAG),
IS_STEREO = (1 << IS_STEREO_FLAG),
IS_DEPTH_ONLY = (1 << IS_DEPTH_ONLY_FLAG),
IS_SHADOW = (1 << IS_SHADOW_FLAG),
IS_MIRROR = (1 << IS_MIRROR_FLAG),
IS_WIREFRAME = (1 << IS_WIREFRAME_FLAG),
};
typedef unsigned short Flags;
bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); }
bool isTranslucent() const { return isFlag(IS_TRANSLUCENT); }
bool hasLightmap() const { return isFlag(HAS_LIGHTMAP); }
bool hasTangents() const { return isFlag(HAS_TANGENTS); }
bool hasSpecular() const { return isFlag(HAS_SPECULAR); }
bool hasEmissive() const { return isFlag(HAS_EMISSIVE); }
bool isSkinned() const { return isFlag(IS_SKINNED); }
bool isStereo() const { return isFlag(IS_STEREO); }
bool isDepthOnly() const { return isFlag(IS_DEPTH_ONLY); }
bool isShadow() const { return isFlag(IS_SHADOW); } // = depth only but with back facing
bool isMirror() const { return isFlag(IS_MIRROR); }
bool isWireFrame() const { return isFlag(IS_WIREFRAME); }
Flags _flags = 0;
short _spare = 0;
int getRaw() { return *reinterpret_cast<int*>(this); }
RenderKey(
bool translucent, bool hasLightmap,
bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) :
RenderKey( (translucent ? IS_TRANSLUCENT : 0)
| (hasLightmap ? HAS_LIGHTMAP : 0)
| (hasTangents ? HAS_TANGENTS : 0)
| (hasSpecular ? HAS_SPECULAR : 0)
| (isSkinned ? IS_SKINNED : 0)
| (isWireframe ? IS_WIREFRAME : 0)
) {}
RenderKey(RenderArgs::RenderMode mode,
bool translucent, float alphaThreshold, bool hasLightmap,
bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) :
RenderKey( ((translucent && (alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0)
| (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly
| (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0)
| (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0)
| (isSkinned ? IS_SKINNED : 0)
| (isWireframe ? IS_WIREFRAME : 0)
| ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_DEPTH_ONLY : 0)
| ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_SHADOW : 0)
| ((mode == RenderArgs::MIRROR_RENDER_MODE) ? IS_MIRROR :0)
) {}
RenderKey(int bitmask) : _flags(bitmask) {}
};
class RenderPipeline {
public:
gpu::PipelinePointer _pipeline;
std::shared_ptr<Locations> _locations;
RenderPipeline(gpu::PipelinePointer pipeline, std::shared_ptr<Locations> locations) :
_pipeline(pipeline), _locations(locations) {}
};
typedef std::unordered_map<int, RenderPipeline> BaseRenderPipelineMap;
class RenderPipelineLib : public BaseRenderPipelineMap {
public:
typedef RenderKey Key;
void addRenderPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader);
void initLocations(gpu::ShaderPointer& program, Locations& locations);
};
static RenderPipelineLib _renderPipelineLib;
bool _renderCollisionHull;

View file

@ -11,8 +11,299 @@
#include "ModelRenderPayload.h"
#include "DeferredLightingEffect.h"
#include "Model.h"
#include "model_vert.h"
#include "model_shadow_vert.h"
#include "model_normal_map_vert.h"
#include "model_lightmap_vert.h"
#include "model_lightmap_normal_map_vert.h"
#include "skin_model_vert.h"
#include "skin_model_shadow_vert.h"
#include "skin_model_normal_map_vert.h"
#include "model_frag.h"
#include "model_shadow_frag.h"
#include "model_normal_map_frag.h"
#include "model_normal_specular_map_frag.h"
#include "model_specular_map_frag.h"
#include "model_lightmap_frag.h"
#include "model_lightmap_normal_map_frag.h"
#include "model_lightmap_normal_specular_map_frag.h"
#include "model_lightmap_specular_map_frag.h"
#include "model_translucent_frag.h"
ModelRender::RenderPipelineLib ModelRender::_renderPipelineLib;
const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib() {
if (_renderPipelineLib.empty()) {
// Vertex shaders
auto modelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_vert)));
auto modelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_normal_map_vert)));
auto modelLightmapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_vert)));
auto modelLightmapNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert)));
auto modelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(model_shadow_vert)));
auto skinModelVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_vert)));
auto skinModelNormalMapVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_normal_map_vert)));
auto skinModelShadowVertex = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(skin_model_shadow_vert)));
// Pixel shaders
auto modelPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_frag)));
auto modelNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_map_frag)));
auto modelSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_specular_map_frag)));
auto modelNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)));
auto modelTranslucentPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_translucent_frag)));
auto modelShadowPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_shadow_frag)));
auto modelLightmapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_frag)));
auto modelLightmapNormalMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)));
auto modelLightmapSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)));
auto modelLightmapNormalSpecularMapPixel = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)));
// Fill the renderPipelineLib
_renderPipelineLib.addRenderPipeline(
RenderKey(0),
modelVertex, modelPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_TANGENTS),
modelNormalMapVertex, modelNormalMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_SPECULAR),
modelVertex, modelSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR),
modelNormalMapVertex, modelNormalSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_TRANSLUCENT),
modelVertex, modelTranslucentPixel);
// FIXME Ignore lightmap for translucents meshpart
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP),
modelVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT),
modelNormalMapVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
modelVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
modelNormalMapVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_LIGHTMAP),
modelLightmapVertex, modelLightmapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS),
modelLightmapNormalMapVertex, modelLightmapNormalMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_SPECULAR),
modelLightmapVertex, modelLightmapSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR),
modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED),
skinModelVertex, modelPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS),
skinModelNormalMapVertex, modelNormalMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR),
skinModelVertex, modelSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR),
skinModelNormalMapVertex, modelNormalSpecularMapPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT),
skinModelVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT),
skinModelNormalMapVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
skinModelVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
skinModelNormalMapVertex, modelTranslucentPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW),
modelShadowVertex, modelShadowPixel);
_renderPipelineLib.addRenderPipeline(
RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW),
skinModelShadowVertex, modelShadowPixel);
}
return _renderPipelineLib;
}
void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey key,
gpu::ShaderPointer& vertexShader,
gpu::ShaderPointer& pixelShader) {
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), ModelRender::MATERIAL_GPU_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), ModelRender::DIFFUSE_MAP_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), ModelRender::NORMAL_MAP_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), ModelRender::SPECULAR_MAP_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), ModelRender::LIGHTMAP_MAP_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ModelRender::LIGHT_BUFFER_SLOT));
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT));
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader));
gpu::Shader::makeProgram(*program, slotBindings);
auto locations = std::make_shared<Locations>();
initLocations(program, *locations);
auto state = std::make_shared<gpu::State>();
// Backface on shadow
if (key.isShadow()) {
state->setCullMode(gpu::State::CULL_FRONT);
state->setDepthBias(1.0f);
state->setDepthBiasSlopeScale(4.0f);
} else {
state->setCullMode(gpu::State::CULL_BACK);
}
// Z test depends if transparent or not
state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL);
// Blend on transparent
state->setBlendFunction(key.isTranslucent(),
gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, // For transparent only, this keep the highlight intensity
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
// Good to go add the brand new pipeline
auto pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations)));
if (!key.isWireFrame()) {
RenderKey wireframeKey(key.getRaw() | RenderKey::IS_WIREFRAME);
auto wireframeState = std::make_shared<gpu::State>(state->getValues());
wireframeState->setFillMode(gpu::State::FILL_LINE);
// create a new RenderPipeline with the same shader side and the mirrorState
auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState));
insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations)));
}
// If not a shadow pass, create the mirror version from the same state, just change the FrontFace
if (!key.isShadow()) {
RenderKey mirrorKey(key.getRaw() | RenderKey::IS_MIRROR);
auto mirrorState = std::make_shared<gpu::State>(state->getValues());
// create a new RenderPipeline with the same shader side and the mirrorState
auto mirrorPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, mirrorState));
insert(value_type(mirrorKey.getRaw(), RenderPipeline(mirrorPipeline, locations)));
if (!key.isWireFrame()) {
RenderKey wireframeKey(key.getRaw() | RenderKey::IS_MIRROR | RenderKey::IS_WIREFRAME);
auto wireframeState = std::make_shared<gpu::State>(state->getValues());
wireframeState->setFillMode(gpu::State::FILL_LINE);
// create a new RenderPipeline with the same shader side and the mirrorState
auto wireframePipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, wireframeState));
insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations)));
}
}
}
void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, ModelRender::Locations& locations) {
locations.alphaThreshold = program->getUniforms().findLocation("alphaThreshold");
locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices");
locations.emissiveParams = program->getUniforms().findLocation("emissiveParams");
locations.glowIntensity = program->getUniforms().findLocation("glowIntensity");
locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
locations.diffuseTextureUnit = program->getTextures().findLocation("diffuseMap");
locations.normalTextureUnit = program->getTextures().findLocation("normalMap");
locations.specularTextureUnit = program->getTextures().findLocation("specularMap");
locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer");
locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices");
locations.clusterIndices = program->getInputs().findLocation("inSkinClusterIndex");
locations.clusterWeights = program->getInputs().findLocation("inSkinClusterWeight");
}
void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold,
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args,
Locations*& locations) {
// PerformanceTimer perfTimer("Model::pickPrograms");
getRenderPipelineLib();
RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe);
if (mode == RenderArgs::MIRROR_RENDER_MODE) {
key = RenderKey(key.getRaw() | RenderKey::IS_MIRROR);
}
auto pipeline = _renderPipelineLib.find(key.getRaw());
if (pipeline == _renderPipelineLib.end()) {
qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw();
locations = 0;
return;
}
gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram();
locations = (*pipeline).second._locations.get();
// Setup the One pipeline
batch.setPipeline((*pipeline).second._pipeline);
if ((locations->alphaThreshold > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) {
batch._glUniform1f(locations->alphaThreshold, alphaThreshold);
}
if ((locations->glowIntensity > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) {
const float DEFAULT_GLOW_INTENSITY = 1.0f; // FIXME - glow is removed
batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY);
}
if ((locations->normalFittingMapUnit > -1)) {
batch.setResourceTexture(locations->normalFittingMapUnit,
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
}
}
namespace render {
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
if (payload) {
@ -42,34 +333,50 @@ using namespace render;
MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) :
model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex)
{
initCache();
}
void MeshPartPayload::initCache() {
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
_drawMesh = networkMesh._mesh;
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
_hasColorAttrib = !mesh.colors.isEmpty();
_isBlendShaped = !mesh.blendshapes.isEmpty();
_isSkinned = !mesh.clusterIndices.isEmpty();
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
auto networkMaterial = model->_geometry->getShapeMaterial(_shapeID);
if (networkMaterial) {
_drawMaterial = networkMaterial->_material;
};
}
render::ItemKey MeshPartPayload::getKey() const {
ItemKey::Builder builder;
builder.withTypeShape();
if (!model->isVisible()) {
return ItemKey::Builder().withInvisible().build();
builder.withInvisible();
}
auto geometry = model->getGeometry();
if (!geometry.isNull()) {
auto drawMaterial = geometry->getShapeMaterial(_shapeID);
if (drawMaterial) {
auto matKey = drawMaterial->_material->getKey();
if (matKey.isTransparent() || matKey.isTransparentMap()) {
return ItemKey::Builder::transparentShape();
} else {
return ItemKey::Builder::opaqueShape();
}
if (_isBlendShaped || _isSkinned) {
builder.withDeformed();
}
if (_drawMaterial) {
auto matKey = _drawMaterial->getKey();
if (matKey.isTransparent() || matKey.isTransparentMap()) {
builder.withTransparent();
}
}
// Return opaque for lack of a better idea
return ItemKey::Builder::opaqueShape();
return builder.build();
}
render::Item::Bound MeshPartPayload::getBound() const {
@ -84,313 +391,139 @@ void MeshPartPayload::render(RenderArgs* args) const {
return model->renderPart(args, meshIndex, partIndex, _shapeID, this);
}
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
}
void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
// auto drawMesh = networkMesh._mesh;
if (mesh.blendshapes.isEmpty()) {
if (!_isBlendShaped) {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
auto inputStream = _drawMesh->makeBufferStream();
batch.setInputStream(0, inputStream);
batch.setInputStream(0, _drawMesh->getVertexStream());
} else {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((_drawMesh->getVertexFormat()));
batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
auto inputStream = _drawMesh->makeBufferStream().makeRangedStream(2);
batch.setInputStream(2, inputStream);
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
}
if (mesh.colors.isEmpty()) {
// TODO: Get rid of that extra call
if (!_hasColorAttrib) {
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
}
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
}
/*
void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID) {
// PROFILE_RANGE(__FUNCTION__);
PerformanceTimer perfTimer("Model::renderPart");
if (!_readyWhenAdded) {
return; // bail asap
void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const {
if (!_drawMaterial) {
return;
}
auto textureCache = DependencyManager::get<TextureCache>();
gpu::Batch& batch = *(args->_batch);
auto mode = args->_renderMode;
// Capture the view matrix once for the rendering of this model
if (_transforms.empty()) {
_transforms.push_back(Transform());
}
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
const FBXGeometry& geometry = _geometry->getFBXGeometry();
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _geometry->getMeshes();
auto networkMaterial = _geometry->getShapeMaterial(shapeID);
if (!networkMaterial) {
return;
};
auto material = networkMaterial->_material;
if (!material) {
return;
}
// TODO: Not yet
// auto drawMesh = _geometry->getShapeMesh(shapeID);
// auto drawPart = _geometry->getShapePart(shapeID);
// guard against partially loaded meshes
if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) {
return;
}
updateClusterMatrices();
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
const MeshState& state = _meshStates.at(meshIndex);
auto drawMesh = networkMesh._mesh;
auto drawMaterialKey = material->getKey();
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty();
bool hasSpecular = drawMaterialKey.isGlossMap(); // !drawMaterial->specularTextureName.isEmpty(); //mesh.hasSpecularTexture();
bool hasLightmap = drawMaterialKey.isLightmapMap(); // !drawMaterial->emissiveTextureName.isEmpty(); //mesh.hasEmissiveTexture();
bool isSkinned = state.clusterMatrices.size() > 1;
bool wireframe = isWireframe();
// render the part bounding box
#ifdef DEBUG_BOUNDING_PARTS
{
AABox partBounds = getPartBounds(meshIndex, partIndex);
bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE;
glm::vec4 cubeColor;
if (isSkinned) {
cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f);
} else if (inView) {
cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f);
batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer());
auto materialKey = _drawMaterial->getKey();
auto textureMaps = _drawMaterial->getTextureMaps();
glm::mat4 texcoordTransform[2];
// Diffuse
if (materialKey.isDiffuseMap()) {
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
if (diffuseMap && diffuseMap->isDefined()) {
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
if (!diffuseMap->getTextureTransform().isIdentity()) {
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
}
} else {
cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f);
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
}
Transform transform;
transform.setTranslation(partBounds.calcCenter());
transform.setScale(partBounds.getDimensions());
batch.setModelTransform(transform);
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f, cubeColor);
} else {
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
}
#endif //def DEBUG_BOUNDING_PARTS
if (wireframe) {
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
// Normal map
if (materialKey.isNormalMap()) {
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
if (normalMap && normalMap->isDefined()) {
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView());
// texcoord are assumed to be the same has diffuse
} else {
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture());
}
} else {
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr);
}
Locations* locations = nullptr;
pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
args, locations);
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
// to false to rebuild out mesh groups.
if (meshIndex < 0 || meshIndex >= (int)networkMeshes.size() || meshIndex > geometry.meshes.size()) {
_meshGroupsKnown = false; // regenerate these lists next time around.
_readyWhenAdded = false; // in case any of our users are using scenes
invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
return; // FIXME!
// TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that
if (materialKey.isGlossMap()) {
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
if (specularMap && specularMap->isDefined()) {
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, specularMap->getTextureView());
// texcoord are assumed to be the same has diffuse
} else {
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture());
}
} else {
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, nullptr);
}
int vertexCount = mesh.vertices.size();
if (vertexCount == 0) {
// sanity check
return; // FIXME!
// TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too
if (materialKey.isLightmapMap()) {
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
if (lightmapMap && lightmapMap->isDefined()) {
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView());
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
if (!lightmapMap->getTextureTransform().isIdentity()) {
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
}
} else {
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture());
}
} else {
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr);
}
// Transform stage
if (_transforms.empty()) {
_transforms.push_back(Transform());
// Texcoord transforms ?
if (locations->texcoordMatrices >= 0) {
batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform);
}
if (isSkinned) {
}
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
Transform transform;
// Still relying on the raw data from the
const Model::MeshState& state = model->_meshStates.at(meshIndex);
if (_isSkinned) {
const float* bones;
if (_cauterizeBones) {
if (model->_cauterizeBones) {
bones = (const float*)state.cauterizedClusterMatrices.constData();
} else {
bones = (const float*)state.clusterMatrices.constData();
}
batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, bones);
_transforms[0] = Transform();
_transforms[0].preTranslate(_translation);
} else {
if (_cauterizeBones) {
_transforms[0] = Transform(state.cauterizedClusterMatrices[0]);
} else {
_transforms[0] = Transform(state.clusterMatrices[0]);
}
_transforms[0].preTranslate(_translation);
}
batch.setModelTransform(_transforms[0]);
auto drawPart = drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
if (mesh.blendshapes.isEmpty()) {
batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((drawMesh->getVertexFormat()));
auto inputStream = drawMesh->makeBufferStream();
batch.setInputStream(0, inputStream);
} else {
batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0);
batch.setInputFormat((drawMesh->getVertexFormat()));
batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3));
auto inputStream = drawMesh->makeBufferStream().makeRangedStream(2);
batch.setInputStream(2, inputStream);
}
if (mesh.colors.isEmpty()) {
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
// guard against partially loaded meshes
if (partIndex >= mesh.parts.size()) {
return;
}
#ifdef WANT_DEBUG
if (material == nullptr) {
qCDebug(renderutils) << "WARNING: material == nullptr!!!";
}
#endif
{
// apply material properties
if (mode != RenderArgs::SHADOW_RENDER_MODE) {
#ifdef WANT_DEBUG
qCDebug(renderutils) << "Material Changed ---------------------------------------------";
qCDebug(renderutils) << "part INDEX:" << partIndex;
qCDebug(renderutils) << "NEW part.materialID:" << part.materialID;
#endif //def WANT_DEBUG
if (locations->materialBufferUnit >= 0) {
batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer());
}
auto materialKey = material->getKey();
auto textureMaps = material->getTextureMaps();
glm::mat4 texcoordTransform[2];
// Diffuse
if (materialKey.isDiffuseMap()) {
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
if (diffuseMap && diffuseMap->isDefined()) {
batch.setResourceTexture(DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
if (!diffuseMap->getTextureTransform().isIdentity()) {
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
}
} else {
batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
}
} else {
batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
}
// Normal map
if ((locations->normalTextureUnit >= 0) && hasTangents) {
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
if (normalMap && normalMap->isDefined()) {
batch.setResourceTexture(NORMAL_MAP_SLOT, normalMap->getTextureView());
// texcoord are assumed to be the same has diffuse
} else {
batch.setResourceTexture(NORMAL_MAP_SLOT, textureCache->getBlueTexture());
}
} else {
batch.setResourceTexture(NORMAL_MAP_SLOT, nullptr);
}
// TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that
if ((locations->specularTextureUnit >= 0) && materialKey.isGlossMap()) {
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
if (specularMap && specularMap->isDefined()) {
batch.setResourceTexture(SPECULAR_MAP_SLOT, specularMap->getTextureView());
// texcoord are assumed to be the same has diffuse
} else {
batch.setResourceTexture(SPECULAR_MAP_SLOT, textureCache->getBlackTexture());
}
} else {
batch.setResourceTexture(SPECULAR_MAP_SLOT, nullptr);
}
// TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too
if ((locations->emissiveTextureUnit >= 0) && materialKey.isLightmapMap()) {
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
if (lightmapMap && lightmapMap->isDefined()) {
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView());
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
if (!lightmapMap->getTextureTransform().isIdentity()) {
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
}
}
else {
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture());
}
} else {
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, nullptr);
}
// Texcoord transforms ?
if (locations->texcoordMatrices >= 0) {
batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform);
}
// TODO: We should be able to do that just in the renderTransparentJob
if (translucentMesh && locations->lightBufferUnit >= 0) {
PerformanceTimer perfTimer("DLE->setupTransparent()");
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
}
if (args) {
args->_details._materialSwitches++;
}
}
}
if (args) {
const int INDICES_PER_TRIANGLE = 3;
args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE;
transform.preTranslate(model->_translation);
} else {
if (model->_cauterizeBones) {
transform = Transform(state.cauterizedClusterMatrices[0]);
} else {
transform = Transform(state.clusterMatrices[0]);
}
transform.preTranslate(model->_translation);
}
batch.setModelTransform(transform);
}
*/

View file

@ -22,6 +22,148 @@
class Model;
class ModelRender {
public:
static const int MATERIAL_GPU_SLOT = 3;
static const int DIFFUSE_MAP_SLOT = 0;
static const int NORMAL_MAP_SLOT = 1;
static const int SPECULAR_MAP_SLOT = 2;
static const int LIGHTMAP_MAP_SLOT = 3;
static const int LIGHT_BUFFER_SLOT = 4;
class Locations {
public:
int tangent;
int alphaThreshold;
int texcoordMatrices;
int diffuseTextureUnit;
int normalTextureUnit;
int specularTextureUnit;
int emissiveTextureUnit;
int emissiveParams;
int glowIntensity;
int normalFittingMapUnit;
int materialBufferUnit;
int clusterMatrices;
int clusterIndices;
int clusterWeights;
int lightBufferUnit;
};
static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold,
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args,
Locations*& locations);
class RenderKey {
public:
enum FlagBit {
IS_TRANSLUCENT_FLAG = 0,
HAS_LIGHTMAP_FLAG,
HAS_TANGENTS_FLAG,
HAS_SPECULAR_FLAG,
HAS_EMISSIVE_FLAG,
IS_SKINNED_FLAG,
IS_STEREO_FLAG,
IS_DEPTH_ONLY_FLAG,
IS_SHADOW_FLAG,
IS_MIRROR_FLAG, //THis means that the mesh is rendered mirrored, not the same as "Rear view mirror"
IS_WIREFRAME_FLAG,
NUM_FLAGS,
};
enum Flag {
IS_TRANSLUCENT = (1 << IS_TRANSLUCENT_FLAG),
HAS_LIGHTMAP = (1 << HAS_LIGHTMAP_FLAG),
HAS_TANGENTS = (1 << HAS_TANGENTS_FLAG),
HAS_SPECULAR = (1 << HAS_SPECULAR_FLAG),
HAS_EMISSIVE = (1 << HAS_EMISSIVE_FLAG),
IS_SKINNED = (1 << IS_SKINNED_FLAG),
IS_STEREO = (1 << IS_STEREO_FLAG),
IS_DEPTH_ONLY = (1 << IS_DEPTH_ONLY_FLAG),
IS_SHADOW = (1 << IS_SHADOW_FLAG),
IS_MIRROR = (1 << IS_MIRROR_FLAG),
IS_WIREFRAME = (1 << IS_WIREFRAME_FLAG),
};
typedef unsigned short Flags;
bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); }
bool isTranslucent() const { return isFlag(IS_TRANSLUCENT); }
bool hasLightmap() const { return isFlag(HAS_LIGHTMAP); }
bool hasTangents() const { return isFlag(HAS_TANGENTS); }
bool hasSpecular() const { return isFlag(HAS_SPECULAR); }
bool hasEmissive() const { return isFlag(HAS_EMISSIVE); }
bool isSkinned() const { return isFlag(IS_SKINNED); }
bool isStereo() const { return isFlag(IS_STEREO); }
bool isDepthOnly() const { return isFlag(IS_DEPTH_ONLY); }
bool isShadow() const { return isFlag(IS_SHADOW); } // = depth only but with back facing
bool isMirror() const { return isFlag(IS_MIRROR); }
bool isWireFrame() const { return isFlag(IS_WIREFRAME); }
Flags _flags = 0;
short _spare = 0;
int getRaw() { return *reinterpret_cast<int*>(this); }
RenderKey(
bool translucent, bool hasLightmap,
bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) :
RenderKey((translucent ? IS_TRANSLUCENT : 0)
| (hasLightmap ? HAS_LIGHTMAP : 0)
| (hasTangents ? HAS_TANGENTS : 0)
| (hasSpecular ? HAS_SPECULAR : 0)
| (isSkinned ? IS_SKINNED : 0)
| (isWireframe ? IS_WIREFRAME : 0)
) {}
RenderKey(RenderArgs::RenderMode mode,
bool translucent, float alphaThreshold, bool hasLightmap,
bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) :
RenderKey(((translucent && (alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0)
| (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly
| (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0)
| (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0)
| (isSkinned ? IS_SKINNED : 0)
| (isWireframe ? IS_WIREFRAME : 0)
| ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_DEPTH_ONLY : 0)
| ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_SHADOW : 0)
| ((mode == RenderArgs::MIRROR_RENDER_MODE) ? IS_MIRROR : 0)
) {}
RenderKey(int bitmask) : _flags(bitmask) {}
};
class RenderPipeline {
public:
gpu::PipelinePointer _pipeline;
std::shared_ptr<Locations> _locations;
RenderPipeline(gpu::PipelinePointer pipeline, std::shared_ptr<Locations> locations) :
_pipeline(pipeline), _locations(locations) {}
};
typedef std::unordered_map<int, RenderPipeline> BaseRenderPipelineMap;
class RenderPipelineLib : public BaseRenderPipelineMap {
public:
typedef RenderKey Key;
void addRenderPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader);
void initLocations(gpu::ShaderPointer& program, Locations& locations);
};
static RenderPipelineLib _renderPipelineLib;
static const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib();
};
class MeshPartPayload {
public:
MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex);
@ -41,15 +183,30 @@ public:
void render(RenderArgs* args) const;
// MeshPartPayload functions to perform render
void bindMesh(gpu::Batch& batch) const;
void drawCall(gpu::Batch& batch) const;
void bindMesh(gpu::Batch& batch) const;
void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const;
void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const;
void initCache();
// Payload resource cached values
model::MeshPointer _drawMesh;
model::Mesh::Part _drawPart;
model::MaterialPointer _drawMaterial;
bool _hasColorAttrib = false;
bool _isSkinned = false;
bool _isBlendShaped = false;
mutable render::Item::Bound _bound;
mutable bool _isBoundInvalid = true;
};
namespace render {
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload);
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
}
#endif // hifi_ModelRenderPayload_h

View file

@ -0,0 +1,68 @@
<!
// Skinning.slh
// libraries/render-utils/src
//
// Created by Sam Gateau on 10/5/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
!>
<@if not SKINNING_SLH@>
<@def SKINNING_SLH@>
const int MAX_TEXCOORDS = 2;
const int MAX_CLUSTERS = 128;
const int INDICES_PER_VERTEX = 4;
uniform mat4 clusterMatrices[MAX_CLUSTERS];
void skinPosition(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
newPosition += clusterMatrix * inPosition * clusterWeight;
}
skinnedPosition = newPosition;
}
void skinPositionNormal(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal,
out vec4 skinnedPosition, out vec3 skinnedNormal) {
vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0);
vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
newPosition += clusterMatrix * inPosition * clusterWeight;
newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight;
}
skinnedPosition = newPosition;
skinnedNormal = newNormal.xyz;
}
void skinPositionNormalTangent(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent,
out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) {
vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0);
vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0);
vec4 newTangent = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
newPosition += clusterMatrix * inPosition * clusterWeight;
newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight;
newTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight;
}
skinnedPosition = newPosition;
skinnedNormal = newNormal.xyz;
skinnedTangent = newTangent.xyz;
}
<@endif@>

View file

@ -18,11 +18,8 @@
<$declareStandardTransform()$>
const int MAX_TEXCOORDS = 2;
const int MAX_CLUSTERS = 128;
const int INDICES_PER_VERTEX = 4;
<@include Skinning.slh@>
uniform mat4 clusterMatrices[MAX_CLUSTERS];
uniform mat4 texcoordMatrices[MAX_TEXCOORDS];
out vec4 _position;
@ -32,13 +29,9 @@ out vec3 _color;
void main(void) {
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[int(inSkinClusterIndex[i])];
float clusterWeight = inSkinClusterWeight[i];
position += clusterMatrix * inPosition * clusterWeight;
interpolatedNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight;
}
vec3 interpolatedNormal = vec3(0.0, 0.0, 0.0);
skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal);
// pass along the diffuse color
_color = inColor.rgb;

View file

@ -18,11 +18,8 @@
<$declareStandardTransform()$>
const int MAX_TEXCOORDS = 2;
const int MAX_CLUSTERS = 128;
const int INDICES_PER_VERTEX = 4;
<@include Skinning.slh@>
uniform mat4 clusterMatrices[MAX_CLUSTERS];
uniform mat4 texcoordMatrices[MAX_TEXCOORDS];
out vec4 _position;
@ -35,13 +32,8 @@ void main(void) {
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0);
vec4 interpolatedTangent = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[int(inSkinClusterIndex[i])];
float clusterWeight = inSkinClusterWeight[i];
position += clusterMatrix * inPosition * clusterWeight;
interpolatedNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight;
interpolatedTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight;
}
skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz);
// pass along the diffuse color
_color = inColor.rgb;

View file

@ -16,18 +16,11 @@
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
const int MAX_CLUSTERS = 128;
const int INDICES_PER_VERTEX = 4;
uniform mat4 clusterMatrices[MAX_CLUSTERS];
<@include Skinning.slh@>
void main(void) {
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[int(inSkinClusterIndex[i])];
float clusterWeight = inSkinClusterWeight[i];
position += clusterMatrix * inPosition * clusterWeight;
}
skinPosition(inSkinClusterIndex, inSkinClusterWeight, inPosition, position);
// standard transform
TransformCamera cam = getTransformCamera();