mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 09:15:50 +02:00
Move skinning shader features in its own slh and get ready for moving cluster matrices to uniform buffer
This commit is contained in:
parent
9e393ced46
commit
12fedb6ff0
12 changed files with 731 additions and 935 deletions
|
@ -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; }
|
||||
|
|
|
@ -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() {
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
|
@ -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
|
68
libraries/render-utils/src/Skinning.slh
Normal file
68
libraries/render-utils/src/Skinning.slh
Normal 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@>
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue