mirror of
https://github.com/JulianGro/overte.git
synced 2025-08-13 01:55:39 +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();
|
||||||
~BufferStream();
|
~BufferStream();
|
||||||
|
|
||||||
|
void clear() { _buffers.clear(); _offsets.clear(); _strides.clear(); }
|
||||||
void addBuffer(const BufferPointer& buffer, Offset offset, Offset stride);
|
void addBuffer(const BufferPointer& buffer, Offset offset, Offset stride);
|
||||||
|
|
||||||
const Buffers& getBuffers() const { return _buffers; }
|
const Buffers& getBuffers() const { return _buffers; }
|
||||||
|
|
|
@ -64,6 +64,24 @@ void Mesh::evalVertexFormat() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_vertexFormat.reset(vf);
|
_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) {
|
void Mesh::setIndexBuffer(const BufferView& buffer) {
|
||||||
|
@ -116,23 +134,6 @@ const Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const
|
||||||
return totalBound;
|
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() {
|
Geometry::Geometry() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,9 @@ public:
|
||||||
// Stream format
|
// Stream format
|
||||||
const gpu::Stream::FormatPointer getVertexFormat() const { return _vertexFormat; }
|
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
|
// Index Buffer
|
||||||
void setIndexBuffer(const BufferView& buffer);
|
void setIndexBuffer(const BufferView& buffer);
|
||||||
const BufferView& getIndexBuffer() const { return _indexBuffer; }
|
const BufferView& getIndexBuffer() const { return _indexBuffer; }
|
||||||
|
@ -109,15 +112,12 @@ public:
|
||||||
// the returned box is the bounding box of ALL the evaluated part bounds.
|
// the returned box is the bounding box of ALL the evaluated part bounds.
|
||||||
const Box evalPartBounds(int partStart, int partEnd, Boxes& bounds) const;
|
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); }
|
static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast<gpu::Primitive>(topo); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
gpu::Stream::FormatPointer _vertexFormat;
|
gpu::Stream::FormatPointer _vertexFormat;
|
||||||
|
gpu::BufferStream _vertexStream;
|
||||||
|
|
||||||
BufferView _vertexBuffer;
|
BufferView _vertexBuffer;
|
||||||
BufferViewMap _attributeBuffers;
|
BufferViewMap _attributeBuffers;
|
||||||
|
@ -127,6 +127,7 @@ protected:
|
||||||
BufferView _partBuffer;
|
BufferView _partBuffer;
|
||||||
|
|
||||||
void evalVertexFormat();
|
void evalVertexFormat();
|
||||||
|
void evalVertexStream();
|
||||||
|
|
||||||
};
|
};
|
||||||
typedef std::shared_ptr< Mesh > MeshPointer;
|
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->setPartBuffer(gpu::BufferView(new gpu::Buffer(sizeof(part), (gpu::Byte*) &part), gpu::Element::PART_DRAWCALL));
|
||||||
|
|
||||||
_spotLightMesh->makeBufferStream();
|
_spotLightMesh->getVertexStream();
|
||||||
}
|
}
|
||||||
return _spotLightMesh;
|
return _spotLightMesh;
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,26 +27,6 @@
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
#include "ModelRenderPayload.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"
|
#include "RenderUtilsLogging.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -92,112 +72,6 @@ Model::~Model() {
|
||||||
deleteGeometry();
|
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;
|
AbstractViewStateInterface* Model::_viewState = NULL;
|
||||||
|
|
||||||
void Model::setTranslation(const glm::vec3& translation) {
|
void Model::setTranslation(const glm::vec3& translation) {
|
||||||
|
@ -255,128 +129,6 @@ void Model::initJointTransforms() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::init() {
|
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() {
|
void Model::reset() {
|
||||||
|
@ -416,6 +168,9 @@ bool Model::updateGeometry() {
|
||||||
MeshState state;
|
MeshState state;
|
||||||
state.clusterMatrices.resize(mesh.clusters.size());
|
state.clusterMatrices.resize(mesh.clusters.size());
|
||||||
state.cauterizedClusterMatrices.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);
|
_meshStates.append(state);
|
||||||
|
|
||||||
auto buffer = std::make_shared<gpu::Buffer>();
|
auto buffer = std::make_shared<gpu::Buffer>();
|
||||||
|
@ -1237,6 +992,7 @@ void Model::updateClusterMatrices() {
|
||||||
for (int i = 0; i < _meshStates.size(); i++) {
|
for (int i = 0; i < _meshStates.size(); i++) {
|
||||||
MeshState& state = _meshStates[i];
|
MeshState& state = _meshStates[i];
|
||||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||||
|
|
||||||
for (int j = 0; j < mesh.clusters.size(); j++) {
|
for (int j = 0; j < mesh.clusters.size(); j++) {
|
||||||
const FBXCluster& cluster = mesh.clusters.at(j);
|
const FBXCluster& cluster = mesh.clusters.at(j);
|
||||||
auto jointMatrix = _rig->getJointTransform(cluster.jointIndex);
|
auto jointMatrix = _rig->getJointTransform(cluster.jointIndex);
|
||||||
|
@ -1250,6 +1006,17 @@ void Model::updateClusterMatrices() {
|
||||||
state.cauterizedClusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix;
|
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
|
// 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);
|
gpu::Batch& batch = *(args->_batch);
|
||||||
auto mode = args->_renderMode;
|
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
|
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
||||||
|
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
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 FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
||||||
const MeshState& state = _meshStates.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();
|
auto drawMaterialKey = material->getKey();
|
||||||
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
|
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;
|
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Locations* locations = nullptr;
|
ModelRender::Locations* locations = nullptr;
|
||||||
pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||||
args, locations);
|
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();
|
payload->bindTransform(batch, locations);
|
||||||
if (vertexCount == 0) {
|
|
||||||
// sanity check
|
|
||||||
return; // FIXME!
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
payload->bindMesh(batch);
|
||||||
|
|
||||||
// guard against partially loaded meshes
|
// guard against partially loaded meshes
|
||||||
|
@ -1544,92 +1255,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// apply material properties
|
// apply material properties
|
||||||
if (mode != RenderArgs::SHADOW_RENDER_MODE) {
|
payload->bindMaterial(batch, locations);
|
||||||
#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
|
// TODO: We should be able to do that just in the renderTransparentJob
|
||||||
if (translucentMesh && locations->lightBufferUnit >= 0) {
|
if (translucentMesh && locations->lightBufferUnit >= 0) {
|
||||||
|
@ -1637,13 +1265,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
|
||||||
|
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
|
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (args) {
|
if (args) {
|
||||||
args->_details._materialSwitches++;
|
args->_details._materialSwitches++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("batch.drawIndexed()");
|
PerformanceTimer perfTimer("batch.drawIndexed()");
|
||||||
|
@ -1652,7 +1277,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
|
||||||
|
|
||||||
if (args) {
|
if (args) {
|
||||||
const int INDICES_PER_TRIANGLE = 3;
|
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;
|
_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) {
|
bool Model::initWhenReady(render::ScenePointer scene) {
|
||||||
if (isActive() && isRenderable() && !_meshGroupsKnown && isLoaded()) {
|
if (isActive() && isRenderable() && !_meshGroupsKnown && isLoaded()) {
|
||||||
segregateMeshGroups();
|
segregateMeshGroups();
|
||||||
|
|
|
@ -47,6 +47,7 @@ namespace render {
|
||||||
typedef unsigned int ItemID;
|
typedef unsigned int ItemID;
|
||||||
}
|
}
|
||||||
class MeshPartPayload;
|
class MeshPartPayload;
|
||||||
|
class ModelRenderLocations;
|
||||||
|
|
||||||
inline uint qHash(const std::shared_ptr<MeshPartPayload>& a, uint seed) {
|
inline uint qHash(const std::shared_ptr<MeshPartPayload>& a, uint seed) {
|
||||||
return qHash(a.get(), seed);
|
return qHash(a.get(), seed);
|
||||||
|
@ -257,6 +258,7 @@ protected:
|
||||||
public:
|
public:
|
||||||
QVector<glm::mat4> clusterMatrices;
|
QVector<glm::mat4> clusterMatrices;
|
||||||
QVector<glm::mat4> cauterizedClusterMatrices;
|
QVector<glm::mat4> cauterizedClusterMatrices;
|
||||||
|
gpu::BufferPointer clusterBuffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
QVector<MeshState> _meshStates;
|
QVector<MeshState> _meshStates;
|
||||||
|
@ -323,8 +325,6 @@ private:
|
||||||
bool _isVisible;
|
bool _isVisible;
|
||||||
|
|
||||||
gpu::Buffers _blendedVertexBuffers;
|
gpu::Buffers _blendedVertexBuffers;
|
||||||
std::vector<Transform> _transforms;
|
|
||||||
gpu::Batch _renderBatch;
|
|
||||||
|
|
||||||
QVector<QVector<QSharedPointer<Texture> > > _dilatedTextures;
|
QVector<QVector<QSharedPointer<Texture> > > _dilatedTextures;
|
||||||
|
|
||||||
|
@ -332,25 +332,6 @@ private:
|
||||||
int _blendNumber;
|
int _blendNumber;
|
||||||
int _appliedBlendNumber;
|
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
|
QHash<QPair<int,int>, AABox> _calculatedMeshPartBoxes; // world coordinate AABoxes for all sub mesh part boxes
|
||||||
|
|
||||||
bool _calculatedMeshPartBoxesValid;
|
bool _calculatedMeshPartBoxesValid;
|
||||||
|
@ -373,118 +354,9 @@ private:
|
||||||
void renderDebugMeshBoxes(gpu::Batch& batch);
|
void renderDebugMeshBoxes(gpu::Batch& batch);
|
||||||
int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID;
|
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;
|
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;
|
bool _renderCollisionHull;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,299 @@
|
||||||
|
|
||||||
#include "ModelRenderPayload.h"
|
#include "ModelRenderPayload.h"
|
||||||
|
|
||||||
|
#include "DeferredLightingEffect.h"
|
||||||
|
|
||||||
#include "Model.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 {
|
namespace render {
|
||||||
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
|
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
|
||||||
if (payload) {
|
if (payload) {
|
||||||
|
@ -42,34 +333,50 @@ using namespace render;
|
||||||
MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) :
|
MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) :
|
||||||
model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex), _shapeID(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 std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
|
||||||
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
|
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
|
||||||
_drawMesh = networkMesh._mesh;
|
_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);
|
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||||
|
|
||||||
}
|
auto networkMaterial = model->_geometry->getShapeMaterial(_shapeID);
|
||||||
|
if (networkMaterial) {
|
||||||
|
_drawMaterial = networkMaterial->_material;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
render::ItemKey MeshPartPayload::getKey() const {
|
render::ItemKey MeshPartPayload::getKey() const {
|
||||||
|
ItemKey::Builder builder;
|
||||||
|
builder.withTypeShape();
|
||||||
|
|
||||||
if (!model->isVisible()) {
|
if (!model->isVisible()) {
|
||||||
return ItemKey::Builder().withInvisible().build();
|
builder.withInvisible();
|
||||||
}
|
}
|
||||||
auto geometry = model->getGeometry();
|
|
||||||
if (!geometry.isNull()) {
|
if (_isBlendShaped || _isSkinned) {
|
||||||
auto drawMaterial = geometry->getShapeMaterial(_shapeID);
|
builder.withDeformed();
|
||||||
if (drawMaterial) {
|
}
|
||||||
auto matKey = drawMaterial->_material->getKey();
|
|
||||||
|
if (_drawMaterial) {
|
||||||
|
auto matKey = _drawMaterial->getKey();
|
||||||
if (matKey.isTransparent() || matKey.isTransparentMap()) {
|
if (matKey.isTransparent() || matKey.isTransparentMap()) {
|
||||||
return ItemKey::Builder::transparentShape();
|
builder.withTransparent();
|
||||||
} else {
|
|
||||||
return ItemKey::Builder::opaqueShape();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return opaque for lack of a better idea
|
return builder.build();
|
||||||
return ItemKey::Builder::opaqueShape();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render::Item::Bound MeshPartPayload::getBound() const {
|
render::Item::Bound MeshPartPayload::getBound() const {
|
||||||
|
@ -84,276 +391,96 @@ void MeshPartPayload::render(RenderArgs* args) const {
|
||||||
return model->renderPart(args, meshIndex, partIndex, _shapeID, this);
|
return model->renderPart(args, meshIndex, partIndex, _shapeID, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
||||||
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
|
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
|
||||||
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()) {
|
void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||||
|
if (!_isBlendShaped) {
|
||||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||||
|
|
||||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||||
auto inputStream = _drawMesh->makeBufferStream();
|
|
||||||
|
|
||||||
batch.setInputStream(0, inputStream);
|
batch.setInputStream(0, _drawMesh->getVertexStream());
|
||||||
} else {
|
} else {
|
||||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||||
|
|
||||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||||
|
|
||||||
batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
|
batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
|
||||||
batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
|
batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
|
||||||
|
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
|
||||||
auto inputStream = _drawMesh->makeBufferStream().makeRangedStream(2);
|
|
||||||
|
|
||||||
batch.setInputStream(2, inputStream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh.colors.isEmpty()) {
|
// TODO: Get rid of that extra call
|
||||||
|
if (!_hasColorAttrib) {
|
||||||
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
||||||
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
|
if (!_drawMaterial) {
|
||||||
}
|
return;
|
||||||
/*
|
|
||||||
void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID) {
|
|
||||||
// PROFILE_RANGE(__FUNCTION__);
|
|
||||||
PerformanceTimer perfTimer("Model::renderPart");
|
|
||||||
if (!_readyWhenAdded) {
|
|
||||||
return; // bail asap
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto textureCache = DependencyManager::get<TextureCache>();
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
|
|
||||||
gpu::Batch& batch = *(args->_batch);
|
batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer());
|
||||||
auto mode = args->_renderMode;
|
|
||||||
|
|
||||||
|
auto materialKey = _drawMaterial->getKey();
|
||||||
// Capture the view matrix once for the rendering of this model
|
auto textureMaps = _drawMaterial->getTextureMaps();
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform transform;
|
|
||||||
transform.setTranslation(partBounds.calcCenter());
|
|
||||||
transform.setScale(partBounds.getDimensions());
|
|
||||||
batch.setModelTransform(transform);
|
|
||||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f, cubeColor);
|
|
||||||
}
|
|
||||||
#endif //def DEBUG_BOUNDING_PARTS
|
|
||||||
|
|
||||||
if (wireframe) {
|
|
||||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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!
|
|
||||||
}
|
|
||||||
|
|
||||||
int vertexCount = mesh.vertices.size();
|
|
||||||
if (vertexCount == 0) {
|
|
||||||
// sanity check
|
|
||||||
return; // FIXME!
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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];
|
glm::mat4 texcoordTransform[2];
|
||||||
|
|
||||||
// Diffuse
|
// Diffuse
|
||||||
if (materialKey.isDiffuseMap()) {
|
if (materialKey.isDiffuseMap()) {
|
||||||
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
|
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
|
||||||
if (diffuseMap && diffuseMap->isDefined()) {
|
if (diffuseMap && diffuseMap->isDefined()) {
|
||||||
batch.setResourceTexture(DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
|
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
|
||||||
|
|
||||||
if (!diffuseMap->getTextureTransform().isIdentity()) {
|
if (!diffuseMap->getTextureTransform().isIdentity()) {
|
||||||
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
|
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal map
|
// Normal map
|
||||||
if ((locations->normalTextureUnit >= 0) && hasTangents) {
|
if (materialKey.isNormalMap()) {
|
||||||
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
|
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
|
||||||
if (normalMap && normalMap->isDefined()) {
|
if (normalMap && normalMap->isDefined()) {
|
||||||
batch.setResourceTexture(NORMAL_MAP_SLOT, normalMap->getTextureView());
|
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView());
|
||||||
|
|
||||||
// texcoord are assumed to be the same has diffuse
|
// texcoord are assumed to be the same has diffuse
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(NORMAL_MAP_SLOT, textureCache->getBlueTexture());
|
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(NORMAL_MAP_SLOT, nullptr);
|
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that
|
// 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()) {
|
if (materialKey.isGlossMap()) {
|
||||||
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
|
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
|
||||||
if (specularMap && specularMap->isDefined()) {
|
if (specularMap && specularMap->isDefined()) {
|
||||||
batch.setResourceTexture(SPECULAR_MAP_SLOT, specularMap->getTextureView());
|
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, specularMap->getTextureView());
|
||||||
|
|
||||||
// texcoord are assumed to be the same has diffuse
|
// texcoord are assumed to be the same has diffuse
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(SPECULAR_MAP_SLOT, textureCache->getBlackTexture());
|
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(SPECULAR_MAP_SLOT, nullptr);
|
batch.setResourceTexture(ModelRender::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
|
// 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()) {
|
if (materialKey.isLightmapMap()) {
|
||||||
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
|
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
|
||||||
|
|
||||||
if (lightmapMap && lightmapMap->isDefined()) {
|
if (lightmapMap && lightmapMap->isDefined()) {
|
||||||
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView());
|
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView());
|
||||||
|
|
||||||
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
|
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
|
||||||
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
|
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
|
||||||
|
@ -361,36 +488,42 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
|
||||||
if (!lightmapMap->getTextureTransform().isIdentity()) {
|
if (!lightmapMap->getTextureTransform().isIdentity()) {
|
||||||
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
|
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture());
|
||||||
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture());
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, nullptr);
|
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texcoord transforms ?
|
// Texcoord transforms ?
|
||||||
if (locations->texcoordMatrices >= 0) {
|
if (locations->texcoordMatrices >= 0) {
|
||||||
batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform);
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (args) {
|
if (_isSkinned) {
|
||||||
args->_details._materialSwitches++;
|
const float* bones;
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args) {
|
|
||||||
const int INDICES_PER_TRIANGLE = 3;
|
|
||||||
args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -22,6 +22,148 @@
|
||||||
|
|
||||||
class Model;
|
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 {
|
class MeshPartPayload {
|
||||||
public:
|
public:
|
||||||
MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex);
|
MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex);
|
||||||
|
@ -41,15 +183,30 @@ public:
|
||||||
void render(RenderArgs* args) const;
|
void render(RenderArgs* args) const;
|
||||||
|
|
||||||
// MeshPartPayload functions to perform render
|
// MeshPartPayload functions to perform render
|
||||||
void bindMesh(gpu::Batch& batch) const;
|
|
||||||
void drawCall(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::MeshPointer _drawMesh;
|
||||||
model::Mesh::Part _drawPart;
|
model::Mesh::Part _drawPart;
|
||||||
model::MaterialPointer _drawMaterial;
|
model::MaterialPointer _drawMaterial;
|
||||||
|
bool _hasColorAttrib = false;
|
||||||
|
bool _isSkinned = false;
|
||||||
|
bool _isBlendShaped = false;
|
||||||
|
|
||||||
mutable render::Item::Bound _bound;
|
mutable render::Item::Bound _bound;
|
||||||
mutable bool _isBoundInvalid = true;
|
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
|
#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()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
const int MAX_TEXCOORDS = 2;
|
<@include Skinning.slh@>
|
||||||
const int MAX_CLUSTERS = 128;
|
|
||||||
const int INDICES_PER_VERTEX = 4;
|
|
||||||
|
|
||||||
uniform mat4 clusterMatrices[MAX_CLUSTERS];
|
|
||||||
uniform mat4 texcoordMatrices[MAX_TEXCOORDS];
|
uniform mat4 texcoordMatrices[MAX_TEXCOORDS];
|
||||||
|
|
||||||
out vec4 _position;
|
out vec4 _position;
|
||||||
|
@ -32,13 +29,9 @@ out vec3 _color;
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 interpolatedNormal = vec4(0.0, 0.0, 0.0, 0.0);
|
vec3 interpolatedNormal = vec3(0.0, 0.0, 0.0);
|
||||||
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
|
|
||||||
mat4 clusterMatrix = clusterMatrices[int(inSkinClusterIndex[i])];
|
skinPositionNormal(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, position, interpolatedNormal);
|
||||||
float clusterWeight = inSkinClusterWeight[i];
|
|
||||||
position += clusterMatrix * inPosition * clusterWeight;
|
|
||||||
interpolatedNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pass along the diffuse color
|
// pass along the diffuse color
|
||||||
_color = inColor.rgb;
|
_color = inColor.rgb;
|
||||||
|
|
|
@ -18,11 +18,8 @@
|
||||||
|
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
const int MAX_TEXCOORDS = 2;
|
<@include Skinning.slh@>
|
||||||
const int MAX_CLUSTERS = 128;
|
|
||||||
const int INDICES_PER_VERTEX = 4;
|
|
||||||
|
|
||||||
uniform mat4 clusterMatrices[MAX_CLUSTERS];
|
|
||||||
uniform mat4 texcoordMatrices[MAX_TEXCOORDS];
|
uniform mat4 texcoordMatrices[MAX_TEXCOORDS];
|
||||||
|
|
||||||
out vec4 _position;
|
out vec4 _position;
|
||||||
|
@ -35,13 +32,8 @@ void main(void) {
|
||||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
vec4 interpolatedNormal = 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);
|
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])];
|
skinPositionNormalTangent(inSkinClusterIndex, inSkinClusterWeight, inPosition, inNormal.xyz, inTangent.xyz, position, interpolatedNormal.xyz, interpolatedTangent.xyz);
|
||||||
float clusterWeight = inSkinClusterWeight[i];
|
|
||||||
position += clusterMatrix * inPosition * clusterWeight;
|
|
||||||
interpolatedNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight;
|
|
||||||
interpolatedTangent += clusterMatrix * vec4(inTangent.xyz, 0.0) * clusterWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pass along the diffuse color
|
// pass along the diffuse color
|
||||||
_color = inColor.rgb;
|
_color = inColor.rgb;
|
||||||
|
|
|
@ -16,18 +16,11 @@
|
||||||
<@include gpu/Transform.slh@>
|
<@include gpu/Transform.slh@>
|
||||||
<$declareStandardTransform()$>
|
<$declareStandardTransform()$>
|
||||||
|
|
||||||
const int MAX_CLUSTERS = 128;
|
<@include Skinning.slh@>
|
||||||
const int INDICES_PER_VERTEX = 4;
|
|
||||||
|
|
||||||
uniform mat4 clusterMatrices[MAX_CLUSTERS];
|
|
||||||
|
|
||||||
void main(void) {
|
void main(void) {
|
||||||
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
vec4 position = vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
|
skinPosition(inSkinClusterIndex, inSkinClusterWeight, inPosition, position);
|
||||||
mat4 clusterMatrix = clusterMatrices[int(inSkinClusterIndex[i])];
|
|
||||||
float clusterWeight = inSkinClusterWeight[i];
|
|
||||||
position += clusterMatrix * inPosition * clusterWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
// standard transform
|
// standard transform
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
|
|
Loading…
Reference in a new issue