花了一周的时间研究CG shader,做一个地形多重纹理混合,看一下效果
渲染后的图
我主要看的是 《focus on terrain programing》,在地形纹理那章用的就是四张小的纹理图,依据高度生一张新纹理图,然后对于实际大规模地形,无法生成这样的大图片。我这里没有生成大的纹理图,直接使用四张小纹理图,然后依据高度,自动混合纹理,混合采用cg shader 编程,下面详细介绍。
首先创建cg顶点着色器,像素着色器程序,像毒着色器程序带有4个参数,为具体的四张纹理图。
void MulTexBlend::initCg()
{
//initGlew();
m_CgContext=cgCreateContext();
checkForCgError("create contex");
cgGLSetDebugMode(CG_FALSE);
cgSetParameterSettingMode(m_CgContext,CG_DEFERRED_PARAMETER_SETTING);
/**//// VertexProfile
m_CgVertexProfile=cgGLGetLatestProfile(CG_GL_VERTEX);
cgGLSetOptimalOptions(m_CgVertexProfile);
m_CgVertexProgram =
cgCreateProgramFromFile(
m_CgContext,
CG_SOURCE,
m_VertexProgramFileName,
m_CgVertexProfile,
m_VertexProgramName,
NULL
);
checkForCgError("creating vertex program from file");
cgGLLoadProgram(m_CgVertexProgram);
m_CgVertexParam_modelViewProj = cgGetNamedParameter(m_CgVertexProgram,"modelViewProj");
/**////Fragment program
m_CgFragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
cgGLSetOptimalOptions(m_CgFragmentProfile);
checkForCgError("selecting fragment profile");
m_CgFragmentProgram =
cgCreateProgramFromFile(
m_CgContext, /**//* Cg runtime context */
CG_SOURCE, /**//* Program in human-readable form */
m_FragmentProgramFileName, /**//* Name of file containing program */
m_CgFragmentProfile, /**//* Profile: OpenGL ARB vertex program */
m_FragmentProgramName, /**//* Entry function name */
NULL); /**//* No extra compiler options */
checkForCgError("creating fragment program from file");
cgGLLoadProgram(m_CgFragmentProgram);
checkForCgError("loading fragment program");
m_CgFragmentParam_tex1 =
cgGetNamedParameter(m_CgFragmentProgram, "tex1");
checkForCgError("getting decal parameter");
m_CgFragmentParam_tex2 =
cgGetNamedParameter(m_CgFragmentProgram, "tex2");
checkForCgError("getting decal parameter");
m_CgFragmentParam_tex3=
cgGetNamedParameter(m_CgFragmentProgram, "tex3");
checkForCgError("getting decal parameter");
m_CgFragmentParam_tex4=
cgGetNamedParameter(m_CgFragmentProgram, "tex4");
checkForCgError("getting decal parameter");
//m_CgFragmentParam_weight0=cgGetNamedParameter(m_CgFragmentProgram,"weight0");
//checkForCgError("getting decal parameter");
//m_CgFragmentParam_weight1=cgGetNamedParameter(m_CgFragmentProgram,"weight1");
//checkForCgError("getting decal parameter");
}
载入纹理,我这里用了四张纹理
void MulTexBlend::loadTexImage(const char *tex1file,const char *tex2file,const char * tex3file,const char * tex4file)
{
m_tex1=wzw::Texture::LoadGLTexture(tex1file,GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, true);
m_tex2=wzw::Texture::LoadGLTexture(tex2file,GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, true);
m_tex3=wzw::Texture::LoadGLTexture(tex3file,GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, true);
m_tex4=wzw::Texture::LoadGLTexture(tex4file,GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, true);
cgGLSetTextureParameter(m_CgFragmentParam_tex1,m_tex1);
checkForCgError("setting decal 2D texture");
cgGLSetTextureParameter(m_CgFragmentParam_tex2,m_tex2);
checkForCgError("setting decal 2D texture");
cgGLSetTextureParameter(m_CgFragmentParam_tex3,m_tex3);
checkForCgError("setting decal 2D texture");
cgGLSetTextureParameter(m_CgFragmentParam_tex4,m_tex4);
checkForCgError("setting decal 2D texture");
}
上面的代码主要创建四张纹理,并设定cg fragment program的参数,没有什么可说的,主要提一下纹理的参数设置,如下:
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
gluBuild2DMipmaps( GL_TEXTURE_2D,GL_RGB, wid, hei, GL_BGR_EXT,
GL_UNSIGNED_BYTE,data );
接下来我们画地形三角网格。首先对地形每个顶点,按照高度计算四张图的纹理分理,具体的计算方法可详细参照(focus on terrain proraming)。对于四张纹理,将地形的高度划分成5个段,为每一张纹理设定一个范围。第一张图高度范围1-2段,第二张图2,3段。我的设定划分段的代码如下:
float lh=minh;
float hh=maxh;
float seg=(hh-lh)/(TEX_NUM+1);
m_ragion[0][0]=lh;
m_ragion[0][1]=lh+seg;
m_ragion[0][2]=m_ragion[0][1]+seg;
for(int i=1;i<TEX_NUM;i++)
{
m_ragion[i][0]=m_ragion[i-1][1]+1;
m_ragion[i][1]=m_ragion[i-1][2]+1;
m_ragion[i][2]=m_ragion[i][1]+seg;
}
接下来为每一个顶点,通过高度计算四个纹理的分理。每一顶点附带一个float m_wight[4];
void comput_weight(const float &height)
{
if(height<m_ragion[0][1])
{
m_weight[0]=1;
m_weight[1]=0;
m_weight[2]=0;
m_weight[3]=0;
}else if(height>m_ragion[TEX_NUM][2])
{
m_weight[0]=0;
m_weight[1]=0;
m_weight[2]=0;
m_weight[3]=1;
}
for(int i=0;i<4;i++)
m_weight[i]=comput_weigth(height,m_ragion[i][0],m_ragion[i][1],m_ragion[i][2]);
}
static inline float comput_weigth(const float &height,const float &lowh,const float &opth,const float &hih)
{
if(height<lowh || height>hih)
return 0;
float ftemp1,ftepm2;
if(height<opth)
{
ftemp1=height-lowh;
ftepm2=opth-lowh;
return ftemp1/ftepm2;
}else if(height==opth)
{
return 1;
}else
{
ftemp1=hih-height;
ftepm2=hih-opth;
return ftemp1/ftepm2;
}
}
准备工作已经完成,现在开始画地形三角网格。
1.启用cg顶点着色器程序,片断着色器程序,(顶点着色器程序,片断着色器的CG 代码在后面详细讲解)
cgGLBindProgram(m_CgVertexProgram);
checkForCgError("bind vertex program");
cgGLEnableProfile(m_CgVertexProfile);
checkForCgError("enabling vertex profile");
cgGLSetStateMatrixParameter(m_CgVertexParam_modelViewProj,CG_GL_MODELVIEW_PROJECTION_MATRIX,CG_GL_MATRIX_IDENTITY);
checkForCgError("set matrix");
cgGLBindProgram(m_CgFragmentProgram);
checkForCgError("binding fragment program");
cgGLEnableProfile(m_CgFragmentProfile);
checkForCgError("enabling fragment profile");
cgGLEnableTextureParameter(m_CgFragmentParam_tex1);
checkForCgError("enable decal texture");
cgGLEnableTextureParameter(m_CgFragmentParam_tex2);
checkForCgError("enable decal texture");
cgGLEnableTextureParameter(m_CgFragmentParam_tex3);
checkForCgError("enable decal texture");
cgGLEnableTextureParameter(m_CgFragmentParam_tex4);
checkForCgError("enable decal texture");
2 开始绘制三角面片网格,并将纹理分量weight通过颜色,传入cg vertex program.
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,m_tex1);
glActiveTexture(GL_TEXTURE1);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,m_tex2);
glActiveTexture(GL_TEXTURE2);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,m_tex3);
glActiveTexture(GL_TEXTURE3);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,m_tex4);
glBegin(GL_TRIANGLES);
for(int i=start;i<end;i++)
{
for(int j=0;j<3;j++)
{
const point &p=tri_list(i,j);
float height=tri_list.height((tri_list(i))[j]);
this->get_tex_heigt(p,height);
glMultiTexCoord2f(GL_TEXTURE0,m_coorx,m_coory);
glMultiTexCoord2f(GL_TEXTURE1,m_coorx,m_coory);
glMultiTexCoord2f(GL_TEXTURE2,m_coorx,m_coory);
glMultiTexCoord2f(GL_TEXTURE3,m_coorx,m_coory);
glColor4f(m_weight[0],m_weight[1],m_weight[2],m_weight[3]);
glVertex3f(p[0],p[1],p[2]);
}
3 disable cg 顶点着色器,片断着色器程序。(不关的话影响下面的别的绘制涵数)
cgGLDisableProfile(m_CgVertexProfile);
checkForCgError("disabling vertex profile");
cgGLDisableProfile(m_CgFragmentProfile);
checkForCgError("disabling fragment profile");
cgGLDisableTextureParameter(m_CgFragmentParam_tex1);
checkForCgError("disabling decal texture");
cgGLDisableTextureParameter(m_CgFragmentParam_tex2);
checkForCgError("disabling decal texture");
这样就行了,下面主要讲一下cg sharder,首先顶点着色程序主要做opengl固定流水线做的操作,将三维顶点坐标换算成屏幕坐标。然后将颜色分量传给片断程序,COLOR0,就是输入的颜色,我把这里颜色当成纹理分量。
uniform float4x4 modelViewProj : state.matrix.mvp;
void C3E5v_twoTextures(float4 position : POSITION
,float4 icolor : COLOR0
,float2 itcoor1 : TEXCOORD0
,float2 itcoor2 : TEXCOORD1
,float2 itcoor3 : TEXCOORD2
,float2 itcoor4 : TEXCOORD3
,out float4 oPosition : POSITION
,out float4 weight : COLOR0
,out float2 otcoor1 : TEXCOORD0
,out float2 otcoor2 : TEXCOORD1
,out float2 otcoor3 : TEXCOORD2
,out float2 otcoor4 : TEXCOORD3
)
{
//modelviewproj 视图模型矩阵,由opengl传入的
oPosition = mul(modelViewProj, position);
otcoor1=itcoor1;
otcoor2=itcoor2;
otcoor3=itcoor3;
otcoor4=itcoor4;
weight=icolor;
}
主要部分工作是还像素着色器,根据四个分理计算新的颜色
uniform
void C3E6f_twoTextures( float2 texcoor1 : TEXCOORD0
,float2 texcoor2 : TEXCOORD1
,float2 texcoor3 : TEXCOORD2
,float2 texcoor4 : TEXCOORD3
,float4 weight:COLOR0
,out float4 color : COLOR
,uniform sampler2D tex1
,uniform sampler2D tex2
,uniform sampler2D tex3
,uniform sampler2D tex4)
{
float4 color1 = tex2D(tex1, texcoor1);
float4 color2 = tex2D(tex2, texcoor2);
float4 color3 = tex2D(tex3, texcoor3);
float4 color4 = tex2D(tex4, texcoor4);
color = color1 *weight.r + color2 * weight.g + color3*weight.b + color4 * weight.a ;
}
这部分的代码相当简单,就是到四张纹理图的颜色,然后根据weight计算新颜色,输出即可。
到这里也就全部完成了,主要提出的我程序中并没有生成大的纹理图,而是有CG sharder计算出混合颜色输出的。在这里赞一下CG实在是强大啊,还在努力学中......
QQ:107831550
王志伟
kuramawzw@163.com
posted on 2010-04-22 15:37
kuramawzw 阅读(4958)
评论(0) 编辑 收藏 引用 所属分类:
图形(opengl)