海洋个人博客

喜欢自由的飞翔!

Cocos2d-x 3.x 图形学渲染系列二十二

笔者介绍:姜雪伟IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

环境映射是一种用来模拟光滑表面对周围环境的反射技术,常见的如镜子、光亮漆面的金属等等。这种技术的实现主要通过将一张带有周围环境的贴图附在所需要表现的多边形表面来实现的。

目前在实时3D游戏画面渲染中经常使用的有两种环境映射:球形环境映射和立方体环境映射。   

市面上很多引擎自身提供了这种功能,但是Cocos2d-x引擎并没有为开发者提供球形映射渲染效果,它只提供了立方体环境映射Shader比如天空盒的环境映射,球形环境映射效果需开发者自己实现,球形环境映射效果的实现只需要一张贴图就可以完成,反射渲染效果也是在Shader中实现的,先说一下其实现思路:

   球形环境映射是模拟在球体表面产生环境映射的技术,通过对普通贴图的UV坐标进行调整计算来产生在球体表面应产生的扭曲。

    UV的计算利用球体表面的法线来计算。计算公式如下:

    u=Nx/2+0.5

    v=Ny/2+0.5

    计算公式中的Nx和Ny是表面法线的x和y分量,除以2将区间限制在[-0.5,0.5],+0.5将区间调整至UV坐标应在的[0,1]区间。在这个公式的计算下,当球体正中表面法线正对摄像机的地方,坐标不会有任何扭曲;周围点依次随着Nx和Ny分量的增大而产生扭曲。球体背面的剔除面可以根据法线Z分量的正负来判断。

下面根据上述思路先从Shader编程中的顶点着色器开始,顶点着色器完整代码如下所示:

attribute vec4 a_position;
attribute vec3 a_normal;
varying vec2 env_mapping_index;

void main(void)
{
	vec3 v_normalVector = normalize(CC_NormalMatrix * a_normal);
	
	env_mapping_index.x = v_normalVector.x / 2.0 + 0.5;
	env_mapping_index.y = v_normalVector.y / 2.0 + 0.5;
	
	gl_Position = CC_MVPMatrix * a_position;
}

顶点着色器计算的反射位置env_mapping_index会传到片段着色器中,片段着色器实现完整代码如下所示:

#ifdef GL_ES
varying medium vec2 v_texture_coord;
precision medium float;
#else
varying vec2 v_texture_coord;
#endif

uniform sampler2D sampler_env;

varying vec2 env_mapping_index;

void main(void)
{
   gl_FragColor=vec4((texture2D(sampler_env,vec2(env_mapping_index.x, 1 - env_mapping_index.y))).rgb,1.0);  
}

它通过texture2D函数将反射信息提取出来,函数最后一位表示的是模型的透明度,1.0表示的是完全不透明,0.0表示的是完全透明。编写完成片段着色器和顶点着色器后,还需要一张反射贴图供模型材质使用,反射贴图如下:


贴图和shader脚本完成后,接下来将其在代码中的效果实现出来,先把模型加载出来,程序代码片段如下所示:

	auto sprite_Zerkalo = Sprite3D::create("astronaut/Zerkalo.c3t");
	sprite_Base->addChild(sprite_Zerkalo);
	sprite_Zerkalo->setRotation3D(Vec3(90, 0, 0));
	sprite_Zerkalo->setPosition3D(Vec3(0, 0, 0));

继续代码的编写,下面是对顶点着色器和片段着色器的加载以及反射贴图的加载如下所示:

auto glprogram_Zerkalo = GLProgram::createWithFilenames("astronaut/zerkalo.vert", "astronaut/zerkalo.frag");
	auto _state_Zerkalo = GLProgramState::getOrCreateWithGLProgram(glprogram_Zerkalo);
	sprite_Zerkalo->setGLProgramState(_state_Zerkalo);
	//加载反射贴图
	auto textrue_astronaut = Director::getInstance()->getTextureCache()->addImage("astronaut/mars.png");
	Texture2D::TexParams		tRepeatParams2;
	tRepeatParams2.magFilter = GL_LINEAR;
	tRepeatParams2.minFilter = GL_LINEAR;
	tRepeatParams2.wrapS = GL_CLAMP_TO_EDGE;
	tRepeatParams2.wrapT = GL_CLAMP_TO_EDGE;
	textrue_astronaut->setTexParameters(tRepeatParams2);
	_state_Zerkalo->setUniformTexture("sampler_env", textrue_astronaut);

该代码段实现的是把环境反射的贴图在模型上渲染出来,操作步骤是首先加载顶点着色器和片段着色器,接着加载反射图片,最后将图片传给GPU去处理,整个流程就完成了。下面展示一下效果图:



宇航员头盔展示的是反射贴图效果,是不是感觉非常赞?



阅读更多

扫码向博主提问

去开通我的Chat快问

jxw167

博客专家

非学,无以致疑;非问,无以广识
  • 擅长领域:
  • 3D引擎架构
  • 服务器架构
  • GPU渲染
  • 客户端架构
  • 引擎优化
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jxw167/article/details/54694335
个人分类: 图形学编程
上一篇学习游戏服务器编程提高篇
下一篇详解Unity3D Shader开发之渲染管线
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭