接着这篇文章:https://blog.csdn.net/wodownload2/article/details/104273629
我们继续。
1.如何加载brdf文件,brdf文件是里面是什么函数?
BRDFBase.cpp中:
bool BRDFBase::loadBRDF( const char* filename )
- BRDF文件所在位置:
3.BRDF内容分析举例
以d_ggx.brdf为例子:
analytic
# ggx from Walter 07
# variables go here...
# only floats supported right now.
# [type] [name] [min val] [max val] [default val]
::begin parameters
float alpha 0.001 1 .1 //最小值,最大值,默认值
::end parameters
# Then comes the shader. This should be GLSL code
# that defines a function called BRDF (although you can
# add whatever else you want too, like sqr() below).
::begin shader
const float PI = 3.14159265358979323846;
float sqr(float x) { return x*x; }
float GGX(float alpha, float cosThetaM)
{
float CosSquared = cosThetaM*cosThetaM;
float TanSquared = (1-CosSquared)/CosSquared;
return (1.0/PI) * sqr(alpha/(CosSquared * (alpha*alpha + TanSquared)));
}
vec3 BRDF( vec3 L, vec3 V, vec3 N, vec3 X, vec3 Y )
{
vec3 H = normalize( L + V );
float D = GGX(alpha, dot(N,H));
return vec3(D);
}
::end shader
BRDF函数调用GGX函数。
读取的细细分析:
BRDFBase* b = NULL; //基类指针
bool success = false; //bool变量
// .brdf is an analytic BRDF file
else if( extension == "brdf" )
{
b = new BRDFAnalytic;
success = b->loadBRDF( filename.c_str() );
}
读取第一行:
std::ifstream ifs( filename );
std::string line, trimmedLine;
// first line needs to be the BRDF type
if( !getline( ifs, line ) )
return false;
判断读取的类型:
// make sure we know how to read this
std::string type = trim(line);
type = type.substr( 0, type.find( ' ' ) );
if( type != "analytic" && type != "bparam" )
return false;
接下来是逐行读取:
while( getline( ifs, line ) )
{
trimmedLine = line;
trim( trimmedLine );
// skip blank lines
if( trimmedLine.length() == 0 )
continue;
// skip comments
if( trimmedLine[0] == '#' )
continue;
处理参数:
处理float的代码:
else if( token == "float" )
{
std::string name;
float min, max, value;
os >> name;
os >> min;
os >> max;
os >> value;
addFloatParameter( name, min, max, value );
}
float类型的结构体:
struct brdfFloatParam
{
std::string name;
float minVal;
float maxVal;
float defaultVal;
float currentVal;
};
实例化一个float结构体,然后添加到列表中去:
void BRDFBase::addFloatParameter( std::string name, float min, float max, float value )
{
brdfFloatParam param;
param.name = name;
param.minVal = min;
param.maxVal = max;
param.defaultVal = value;
param.currentVal = value;
floatParameters.push_back( param );
parameterTypes.push_back( BRDF_VAR_FLOAT );
}
参数读取完毕之后,就是一行一行读取shader,进行拼接:
bool BRDFAnalytic::processLineFromSection( std::string section, std::string line )
{
if( section == "shader" )
shader = shader + line + std::string("\n");
else if( section == "isFunc" )
isFunc = isFunc + line + std::string("\n");
return true;
}
以画一个球体为例子:
LitSphereWidget类中的drawSphere方法:
准备shader:
void LitSphereWidget::drawSphere( double r, int lats, int longs )
{
DGLShader* shader = NULL;
// if there's a BRDF, the BRDF pbject sets up and enables the shader
if( brdfs.size() )
{
shader = brdfs[0].brdf->getUpdatedShader( SHADER_LITSPHERE, &brdfs[0] );
shader->setUniformMatrix4("projectionMatrix", glm::value_ptr(projectionMatrix));
shader->setUniformMatrix4("modelViewMatrix", glm::value_ptr(modelViewMatrix));
shader->setUniformFloat( "incidentVector", incidentVector[0], incidentVector[1], incidentVector[2] );
shader->setUniformFloat( "incidentTheta", inTheta );
shader->setUniformFloat( "incidentPhi", inPhi );
shader->setUniformFloat( "brightness", brightness );
shader->setUniformFloat( "gamma", gamma );
shader->setUniformFloat( "exposure", exposure );
shader->setUniformFloat( "useNDotL", useNDotL ? 1.0 : 0.0 );
}
这里的brdfs是一个集合,从集合中拿出第0个位置的brdf函数。
然后将读取出来的BRDF函数插入到指定的shader中去:getBRDFFunction就是获取brdf函数。
bool BRDFBase::compileShader( DGLShader*& shader, std::string vs, std::string fs, std::string gs )
{
// nuke the shader if it exists
if( shader )
delete shader;
// here's the tricky bit: load the shader templates, sticking in the BRDF function where needed
std::string vertShader = loadShaderFromFile( vs, getBRDFFunction(), getISFunction() );
std::string fragShader = loadShaderFromFile( fs, getBRDFFunction(), getISFunction() );
/*
printf( "==========\n" );
printf( "%s\n", fragShader.c_str() );
printf( "==========\n" );
*/
// try and compile it
//IC: This expects file names!s
// shader = new DGLShader( vertShader, fragShader );
shader = new DGLShader();
shader->setVertexShaderFromString(vertShader);
shader->setFragmentShaderFromString(fragShader);
if(!gs.empty())
shader->setGeometryShaderFromFile(gs);
shader->create();
return shader->ready();
}
然后就是将shader塞到sphere中进行绘制,绘制的部分代码如下:
void Sphere::draw(const DGLShader *shader)
{
if (!_ready) {
init();
}
glf->glBindVertexArray(_vao);
int vertex_loc = shader->getAttribLocation("vtx_position");
if(vertex_loc>=0){
glf->glBindBuffer(GL_ARRAY_BUFFER, _bufs[1]);
glf->glVertexAttribPointer(vertex_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
glf->glEnableVertexAttribArray(vertex_loc);
}
int color_loc = shader->getAttribLocation("vtx_color");
if(color_loc>=0){
glf->glBindBuffer(GL_ARRAY_BUFFER, _bufs[2]);
glf->glVertexAttribPointer(color_loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
glf->glEnableVertexAttribArray(color_loc);
}
ok,就有了: