A9VG电玩部落论坛

 找回密码
 注册
搜索
查看: 2643|回复: 0

html5游戏开发告诉你什么是3D雾化效果实现

[复制链接]

精华
0
帖子
1
威望
0 点
积分
1 点
种子
5 点
注册时间
2014-7-6
最后登录
2024-1-27
 楼主| 发表于 2015-7-24 19:15  ·  福建 | 显示全部楼层 |阅读模式
  今天这篇教程html5游戏开发来讲一下游戏中的雾化效果以及如何在Cocos2d-x中加入雾化的效果。下面html5游戏开发就先来讲一下游戏中为什么要加入雾化效果以及雾化的原理。

  雾化效果就是远处看的模糊,一种类似于大气效果。雾是在执行了矩阵变换,光照,纹理后才会应用,因此雾化效果对上述内容都会产生印象。在大型游戏项目中雾化可以提高性能,因为他可以选择不绘画因为雾气影响而看不见的物体,这就是为什么我们要加入雾化的原因,当然有时我们可能是真的需要雾化的效果。

  

  说完了为什么要加入雾化,下面我们来说下雾化的原理:把片断(fragment)颜色和雾颜色以一定比例混合,就能产生雾的效果。

  

  比例因子f,主要有三种计算混合因子的方法,如下面的三个等式所示,其中c指的是眼睛坐标与片段中心之间的距离或者是雾坐标,通过等式计算出个的因子f,需要缩放至[0,1]范围内。

  

  雾的工作模式有三种:线性模式,指数模式和指数平方模式。这三种模式是根据雾的浓度变化来区分的。在线性模式下,只需要提供一个距离视点的开始位置和结束位置。从开始位置到结束位置之间,雾的浓度越来越高,浓度的变化和距离成正比。在指数和指数平方模式下,雾的浓度随着距离的增加呈指数增长。这种模式通常用来用于烟雾、烟幕等效果。

      

  



  

  Linear:最好的渲染模式。物体淡入淡出的效果更自然。

      

  



    

  

  Exp:充满整个屏幕的基本渲染的雾。它能在较老的PC上工作,因此并不是特别像雾。

      

  



    

  

  Exp2:比Exp更进一步。它也是充满整个屏幕,但它使屏幕看起来更有深度。

      

  



  

  

  下面来讲下公式:

  

  

  说完原理我们来讲下怎么在Cocos2d-x中实现,首先我们要给需要雾化的物体加入我们自定义的雾化的shader并将这个物体的所有顶点的属性属性,存入这个shader的state中:

  1

  2

  3

  4

  5

  6

  7

  8

  9

  10

  11

  12

  13

  14

  15

  16

  17 _shader=GLProgram::createWithFilenames("Sprite3DTest/fog.vert","Sprite3DTest/fog.frag");

  _state = GLProgramState::create(_shader);

  _sprite3D1 = Sprite3D::create("Sprite3DTest/teapot.c3b");

  _sprite3D1->setGLProgramState(_state);

  //pass mesh's attribute to shader

  long offset = 0;

  auto attributeCount = _sprite3D1->getMesh()->getMeshVertexAttribCount();

  for (auto i = 0; i < attributeCount; i++) {

      auto meshattribute = _sprite3D1->getMesh()->getMeshVertexAttribute(i);

      _state->setVertexAttribPointer(s_attributeNames[meshattribute.vertexAttrib],

          meshattribute.size,

          meshattribute.type,

          GL_FALSE,

          _sprite3D1->getMesh()->getVertexSizeInBytes(),

          (GLvoid*)offset);

      offset += meshattribute.attribSizeBytes;

  }

  接下来我们要设置雾化的参数:

  1

  2

  3

  4 _state->setUniformVec4("u_fogColor", Vec4(0.5,0.5,0.5,1.0));

  _state->setUniformFloat("u_fogStart",10);

  _state->setUniformFloat("u_fogEnd",60);

  _state->setUniformInt("u_fogEquation" ,0);

  我们默认是用的线性的雾所以参数是雾的颜色,雾的起始点,雾的结束点,还有雾的类型,我们定义u_fogEquation 等于0是线性雾。

  1

  2

  3 _state->setUniformVec4("u_fogColor", Vec4(0.5,0.5,0.5,1.0));

  _state->setUniformFloat("u_fogDensity",0.03);

  _state->setUniformInt("u_fogEquation" ,1);

  上图是指数的雾,u_fogEquation 等于1。

  1

  2

  3 _state->setUniformVec4("u_fogColor", Vec4(0.5,0.5,0.5,1.0));

  _state->setUniformFloat("u_fogDensity",0.03);

  _state->setUniformInt("u_fogEquation" ,2);

  上图是指数平方的雾,u_fogEquation 等于2。

  这样一来我们的雾化效果就做出来了,接下来,我们来看一下shader内部是如何处理的,首先我们看一看顶点着色器部分:

  attribute vec4 a_position;

  attribute vec2 a_texCoord;

  varying float v_fogFactor;              //weight for fog

  varying vec2 v_texture_coord;

  uniform float u_fogDensity;// For exp and exp2 equation

  uniform float u_fogStart; // This is only for linear fog

  uniform float u_fogEnd; // This is only for linear fog

  uniform int u_fogEquation; // 0 = linear, 1 = exp, 2 = exp2

  

  void main(void)

  {

      gl_Position = CC_MVPMatrix

a_position;

      v_texture_coord = a_texCoord;

  

      float fogFragCoord = abs(gl_Position.z);                          //get fog distance

  

  

      if(u_fogEquation == 0)

              v_fogFactor = (u_fogEnd-fogFragCoord )/(u_fogEnd-u_fogStart);    //linear fog

      else if(u_fogEquation == 1)

              v_fogFactor = exp(-u_fogDensity*fogFragCoord  );                //exp fog

      else if(u_fogEquation == 2)

     v_fogFactor = exp(-pow(u_fogDensity*fogFragCoord , 2.0));          //exp2 fog

  

      v_fogFactor = clamp(v_fogFactor, 0.0, 1.0);                           //clamp 0 to 1

     

  }

  我们在这***据雾化方程计算出雾化的权重,然后传给片段着色器阶段,使其能够获得正确的物体和雾混合的颜色值,当然我们还要传递纹理以便计算出物体本来的颜色。

  

  现在我们来看看像素着色器部分:

  1

  2

  3

  4

  5

  6

  7

  8

  9

  10

  11

  12 #ifdef GL_ES

  varying mediump vec2 v_texture_coord;

  #else

  varying vec2 v_texture_coord;

  #endif

  varying float v_fogFactor;

  uniform vec4 u_fogColor;

  void main (void)

  {

      vec4 finalColor = texture2D(CC_Texture0, v_texture_coord);

      gl_FragColor     = mix(u_fogColor, finalColor, v_fogFactor ); //out put finalColor

  }

  像素着色器的原理很简单,就是把我们传入的雾的颜色根据顶点着色器穿入的雾的权重和物体本身的颜色混合输出就可以了。

  说了这么多现在让我们来看下最终的效果:

  线性雾:

  

  指数雾:

  

  指数平方雾:

  

  学完了这篇教程,相信大家已经学会了如何在Cocos2d-x中实现一个简单的雾化效果。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|A9VG电玩部落 川公网安备 51019002005286号

GMT+8, 2025-1-16 11:14 , Processed in 0.178947 second(s), 18 queries , Redis On.

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

返回顶部