242 lines
7.4 KiB
C++
242 lines
7.4 KiB
C++
#if !defined(__VPL_HW_H)
|
|
#define __VPL_HW_H
|
|
|
|
#include <mitsuba/render/vpl.h>
|
|
#include <mitsuba/hw/renderer.h>
|
|
|
|
MTS_NAMESPACE_BEGIN
|
|
|
|
/**
|
|
* This class is responsible for the on-demand creation of
|
|
* GPU shaders to render meshes with a particular material
|
|
* illuminated by a virtual point light source. For each
|
|
* encountered BSDF-VPL pair, a custom piece of code describing
|
|
* the characteristic light transport between them is created
|
|
* and cached. To avoid generating a potentially huge (N squared)
|
|
* number of very similar programs, the implementation passes some
|
|
* properties using uniforms, in which case already existing code
|
|
* can be reused and we get something more like lower case n squared.
|
|
*/
|
|
class MTS_EXPORT_HW VPLShaderManager : public Object {
|
|
public:
|
|
VPLShaderManager(const Scene *scene, Renderer *renderer);
|
|
|
|
/// To be called once before use
|
|
void init();
|
|
|
|
/// Generate the shadow map for a particular VPL
|
|
void setVPL(const VPL &vpl);
|
|
|
|
/// Prepare for rendering a material with BSDF 'bsdf' illuminated by VPL 'vpl'.
|
|
void configure(const VPL &vpl, const BSDF *bsdf,
|
|
const Luminaire *luminaire, const Point &camPos);
|
|
|
|
/// Draw the background if there is an environment luminaire
|
|
void drawBackground(const Transform &clipToWorld, const Point &camPos);
|
|
|
|
/// Release bound resources
|
|
void unbind();
|
|
|
|
/// Return the shadow cube map for debugging purposes
|
|
inline GPUTexture *getShadowMap() { return m_shadowMap; }
|
|
|
|
/// Should the shadow map generation be done in a single pass? (requires geometry shader support)
|
|
inline void setSinglePass(bool singlePass) { m_singlePass = singlePass; }
|
|
|
|
/// Is shadow map generation generation performed in a single pass?
|
|
inline bool isSinglePass() const { return m_singlePass; }
|
|
|
|
/// Set the current shadow map resolution
|
|
inline void setShadowMapResolution(int resolution) { m_shadowMapResolution = resolution; }
|
|
|
|
/// Return the current shadow map resolution
|
|
inline int getShadowMapResolution() const { return m_shadowMapResolution; }
|
|
|
|
/// Set the max. shadow map far plane distance
|
|
inline void setMaxClipDist(Float maxClipDist) { m_maxClipDist = maxClipDist; }
|
|
|
|
/// Return the max. shadow map far plane distance
|
|
inline Float getMaxClipDist() const { return m_maxClipDist; }
|
|
|
|
/// Set the clamping distance
|
|
inline void setClamping(Float clamping) { m_clamping = clamping; }
|
|
|
|
/// Return the clamping distance
|
|
inline Float getClamping() const { return m_clamping; }
|
|
|
|
/// Return the associated scene
|
|
inline const Scene *getScene() const { return m_scene.get(); }
|
|
|
|
/// To be called once before destruction
|
|
void cleanup();
|
|
|
|
MTS_DECLARE_CLASS()
|
|
protected:
|
|
/// Virtual destructor
|
|
virtual ~VPLShaderManager();
|
|
private:
|
|
struct VPLDependencyNode {
|
|
Shader *shader;
|
|
std::vector<VPLDependencyNode> children;
|
|
std::vector<int> parameterIDs;
|
|
|
|
inline VPLDependencyNode(const VPLDependencyNode &node)
|
|
: shader(node.shader), children(node.children), parameterIDs(node.parameterIDs) {
|
|
}
|
|
|
|
inline VPLDependencyNode(Shader *shader = NULL) : shader(shader) {
|
|
if (shader == NULL)
|
|
return;
|
|
std::vector<Shader *> deps;
|
|
shader->putDependencies(deps);
|
|
for (std::vector<Shader *>::iterator it = deps.begin();
|
|
it != deps.end(); ++it)
|
|
children.push_back(VPLDependencyNode(*it));
|
|
}
|
|
|
|
std::string recursiveGenerateCode(std::ostringstream &oss, int &id) const {
|
|
std::vector<std::string> depNames;
|
|
for (size_t i=0; i<children.size(); ++i)
|
|
depNames.push_back(children[i].recursiveGenerateCode(oss, id));
|
|
std::string evalName = formatString("shader_%i", id++);
|
|
shader->generateCode(oss, evalName, depNames);
|
|
oss << endl;
|
|
return evalName;
|
|
}
|
|
|
|
void recursiveResolve(GPUProgram *program, int &id) {
|
|
std::vector<std::string> depNames;
|
|
for (size_t i=0; i<children.size(); ++i)
|
|
children[i].recursiveResolve(program, id);
|
|
|
|
std::string evalName = formatString("shader_%i", id++);
|
|
shader->resolve(program, evalName, parameterIDs);
|
|
}
|
|
|
|
void recursiveBind(GPUProgram *program, const VPLDependencyNode &targetNode, int &textureUnitOffset) {
|
|
for (size_t i=0; i<children.size(); ++i)
|
|
children[i].recursiveBind(program, targetNode.children[i], textureUnitOffset);
|
|
shader->bind(program, targetNode.parameterIDs, textureUnitOffset);
|
|
}
|
|
|
|
void recursiveUnbind() {
|
|
shader->unbind();
|
|
for (size_t i=0; i<children.size(); ++i)
|
|
children[i].recursiveUnbind();
|
|
}
|
|
|
|
inline void toString(std::ostringstream &oss) const {
|
|
oss << shader->getClass()->getName();
|
|
if (children.size() > 0) {
|
|
oss << '{';
|
|
for (size_t i=0; i<children.size(); ++i) {
|
|
children[i].toString(oss);
|
|
if (i+1<children.size())
|
|
oss << ',';
|
|
}
|
|
oss << "}";
|
|
}
|
|
}
|
|
};
|
|
|
|
struct VPLProgramConfiguration {
|
|
VPLDependencyNode vpl, bsdf, luminaire;
|
|
bool hasLuminaire;
|
|
int param_shadowMap, param_vplPos, param_camPos, param_vplPower;
|
|
int param_vplN, param_vplS, param_vplT, param_vplWi, param_vplUV;
|
|
int param_nearClip, param_invClipRange, param_minDist;
|
|
|
|
inline VPLProgramConfiguration() { }
|
|
|
|
inline VPLProgramConfiguration(Shader *vpl, Shader *bsdf, Shader *luminaire)
|
|
: vpl(vpl), bsdf(bsdf), luminaire(luminaire) {
|
|
hasLuminaire = (luminaire != NULL);
|
|
}
|
|
|
|
void generateCode(std::ostringstream &oss, std::string &vplEvalName,
|
|
std::string &bsdfEvalName, std::string &luminaireEvalName) const {
|
|
int id = 0;
|
|
vplEvalName = vpl.recursiveGenerateCode(oss, id);
|
|
bsdfEvalName = bsdf.recursiveGenerateCode(oss, id);
|
|
if (hasLuminaire)
|
|
luminaireEvalName = luminaire.recursiveGenerateCode(oss, id);
|
|
}
|
|
|
|
void resolve(GPUProgram *program) {
|
|
int id = 0;
|
|
vpl.recursiveResolve(program, id);
|
|
bsdf.recursiveResolve(program, id);
|
|
if (hasLuminaire)
|
|
luminaire.recursiveResolve(program, id);
|
|
}
|
|
|
|
inline void bind(GPUProgram *program, const VPLProgramConfiguration &targetConf, int &textureUnitOffset) {
|
|
vpl.recursiveBind(program, targetConf.vpl, textureUnitOffset);
|
|
bsdf.recursiveBind(program, targetConf.bsdf, textureUnitOffset);
|
|
if (hasLuminaire)
|
|
luminaire.recursiveBind(program, targetConf.luminaire, textureUnitOffset);
|
|
}
|
|
|
|
inline void unbind() {
|
|
vpl.recursiveUnbind();
|
|
bsdf.recursiveUnbind();
|
|
if (hasLuminaire)
|
|
luminaire.recursiveUnbind();
|
|
}
|
|
|
|
inline void toString(std::ostringstream &oss) const {
|
|
oss << "vpl=";
|
|
vpl.toString(oss);
|
|
oss << ", bsdf=";
|
|
bsdf.toString(oss);
|
|
if (hasLuminaire) {
|
|
oss << ", luminaire=";
|
|
luminaire.toString(oss);
|
|
}
|
|
}
|
|
};
|
|
|
|
struct ProgramAndConfiguration {
|
|
GPUProgram *program;
|
|
VPLProgramConfiguration config;
|
|
|
|
inline ProgramAndConfiguration() : program(NULL) {
|
|
}
|
|
|
|
inline ProgramAndConfiguration(GPUProgram *program,
|
|
const VPLProgramConfiguration &config)
|
|
: program(program), config(config) {
|
|
}
|
|
};
|
|
|
|
/* General */
|
|
ref<const Scene> m_scene;
|
|
ref<Renderer> m_renderer;
|
|
Float m_clamping, m_minDist;
|
|
Float m_maxClipDist;
|
|
bool m_initialized;
|
|
|
|
/* Shadow mapping related */
|
|
ref<GPUProgram> m_shadowProgram;
|
|
ref<GPUProgram> m_altShadowProgram;
|
|
int m_shadowProgramParam_cubeMapTransform[6];
|
|
int m_shadowProgramParam_depthVec[6];
|
|
int m_altShadowProgramParam_cubeMapTransform;
|
|
int m_altShadowProgramParam_depthVec;
|
|
ref<GPUTexture> m_shadowMap;
|
|
Float m_nearClip, m_invClipRange;
|
|
int m_shadowMapResolution;
|
|
bool m_singlePass;
|
|
|
|
/* Rendering related */
|
|
std::map<std::string, ProgramAndConfiguration> m_programs;
|
|
ProgramAndConfiguration m_current;
|
|
VPLProgramConfiguration m_targetConfig;
|
|
ref<GPUProgram> m_backgroundProgram;
|
|
VPLDependencyNode m_backgroundDependencies;
|
|
};
|
|
|
|
MTS_NAMESPACE_END
|
|
|
|
#endif /* __VPL_HW_H */
|