started a new branch for a material development cycle. new features: glass preview in the VPL renderer, more documentation
parent
8fec5a4d87
commit
5cc7e40df2
Binary file not shown.
After Width: | Height: | Size: 147 KiB |
Binary file not shown.
After Width: | Height: | Size: 194 KiB |
Binary file not shown.
After Width: | Height: | Size: 209 KiB |
Binary file not shown.
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 192 KiB |
|
@ -43,22 +43,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
\newcommand{\renderings}[1]{
|
\newcommand{\renderings}[1]{
|
||||||
\begin{figure}[h]
|
\begin{figure}[h!]
|
||||||
\centering
|
\centering
|
||||||
\hfill
|
\hfill
|
||||||
#1
|
#1
|
||||||
\end{figure}
|
\end{figure}
|
||||||
}
|
}
|
||||||
|
|
||||||
\newcommand{\rendering}[2]{
|
\newcommand{\rendering}[2]{\subfigure[#1]{\fbox{\includegraphics[width=0.4\textwidth]{images/#2}}}\hfill}
|
||||||
\subfigure[#1]{\fbox{\includegraphics[width=0.4\textwidth]{images/#2}}}
|
\newcommand{\medrendering}[2]{ \subfigure[#1]{\fbox{\includegraphics[width=0.3\textwidth]{images/#2}}}\hfill}
|
||||||
\hfill
|
\newcommand{\smallrendering}[2]{ \subfigure[#1]{\fbox{\includegraphics[width=0.2\textwidth]{images/#2}}}\hfill}
|
||||||
}
|
|
||||||
|
|
||||||
\newcommand{\smallrendering}[2]{
|
|
||||||
\subfigure[#1]{\fbox{\includegraphics[width=0.2\textwidth]{images/#2}}}
|
|
||||||
\hfill
|
|
||||||
}
|
|
||||||
|
|
||||||
\newcommand{\parameter}[3]{
|
\newcommand{\parameter}[3]{
|
||||||
\small\texttt{#1} & \small #2 & \small #3\\
|
\small\texttt{#1} & \small #2 & \small #3\\
|
||||||
|
|
|
@ -159,7 +159,7 @@ public:
|
||||||
void setColorMask(bool value);
|
void setColorMask(bool value);
|
||||||
|
|
||||||
/// Set the current fixed-function pipeline color
|
/// Set the current fixed-function pipeline color
|
||||||
void setColor(const Spectrum &spec);
|
void setColor(const Spectrum &spec, Float alpha = 1.0f);
|
||||||
|
|
||||||
/// Push a view transformation onto the matrix stack
|
/// Push a view transformation onto the matrix stack
|
||||||
void pushTransform(const Transform &trafo);
|
void pushTransform(const Transform &trafo);
|
||||||
|
|
|
@ -207,7 +207,7 @@ public:
|
||||||
virtual void setColorMask(bool value) = 0;
|
virtual void setColorMask(bool value) = 0;
|
||||||
|
|
||||||
/// Set the current fixed-function pipeline color
|
/// Set the current fixed-function pipeline color
|
||||||
virtual void setColor(const Spectrum &spec) = 0;
|
virtual void setColor(const Spectrum &spec, Float alpha = 1.0f) = 0;
|
||||||
|
|
||||||
/// Push a view transformation onto the matrix stack
|
/// Push a view transformation onto the matrix stack
|
||||||
virtual void pushTransform(const Transform &trafo) = 0;
|
virtual void pushTransform(const Transform &trafo) = 0;
|
||||||
|
|
|
@ -25,15 +25,17 @@
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is responsible for the on-demand creation of
|
* \brief This class is responsible for the on-demand creation of
|
||||||
* GPU shaders to render meshes with a particular material
|
* GPU shaders to render meshes that are illuminated by a virtual
|
||||||
* illuminated by a virtual point light source. For each
|
* point light source.
|
||||||
* encountered BSDF-VPL pair, a custom piece of code describing
|
*
|
||||||
* the characteristic light transport between them is created
|
* 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)
|
* and cached. To avoid generating a potentially huge (N squared)
|
||||||
* number of very similar programs, the implementation passes some
|
* number of very similar programs, the implementation passes some
|
||||||
* properties using uniforms, in which case already existing code
|
* properties using uniforms, in which case already existing code
|
||||||
* can be reused and we get something more like lower case n squared.
|
* can be reused and we get something more like lower case n squared
|
||||||
|
* (where lower n is the number of material types).
|
||||||
*/
|
*/
|
||||||
class MTS_EXPORT_HW VPLShaderManager : public Object {
|
class MTS_EXPORT_HW VPLShaderManager : public Object {
|
||||||
public:
|
public:
|
||||||
|
@ -55,9 +57,12 @@ public:
|
||||||
/// Release bound resources
|
/// Release bound resources
|
||||||
void unbind();
|
void unbind();
|
||||||
|
|
||||||
/// Return all bound triangle meshes
|
/// Return all bound opaque triangle meshes
|
||||||
inline const std::vector<std::pair<const TriMesh *, Transform> > &getMeshes() const { return m_meshes; }
|
inline const std::vector<std::pair<const TriMesh *, Transform> > &getMeshes() const { return m_meshes; }
|
||||||
|
|
||||||
|
/// Return all bound transparent triangle meshes
|
||||||
|
inline const std::vector<std::pair<const TriMesh *, Transform> > &getTransparentMeshes() const { return m_transparentMeshes; }
|
||||||
|
|
||||||
/// Return the shadow cube map for debugging purposes
|
/// Return the shadow cube map for debugging purposes
|
||||||
inline GPUTexture *getShadowMap() { return m_shadowMap; }
|
inline GPUTexture *getShadowMap() { return m_shadowMap; }
|
||||||
|
|
||||||
|
@ -178,7 +183,7 @@ private:
|
||||||
int param_shadowMap, param_vplPos, param_camPos, param_vplPower;
|
int param_shadowMap, param_vplPos, param_camPos, param_vplPower;
|
||||||
int param_vplN, param_vplS, param_vplT, param_vplWi, param_vplUV;
|
int param_vplN, param_vplS, param_vplT, param_vplWi, param_vplUV;
|
||||||
int param_nearClip, param_invClipRange, param_minDist;
|
int param_nearClip, param_invClipRange, param_minDist;
|
||||||
int param_diffuseSources, param_diffuseReceivers;
|
int param_diffuseSources, param_diffuseReceivers, param_alpha;
|
||||||
|
|
||||||
inline VPLProgramConfiguration() { }
|
inline VPLProgramConfiguration() { }
|
||||||
|
|
||||||
|
@ -272,6 +277,7 @@ private:
|
||||||
ref<GPUProgram> m_backgroundProgram;
|
ref<GPUProgram> m_backgroundProgram;
|
||||||
VPLDependencyNode m_backgroundDependencies;
|
VPLDependencyNode m_backgroundDependencies;
|
||||||
std::vector<std::pair<const TriMesh *, Transform> > m_meshes;
|
std::vector<std::pair<const TriMesh *, Transform> > m_meshes;
|
||||||
|
std::vector<std::pair<const TriMesh *, Transform> > m_transparentMeshes;
|
||||||
std::vector<std::pair<const GPUGeometry *, Transform> > m_drawList;
|
std::vector<std::pair<const GPUGeometry *, Transform> > m_drawList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,12 @@ class Renderer;
|
||||||
class GPUProgram;
|
class GPUProgram;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract hardware resource -- provides support for functionality,
|
* \brief Abstract hardware resource.
|
||||||
* which can alternatively also live on the GPU. By default, the
|
*
|
||||||
* method 'createShader' just returns NULL, which means that the
|
* Implementations provides support for functionality that are also able to
|
||||||
* BSDF/Light source/Texture/.. cannot be used with a GPU-based renderer.
|
* live on the GPU. By default, the method 'createShader' just returns \c NULL,
|
||||||
|
* which means that the BSDF/Light source/Texture/.. has not yet been ported
|
||||||
|
* to the GPU-based renderer.
|
||||||
*/
|
*/
|
||||||
class MTS_EXPORT_RENDER HWResource {
|
class MTS_EXPORT_RENDER HWResource {
|
||||||
public:
|
public:
|
||||||
|
@ -41,8 +43,10 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shader base class for use with a VPL-style renderer. Could implement
|
* \brief Shader base class for use with a VPL-style renderer.
|
||||||
* one of various things, such as a BSDF, a light source, or a texture.
|
*
|
||||||
|
* Subclasses can implement one of various things, such as a BSDF,
|
||||||
|
* a light source, or a texture.
|
||||||
*/
|
*/
|
||||||
class MTS_EXPORT_RENDER Shader : public Object {
|
class MTS_EXPORT_RENDER Shader : public Object {
|
||||||
public:
|
public:
|
||||||
|
@ -52,59 +56,65 @@ public:
|
||||||
ELuminaireShader
|
ELuminaireShader
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
enum EFlags {
|
||||||
* Return the type of shader represented by this instance
|
ETransparent = 0x01
|
||||||
*/
|
};
|
||||||
|
|
||||||
|
// Return the type of shader represented by this instance
|
||||||
inline EShaderType getType() const { return m_type; }
|
inline EShaderType getType() const { return m_type; }
|
||||||
|
|
||||||
/**
|
/// Return a list of flags
|
||||||
* List other shaders, on which this instance depends
|
inline uint32_t getFlags() const { return m_flags; }
|
||||||
*/
|
|
||||||
|
|
||||||
|
// List other shaders, on which this instance depends
|
||||||
virtual void putDependencies(std::vector<Shader *> &deps);
|
virtual void putDependencies(std::vector<Shader *> &deps);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is this shader complete? This is mainly useful to
|
* \brief Is this shader complete?
|
||||||
* check whether all dependencies could be constructed
|
*
|
||||||
* successfully. The default implementation returns true
|
* This is mainly useful to check whether all dependencies
|
||||||
|
* could be constructed successfully. The default
|
||||||
|
* implementation returns \c true.
|
||||||
*/
|
*/
|
||||||
virtual bool isComplete() const;
|
virtual bool isComplete() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a string version of this shader's evaluation
|
* \brief Generate a string version of this shader's evaluation
|
||||||
* routine. The appended string should assign the name
|
* routine.
|
||||||
* 'evalName' to this function. The function names of
|
*
|
||||||
* depedencies (as specified by 'putDependencies'), are
|
* The appended string should assign the name \c evalName to this
|
||||||
* supplied in the parameter 'depNames' in identical order.
|
* function. The function names of depedencies (as specified by
|
||||||
|
* \ref putDependencies), are supplied in the parameter \c depNames
|
||||||
|
* in identical order.
|
||||||
*/
|
*/
|
||||||
virtual void generateCode(std::ostringstream &oss,
|
virtual void generateCode(std::ostringstream &oss,
|
||||||
const std::string &evalName,
|
const std::string &evalName,
|
||||||
const std::vector<std::string> &depNames) const = 0;
|
const std::vector<std::string> &depNames) const = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function can optionally be implemented to resolve named
|
* \brief This function can optionally be implemented to resolve named
|
||||||
* program parameters to numerical IDs for increased performance.
|
* program parameters to numerical IDs for increased performance.
|
||||||
* The int array returned here will later be passed to bind().
|
*
|
||||||
|
* The int array returned here will later be passed to \ref bind().
|
||||||
* The default implementation does nothing.
|
* The default implementation does nothing.
|
||||||
*/
|
*/
|
||||||
virtual void resolve(const GPUProgram *program, const std::string &evalName,
|
virtual void resolve(const GPUProgram *program, const std::string &evalName,
|
||||||
std::vector<int> ¶meterIDs) const;
|
std::vector<int> ¶meterIDs) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure the the associated GPU program. This
|
* \brief Configure the the associated GPU program.
|
||||||
* function is typically used to bind textures and
|
*
|
||||||
|
* This function is typically used to bind textures and
|
||||||
* to set program pararameters.
|
* to set program pararameters.
|
||||||
*/
|
*/
|
||||||
virtual void bind(GPUProgram *program, const std::vector<int> ¶meterIDs,
|
virtual void bind(GPUProgram *program, const std::vector<int> ¶meterIDs,
|
||||||
int &textureUnitOffset) const;
|
int &textureUnitOffset) const;
|
||||||
|
|
||||||
/**
|
/// Release any bound resources.
|
||||||
* Release any bound resources.
|
|
||||||
*/
|
|
||||||
virtual void unbind() const;
|
virtual void unbind() const;
|
||||||
|
|
||||||
/**
|
/// Release all resources
|
||||||
* Release all resources
|
|
||||||
*/
|
|
||||||
virtual void cleanup(Renderer *renderer);
|
virtual void cleanup(Renderer *renderer);
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
|
@ -113,8 +123,9 @@ protected:
|
||||||
|
|
||||||
/// Virtual destructor
|
/// Virtual destructor
|
||||||
virtual ~Shader();
|
virtual ~Shader();
|
||||||
private:
|
protected:
|
||||||
EShaderType m_type;
|
EShaderType m_type;
|
||||||
|
uint32_t m_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/*! \plugin{dielectric}{Ideal dielectric/glass material}
|
/*! \plugin{dielectric}{Smooth dielectric material}
|
||||||
*
|
*
|
||||||
* \parameters{
|
* \parameters{
|
||||||
* \parameter{intIOR}{\Float}{Interior index of refraction \default{1.5046}}
|
* \parameter{intIOR}{\Float}{Interior index of refraction \default{1.5046}}
|
||||||
|
@ -32,21 +32,59 @@ MTS_NAMESPACE_BEGIN
|
||||||
* factor used to modulate the transmittance component\default{1.0}}
|
* factor used to modulate the transmittance component\default{1.0}}
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* This plugin models an interface between two materials having mismatched
|
* \renderings{
|
||||||
* indices of refraction (e.g. a boundary between water and air).
|
* \medrendering{Air-Water (IOR: 1$\leftrightarrow$1.33) interface, see \lstref{dielectric-water}}{bsdf_dielectric_water}
|
||||||
* The microscopic surface structure of the surface is assumed to be perfectly
|
* \medrendering{Air-Diamond (IOR: 1$\leftrightarrow$2.419)}{bsdf_dielectric_diamond}
|
||||||
* smooth, resulting in a degenerate BSDF described by a Dirac delta function.
|
* \medrendering{Air-Glass (1$\leftrightarrow$1.504) interface with absorption, see \lstref{dielectric-glass}}{bsdf_dielectric_glass}
|
||||||
* For non-smooth interfaces, please take a look at the \pluginref{roughglass}
|
* }
|
||||||
* model. When using this plugin, it is crucial that the scene contains
|
*
|
||||||
* meaningful and mutally compatible index of refraction change -- see
|
* This plugin models an interface between two dielectric materials having mismatched
|
||||||
* \figref{glass-explanation} for an example.
|
* indices of refraction (for instance, water and air). Exterior and interior IOR values
|
||||||
|
* can each be independently specified, where ``exterior'' refers to the side that contains
|
||||||
|
* the surface normal. When no parameters are given, the plugin activates the defaults, which
|
||||||
|
* describe a borosilicate glass BK7/air interface.
|
||||||
|
*
|
||||||
|
* In this model, the microscopic surface structure of the surface is assumed to be perfectly
|
||||||
|
* smooth, resulting in a degenerate\footnote{Meaning that for any given incoming ray of light,
|
||||||
|
* the model always scatters into a discrete set of directions, as opposed to a continuum.}
|
||||||
|
* BSDF described by a Dirac delta function. For a similar model that describes a rough
|
||||||
|
* surface microstructure, take a look at the \pluginref{roughglass} plugin.
|
||||||
|
*
|
||||||
|
* \begin{xml}[caption=A simple air-to-water interface, label=lst:dielectric-water]
|
||||||
|
* <shape type="...">
|
||||||
|
* <bsdf type="dielectric">
|
||||||
|
* <float name="intIOR" value="1.33"/>
|
||||||
|
* <float name="extIOR" value="1.0"/>
|
||||||
|
* </bsdf>
|
||||||
|
* <shape>
|
||||||
|
* \end{xml}
|
||||||
|
*
|
||||||
|
* When using this model, it is crucial that the scene contains
|
||||||
|
* meaningful and mutally compatible indices of refraction changes---see
|
||||||
|
* \figref{glass-explanation} for a description of what this entails.
|
||||||
|
*
|
||||||
|
* In many cases, we will want to additionally describe the \emph{medium} within a
|
||||||
|
* dielectric material. This requires the use of a rendering technique that is
|
||||||
|
* aware of media (e.g. the volumetric path tracer). An example of how one might
|
||||||
|
* describe a slightly absorbing piece of glass is given below:
|
||||||
|
*
|
||||||
|
* \begin{xml}[caption=A glass material with absorption, label=lst:dielectric-glass]
|
||||||
|
* <shape type="...">
|
||||||
|
* <bsdf type="dielectric">
|
||||||
|
* <float name="intIOR" value="1.504"/>
|
||||||
|
* <float name="extIOR" value="1.0"/>
|
||||||
|
* </bsdf>
|
||||||
|
* <medium type="homogeneous" name="interior">
|
||||||
|
* <rgb name="sigmaS" value="0, 0, 0"/>
|
||||||
|
* <rgb name="sigmaA" value="4, 4, 2"/>
|
||||||
|
* </medium>
|
||||||
|
* <shape>
|
||||||
|
* \end{xml}
|
||||||
*
|
*
|
||||||
* The default settings of this plugin are set to a borosilicate glass BK7/air
|
|
||||||
* interface.
|
|
||||||
*/
|
*/
|
||||||
class Dielectric : public BSDF {
|
class SmoothDielectric : public BSDF {
|
||||||
public:
|
public:
|
||||||
Dielectric(const Properties &props)
|
SmoothDielectric(const Properties &props)
|
||||||
: BSDF(props) {
|
: BSDF(props) {
|
||||||
/* Specifies the internal index of refraction at the interface */
|
/* Specifies the internal index of refraction at the interface */
|
||||||
m_intIOR = props.getFloat("intIOR", 1.5046f);
|
m_intIOR = props.getFloat("intIOR", 1.5046f);
|
||||||
|
@ -66,7 +104,7 @@ public:
|
||||||
m_usesRayDifferentials = false;
|
m_usesRayDifferentials = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dielectric(Stream *stream, InstanceManager *manager)
|
SmoothDielectric(Stream *stream, InstanceManager *manager)
|
||||||
: BSDF(stream, manager) {
|
: BSDF(stream, manager) {
|
||||||
m_intIOR = stream->readFloat();
|
m_intIOR = stream->readFloat();
|
||||||
m_extIOR = stream->readFloat();
|
m_extIOR = stream->readFloat();
|
||||||
|
@ -81,7 +119,7 @@ public:
|
||||||
m_usesRayDifferentials = false;
|
m_usesRayDifferentials = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~Dielectric() {
|
virtual ~SmoothDielectric() {
|
||||||
delete[] m_type;
|
delete[] m_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,7 +377,7 @@ public:
|
||||||
|
|
||||||
std::string toString() const {
|
std::string toString() const {
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "Dielectric[" << endl
|
oss << "SmoothDielectric[" << endl
|
||||||
<< " intIOR = " << m_intIOR << "," << endl
|
<< " intIOR = " << m_intIOR << "," << endl
|
||||||
<< " extIOR = " << m_extIOR << "," << endl
|
<< " extIOR = " << m_extIOR << "," << endl
|
||||||
<< " specularReflectance = " << indent(m_specularReflectance->toString()) << "," << endl
|
<< " specularReflectance = " << indent(m_specularReflectance->toString()) << "," << endl
|
||||||
|
@ -348,6 +386,8 @@ public:
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shader *createShader(Renderer *renderer) const;
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
private:
|
private:
|
||||||
Float m_intIOR, m_extIOR;
|
Float m_intIOR, m_extIOR;
|
||||||
|
@ -355,7 +395,34 @@ private:
|
||||||
ref<Texture> m_specularReflectance;
|
ref<Texture> m_specularReflectance;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Fake glass shader -- it is really hopeless to visualize
|
||||||
|
this material in the VPL renderer, so let's try to do at least
|
||||||
|
something that suggests the presence of a transparent boundary */
|
||||||
|
class SmoothDielectricShader : public Shader {
|
||||||
|
public:
|
||||||
|
SmoothDielectricShader(Renderer *renderer) :
|
||||||
|
Shader(renderer, EBSDFShader) {
|
||||||
|
m_flags = ETransparent;
|
||||||
|
}
|
||||||
|
|
||||||
MTS_IMPLEMENT_CLASS_S(Dielectric, false, BSDF)
|
void generateCode(std::ostringstream &oss,
|
||||||
MTS_EXPORT_PLUGIN(Dielectric, "Dielectric BSDF");
|
const std::string &evalName,
|
||||||
|
const std::vector<std::string> &depNames) const {
|
||||||
|
oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||||
|
<< " return vec3(0.08);" << endl
|
||||||
|
<< "}" << endl;
|
||||||
|
oss << "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||||
|
<< " return vec3(0.08);" << endl
|
||||||
|
<< "}" << endl;
|
||||||
|
}
|
||||||
|
MTS_DECLARE_CLASS()
|
||||||
|
};
|
||||||
|
|
||||||
|
Shader *SmoothDielectric::createShader(Renderer *renderer) const {
|
||||||
|
return new SmoothDielectricShader(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MTS_IMPLEMENT_CLASS(SmoothDielectricShader, false, Shader)
|
||||||
|
MTS_IMPLEMENT_CLASS_S(SmoothDielectric, false, BSDF)
|
||||||
|
MTS_EXPORT_PLUGIN(SmoothDielectric, "Smooth dielectric BSDF");
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/*! \plugin{roughglass}{Rough dielectric/glass material}
|
/*! \plugin{roughglass}{Rough dielectric material}
|
||||||
* \parameters{
|
* \parameters{
|
||||||
* \parameter{distribution}{\String}{
|
* \parameter{distribution}{\String}{
|
||||||
* Specifies the type of microfacet normal distribution
|
* Specifies the type of microfacet normal distribution
|
||||||
|
@ -58,13 +58,19 @@ MTS_NAMESPACE_BEGIN
|
||||||
* factor used to modulate the transmittance component\default{1.0}}
|
* factor used to modulate the transmittance component\default{1.0}}
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
|
* \renderings{
|
||||||
|
* \medrendering{Beckmann, $\alpha$=0.2}{bsdf_dielectric_glass}
|
||||||
|
* \medrendering{Beckmann, $\alpha$=0.3}{bsdf_dielectric_glass}
|
||||||
|
* \medrendering{Beckmann, $\alpha$=0.4}{bsdf_dielectric_glass}
|
||||||
|
* }
|
||||||
|
*
|
||||||
* This plugin implements a realistic microfacet scattering model for rendering
|
* This plugin implements a realistic microfacet scattering model for rendering
|
||||||
* rough dielectric surfaces, such as ground glass. Microfacet theory
|
* rough interfaces between dielectric materials, such as a transition from air to ground glass.
|
||||||
* describes surfaces as an arrangement of unresolved and ideally specular
|
* Microfacet theory describes surfaces as an arrangement of unresolved and ideally specular
|
||||||
* facets, whose normals are given by a specially chosen \emph{microfacet
|
* facets, whose normals are given by a specially chosen \emph{microfacet
|
||||||
* distribution}. By accounting for shadowing and masking effects between
|
* distribution}. By accounting for shadowing and masking effects between
|
||||||
* these facets, it is possible to reproduce the off-specular reflections
|
* these facets, it is possible to reproduce the off-specular reflections
|
||||||
* peaks observed in measurements of real-world materials.
|
* peaks observed in real-world measurements of such materials.
|
||||||
*
|
*
|
||||||
* This plugin is essentially the ``roughened'' equivalent of the plugin
|
* This plugin is essentially the ``roughened'' equivalent of the plugin
|
||||||
* \pluginref{dielectric}. Its implementation is based on the paper
|
* \pluginref{dielectric}. Its implementation is based on the paper
|
||||||
|
@ -95,7 +101,7 @@ public:
|
||||||
m_specularReflectance = new ConstantSpectrumTexture(
|
m_specularReflectance = new ConstantSpectrumTexture(
|
||||||
props.getSpectrum("specularReflectance", Spectrum(1.0f)));
|
props.getSpectrum("specularReflectance", Spectrum(1.0f)));
|
||||||
m_specularTransmittance = new ConstantSpectrumTexture(
|
m_specularTransmittance = new ConstantSpectrumTexture(
|
||||||
props.getSpectrum("specularTransmittance", Spectrum(1.9f)));
|
props.getSpectrum("specularTransmittance", Spectrum(1.0f)));
|
||||||
|
|
||||||
Float alpha;
|
Float alpha;
|
||||||
if (props.hasProperty("alphaB")) {
|
if (props.hasProperty("alphaB")) {
|
||||||
|
@ -763,6 +769,8 @@ public:
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shader *createShader(Renderer *renderer) const;
|
||||||
|
|
||||||
MTS_DECLARE_CLASS()
|
MTS_DECLARE_CLASS()
|
||||||
private:
|
private:
|
||||||
EDistribution m_distribution;
|
EDistribution m_distribution;
|
||||||
|
@ -772,6 +780,34 @@ private:
|
||||||
Float m_intIOR, m_extIOR;
|
Float m_intIOR, m_extIOR;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Fake glass shader -- it is really hopeless to visualize
|
||||||
|
this material in the VPL renderer, so let's try to do at least
|
||||||
|
something that suggests the presence of a transparent boundary */
|
||||||
|
class RoughGlassShader : public Shader {
|
||||||
|
public:
|
||||||
|
RoughGlassShader(Renderer *renderer) :
|
||||||
|
Shader(renderer, EBSDFShader) {
|
||||||
|
m_flags = ETransparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void generateCode(std::ostringstream &oss,
|
||||||
|
const std::string &evalName,
|
||||||
|
const std::vector<std::string> &depNames) const {
|
||||||
|
oss << "vec3 " << evalName << "(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||||
|
<< " return vec3(0.08);" << endl
|
||||||
|
<< "}" << endl;
|
||||||
|
oss << "vec3 " << evalName << "_diffuse(vec2 uv, vec3 wi, vec3 wo) {" << endl
|
||||||
|
<< " return vec3(0.08);" << endl
|
||||||
|
<< "}" << endl;
|
||||||
|
}
|
||||||
|
MTS_DECLARE_CLASS()
|
||||||
|
};
|
||||||
|
|
||||||
|
Shader *RoughGlass::createShader(Renderer *renderer) const {
|
||||||
|
return new RoughGlassShader(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
MTS_IMPLEMENT_CLASS(RoughGlassShader, false, Shader)
|
||||||
MTS_IMPLEMENT_CLASS_S(RoughGlass, false, BSDF)
|
MTS_IMPLEMENT_CLASS_S(RoughGlass, false, BSDF)
|
||||||
MTS_EXPORT_PLUGIN(RoughGlass, "Rough glass BSDF");
|
MTS_EXPORT_PLUGIN(RoughGlass, "Rough glass BSDF");
|
||||||
MTS_NAMESPACE_END
|
MTS_NAMESPACE_END
|
||||||
|
|
|
@ -54,6 +54,7 @@ public:
|
||||||
/// Draw the full scene using additive blending and shadow maps
|
/// Draw the full scene using additive blending and shadow maps
|
||||||
void drawShadowedScene(const Scene *scene, const VPL &vpl) {
|
void drawShadowedScene(const Scene *scene, const VPL &vpl) {
|
||||||
const std::vector<std::pair<const TriMesh *, Transform> > meshes = m_shaderManager->getMeshes();
|
const std::vector<std::pair<const TriMesh *, Transform> > meshes = m_shaderManager->getMeshes();
|
||||||
|
const std::vector<std::pair<const TriMesh *, Transform> > transpMeshes = m_shaderManager->getTransparentMeshes();
|
||||||
const ProjectiveCamera *camera = static_cast<const ProjectiveCamera *>(scene->getCamera());
|
const ProjectiveCamera *camera = static_cast<const ProjectiveCamera *>(scene->getCamera());
|
||||||
Point2 jitter(0.5f - m_random->nextFloat(), 0.5f - m_random->nextFloat());
|
Point2 jitter(0.5f - m_random->nextFloat(), 0.5f - m_random->nextFloat());
|
||||||
Transform projectionTransform = camera->getGLProjectionTransform(jitter);
|
Transform projectionTransform = camera->getGLProjectionTransform(jitter);
|
||||||
|
@ -75,7 +76,29 @@ public:
|
||||||
m_shaderManager->unbind();
|
m_shaderManager->unbind();
|
||||||
}
|
}
|
||||||
m_renderer->endDrawingMeshes();
|
m_renderer->endDrawingMeshes();
|
||||||
|
|
||||||
m_shaderManager->drawBackground(clipToWorld, camPos, 1.0f);
|
m_shaderManager->drawBackground(clipToWorld, camPos, 1.0f);
|
||||||
|
|
||||||
|
if (transpMeshes.size() > 0) {
|
||||||
|
m_renderer->setDepthMask(false);
|
||||||
|
m_renderer->setBlendMode(Renderer::EBlendAlpha);
|
||||||
|
m_renderer->beginDrawingMeshes();
|
||||||
|
for (unsigned int j=0; j<transpMeshes.size(); j++) {
|
||||||
|
const TriMesh *mesh = transpMeshes[j].first;
|
||||||
|
bool hasTransform = !transpMeshes[j].second.isIdentity();
|
||||||
|
m_shaderManager->configure(vpl, mesh->getBSDF(), mesh->getLuminaire(),
|
||||||
|
camPos, !mesh->hasVertexNormals());
|
||||||
|
if (hasTransform)
|
||||||
|
m_renderer->pushTransform(transpMeshes[j].second);
|
||||||
|
m_renderer->drawTriMesh(mesh);
|
||||||
|
if (hasTransform)
|
||||||
|
m_renderer->popTransform();
|
||||||
|
m_shaderManager->unbind();
|
||||||
|
}
|
||||||
|
m_renderer->endDrawingMeshes();
|
||||||
|
m_renderer->setDepthMask(true);
|
||||||
|
m_renderer->setBlendMode(Renderer::EBlendNone);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool preprocess(const Scene *scene, RenderQueue *queue, const RenderJob *job,
|
bool preprocess(const Scene *scene, RenderQueue *queue, const RenderJob *job,
|
||||||
|
|
|
@ -742,9 +742,11 @@ void GLRenderer::blitQuad(bool flipVertically) {
|
||||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||||
Vector2 scrSize((float) viewport[2], (float) viewport[3]);
|
Vector2 scrSize((float) viewport[2], (float) viewport[3]);
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPushMatrix();
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
glOrtho(0, scrSize.x, scrSize.y, 0, -1, 1);
|
glOrtho(0, scrSize.x, scrSize.y, 0, -1, 1);
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glPushMatrix();
|
||||||
glLoadIdentity();
|
glLoadIdentity();
|
||||||
const Float zDepth = -1.0f;
|
const Float zDepth = -1.0f;
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
|
@ -757,6 +759,9 @@ void GLRenderer::blitQuad(bool flipVertically) {
|
||||||
glTexCoord2f(0.0f, flipVertically ? 0.0f : 1.0f);
|
glTexCoord2f(0.0f, flipVertically ? 0.0f : 1.0f);
|
||||||
glVertex3f(0.0f, scrSize.y, zDepth);
|
glVertex3f(0.0f, scrSize.y, zDepth);
|
||||||
glEnd();
|
glEnd();
|
||||||
|
glPopMatrix();
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLRenderer::drawText(const Point2i &_pos,
|
void GLRenderer::drawText(const Point2i &_pos,
|
||||||
|
@ -966,10 +971,10 @@ void GLRenderer::finish() {
|
||||||
m_queuedTriangles = 0;
|
m_queuedTriangles = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLRenderer::setColor(const Spectrum &spec) {
|
void GLRenderer::setColor(const Spectrum &spec, Float alpha) {
|
||||||
Float r, g, b;
|
Float r, g, b;
|
||||||
spec.toLinearRGB(r, g, b);
|
spec.toLinearRGB(r, g, b);
|
||||||
glColor4f(r, g, b, 1);
|
glColor4f(r, g, b, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLRenderer::setBlendMode(EBlendMode mode) {
|
void GLRenderer::setBlendMode(EBlendMode mode) {
|
||||||
|
|
|
@ -55,7 +55,7 @@ void VPLShaderManager::init() {
|
||||||
"varying float depth;\n"
|
"varying float depth;\n"
|
||||||
"\n"
|
"\n"
|
||||||
"void main() {\n"
|
"void main() {\n"
|
||||||
" depth = 0;\n" // avoid a (incorrect?) warning
|
" depth = 0;\n" // avoid an (incorrect?) warning
|
||||||
" for (int side = 0; side < 6; side++) {\n"
|
" for (int side = 0; side < 6; side++) {\n"
|
||||||
" gl_Layer = side;\n"
|
" gl_Layer = side;\n"
|
||||||
" for (int i = 0; i < gl_VerticesIn; i++) {\n"
|
" for (int i = 0; i < gl_VerticesIn; i++) {\n"
|
||||||
|
@ -134,8 +134,12 @@ void VPLShaderManager::init() {
|
||||||
GPUGeometry *gpuGeo = m_renderer->registerGeometry(triMesh);
|
GPUGeometry *gpuGeo = m_renderer->registerGeometry(triMesh);
|
||||||
Shader *shader = triMesh->hasBSDF() ?
|
Shader *shader = triMesh->hasBSDF() ?
|
||||||
m_renderer->registerShaderForResource(triMesh->getBSDF()) : NULL;
|
m_renderer->registerShaderForResource(triMesh->getBSDF()) : NULL;
|
||||||
if (shader != NULL && !shader->isComplete())
|
if (shader != NULL && !shader->isComplete()) {
|
||||||
m_renderer->unregisterShaderForResource(triMesh->getBSDF());
|
m_renderer->unregisterShaderForResource(triMesh->getBSDF());
|
||||||
|
} else if (shader->getFlags() & Shader::ETransparent) {
|
||||||
|
m_transparentMeshes.push_back(std::make_pair(triMesh.get(), instance->getWorldTransform()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
m_meshes.push_back(std::make_pair(triMesh.get(), instance->getWorldTransform()));
|
m_meshes.push_back(std::make_pair(triMesh.get(), instance->getWorldTransform()));
|
||||||
if (gpuGeo)
|
if (gpuGeo)
|
||||||
m_drawList.push_back(std::make_pair(gpuGeo, instance->getWorldTransform()));
|
m_drawList.push_back(std::make_pair(gpuGeo, instance->getWorldTransform()));
|
||||||
|
@ -146,8 +150,12 @@ void VPLShaderManager::init() {
|
||||||
GPUGeometry *gpuGeo = m_renderer->registerGeometry(triMesh);
|
GPUGeometry *gpuGeo = m_renderer->registerGeometry(triMesh);
|
||||||
Shader *shader = triMesh->hasBSDF() ?
|
Shader *shader = triMesh->hasBSDF() ?
|
||||||
m_renderer->registerShaderForResource(triMesh->getBSDF()) : NULL;
|
m_renderer->registerShaderForResource(triMesh->getBSDF()) : NULL;
|
||||||
if (shader != NULL && !shader->isComplete())
|
if (shader != NULL && !shader->isComplete()) {
|
||||||
m_renderer->unregisterShaderForResource(triMesh->getBSDF());
|
m_renderer->unregisterShaderForResource(triMesh->getBSDF());
|
||||||
|
} else if (shader->getFlags() & Shader::ETransparent) {
|
||||||
|
m_transparentMeshes.push_back(std::make_pair(triMesh.get(), Transform()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
m_meshes.push_back(std::make_pair(triMesh.get(), Transform()));
|
m_meshes.push_back(std::make_pair(triMesh.get(), Transform()));
|
||||||
if (gpuGeo)
|
if (gpuGeo)
|
||||||
m_drawList.push_back(std::make_pair(gpuGeo, Transform()));
|
m_drawList.push_back(std::make_pair(gpuGeo, Transform()));
|
||||||
|
@ -353,7 +361,6 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
||||||
: m_renderer->getShaderForResource(luminaire);
|
: m_renderer->getShaderForResource(luminaire);
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
|
|
||||||
|
|
||||||
if (bsdfShader == NULL || vplShader == NULL ||
|
if (bsdfShader == NULL || vplShader == NULL ||
|
||||||
(luminaire != NULL && lumShader == NULL)) {
|
(luminaire != NULL && lumShader == NULL)) {
|
||||||
/* Unsupported! */
|
/* Unsupported! */
|
||||||
|
@ -361,6 +368,13 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (bsdfShader->getFlags() & Shader::ETransparent) {
|
||||||
|
m_renderer->setColor(Spectrum(1.0f), 0.3f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool anisotropic = bsdf->getType() & BSDF::EAnisotropic;
|
bool anisotropic = bsdf->getType() & BSDF::EAnisotropic;
|
||||||
|
|
||||||
m_targetConfig = VPLProgramConfiguration(vplShader, bsdfShader,
|
m_targetConfig = VPLProgramConfiguration(vplShader, bsdfShader,
|
||||||
|
@ -464,7 +478,7 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
||||||
<< "/* Uniform inputs */" << endl
|
<< "/* Uniform inputs */" << endl
|
||||||
<< "uniform samplerCube shadowMap;" << endl
|
<< "uniform samplerCube shadowMap;" << endl
|
||||||
<< "uniform vec3 vplPower, vplS, vplT, vplN, vplWi;" << endl
|
<< "uniform vec3 vplPower, vplS, vplT, vplN, vplWi;" << endl
|
||||||
<< "uniform float nearClip, invClipRange, minDist;" << endl
|
<< "uniform float nearClip, invClipRange, minDist, alpha;" << endl
|
||||||
<< "uniform vec2 vplUV;" << endl
|
<< "uniform vec2 vplUV;" << endl
|
||||||
<< "uniform bool diffuseSources, diffuseReceivers;" << endl
|
<< "uniform bool diffuseSources, diffuseReceivers;" << endl
|
||||||
<< "varying vec3 vertexColor;" << endl
|
<< "varying vec3 vertexColor;" << endl
|
||||||
|
@ -546,7 +560,7 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
||||||
} else {
|
} else {
|
||||||
oss << ";" << endl;
|
oss << ";" << endl;
|
||||||
}
|
}
|
||||||
oss << " gl_FragColor.a = 1.0;" << endl
|
oss << " gl_FragColor.a = alpha;" << endl
|
||||||
<< "}" << endl;
|
<< "}" << endl;
|
||||||
|
|
||||||
program->setSource(GPUProgram::EFragmentProgram, oss.str());
|
program->setSource(GPUProgram::EFragmentProgram, oss.str());
|
||||||
|
@ -572,6 +586,7 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
||||||
m_targetConfig.param_minDist = program->getParameterID("minDist", false);
|
m_targetConfig.param_minDist = program->getParameterID("minDist", false);
|
||||||
m_targetConfig.param_diffuseSources = program->getParameterID("diffuseSources", false);
|
m_targetConfig.param_diffuseSources = program->getParameterID("diffuseSources", false);
|
||||||
m_targetConfig.param_diffuseReceivers = program->getParameterID("diffuseReceivers", false);
|
m_targetConfig.param_diffuseReceivers = program->getParameterID("diffuseReceivers", false);
|
||||||
|
m_targetConfig.param_alpha = program->getParameterID("alpha", false);
|
||||||
m_current.program = program;
|
m_current.program = program;
|
||||||
m_current.config = m_targetConfig;
|
m_current.config = m_targetConfig;
|
||||||
m_programs[configName] = m_current;
|
m_programs[configName] = m_current;
|
||||||
|
@ -589,11 +604,16 @@ void VPLShaderManager::configure(const VPL &vpl, const BSDF *bsdf,
|
||||||
program->setParameter(config.param_vplN, vpl.its.shFrame.n);
|
program->setParameter(config.param_vplN, vpl.its.shFrame.n);
|
||||||
program->setParameter(config.param_vplS, vpl.its.shFrame.s);
|
program->setParameter(config.param_vplS, vpl.its.shFrame.s);
|
||||||
program->setParameter(config.param_vplT, vpl.its.shFrame.t);
|
program->setParameter(config.param_vplT, vpl.its.shFrame.t);
|
||||||
|
|
||||||
|
program->setParameter(config.param_alpha,
|
||||||
|
bsdfShader->getFlags() & Shader::ETransparent ? 0.5f : 1.0f);
|
||||||
|
|
||||||
if (vpl.type == ESurfaceVPL) {
|
if (vpl.type == ESurfaceVPL) {
|
||||||
program->setParameter(config.param_vplWi, vpl.its.wi);
|
program->setParameter(config.param_vplWi, vpl.its.wi);
|
||||||
program->setParameter(config.param_vplUV, vpl.its.uv);
|
program->setParameter(config.param_vplUV, vpl.its.uv);
|
||||||
program->setParameter(config.param_diffuseSources, m_diffuseSources);
|
program->setParameter(config.param_diffuseSources, m_diffuseSources);
|
||||||
}
|
}
|
||||||
|
|
||||||
Spectrum power = vpl.P;
|
Spectrum power = vpl.P;
|
||||||
if (m_diffuseSources && vpl.type == ESurfaceVPL)
|
if (m_diffuseSources && vpl.type == ESurfaceVPL)
|
||||||
power *= vpl.its.shape->getBSDF()->getDiffuseReflectance(vpl.its) * INV_PI;
|
power *= vpl.its.shape->getBSDF()->getDiffuseReflectance(vpl.its) * INV_PI;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
MTS_NAMESPACE_BEGIN
|
MTS_NAMESPACE_BEGIN
|
||||||
|
|
||||||
Shader::Shader(Renderer *renderer, EShaderType type)
|
Shader::Shader(Renderer *renderer, EShaderType type)
|
||||||
: m_type(type) {
|
: m_type(type), m_flags(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader::~Shader() {
|
Shader::~Shader() {
|
||||||
|
|
|
@ -473,6 +473,7 @@ void PreviewThread::run() {
|
||||||
|
|
||||||
void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
||||||
const std::vector<std::pair<const TriMesh *, Transform> > meshes = m_shaderManager->getMeshes();
|
const std::vector<std::pair<const TriMesh *, Transform> > meshes = m_shaderManager->getMeshes();
|
||||||
|
const std::vector<std::pair<const TriMesh *, Transform> > transpMeshes = m_shaderManager->getTransparentMeshes();
|
||||||
|
|
||||||
m_shaderManager->setVPL(vpl);
|
m_shaderManager->setVPL(vpl);
|
||||||
|
|
||||||
|
@ -510,6 +511,26 @@ void PreviewThread::oglRenderVPL(PreviewQueueEntry &target, const VPL &vpl) {
|
||||||
m_renderer->endDrawingMeshes();
|
m_renderer->endDrawingMeshes();
|
||||||
m_shaderManager->drawBackground(clipToWorld, camPos,
|
m_shaderManager->drawBackground(clipToWorld, camPos,
|
||||||
m_backgroundScaleFactor);
|
m_backgroundScaleFactor);
|
||||||
|
if (transpMeshes.size() > 0) {
|
||||||
|
m_renderer->setDepthMask(false);
|
||||||
|
m_renderer->setBlendMode(Renderer::EBlendAlpha);
|
||||||
|
m_renderer->beginDrawingMeshes();
|
||||||
|
for (size_t j=0; j<transpMeshes.size(); j++) {
|
||||||
|
const TriMesh *mesh = transpMeshes[j].first;
|
||||||
|
bool hasTransform = !transpMeshes[j].second.isIdentity();
|
||||||
|
m_shaderManager->configure(vpl, mesh->getBSDF(),
|
||||||
|
mesh->getLuminaire(), camPos, !mesh->hasVertexNormals());
|
||||||
|
if (hasTransform)
|
||||||
|
m_renderer->pushTransform(transpMeshes[j].second);
|
||||||
|
m_renderer->drawTriMesh(mesh);
|
||||||
|
if (hasTransform)
|
||||||
|
m_renderer->popTransform();
|
||||||
|
m_shaderManager->unbind();
|
||||||
|
}
|
||||||
|
m_renderer->endDrawingMeshes();
|
||||||
|
m_renderer->setBlendMode(Renderer::EBlendNone);
|
||||||
|
m_renderer->setDepthMask(true);
|
||||||
|
}
|
||||||
m_framebuffer->releaseTarget();
|
m_framebuffer->releaseTarget();
|
||||||
|
|
||||||
target.buffer->activateTarget();
|
target.buffer->activateTarget();
|
||||||
|
|
Loading…
Reference in New Issue