mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 21:15:07 +02:00
305 lines
14 KiB
C++
305 lines
14 KiB
C++
//
|
|
// ModelRender.cpp
|
|
// interface/src/renderer
|
|
//
|
|
// Created by Sam Gateau on 10/3/15.
|
|
// Copyright 2015 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#include "ModelRender.h"
|
|
|
|
#include <model-networking/TextureCache.h>
|
|
|
|
#include "DeferredLightingEffect.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());
|
|
}
|
|
}
|