资源预览内容
第1页 / 共9页
第2页 / 共9页
第3页 / 共9页
第4页 / 共9页
第5页 / 共9页
第6页 / 共9页
第7页 / 共9页
第8页 / 共9页
第9页 / 共9页
亲,该文档总共9页全部预览完了,如果喜欢就下载吧!
资源描述
cocos引擎伪阴影在Cocos2d-x中的实现本文检索关键词:游戏引擎,游戏开发引擎,cocos引擎html5游戏开发概要:这篇教程里,我们会简单的介绍一下两种基本的伪阴影的概念,以及在Cocos2d-x中的实现方法。何谓伪阴影:在游戏过程中,我们通常会是用阴影来增强视觉效果的真实度,在这里,我们讨论伪阴影的计算方法,所谓的伪阴影,是指根据指定的空间位置的模型生成一个简单的阴影,这个阴影的形状或者说轮廓与被生成阴影的模型的真实样子并无映射关系。这种影子虽然看起来简单,但是在某些场合也会非常的有用,比方说在一个光源在比较远和比较高的角度,光线比较充足的场景里。比方说,在艳阳高照的足球场上,球员脚底的阴影就是一团模糊不清的圆环状,伪阴影与模型无关,有实现简单,计算效率高等,所以在一些开阔明亮的场景里通常会使用。通过距离计算的方式:我们先说一种非常简单的方式。首先,我们获取到玩家角色的位置,然后将制定的地面的每一像素点的位置与玩家角色位置的距离作比较,当小于一个制定的范围的阈值的时候,就将该点涂黑。实现现在我们来描述一下如何具体的实现这个方式,首先我们读入一个地面,并自定义自己的shader,并将这个地面的所有顶点的属性属性,存入这个shader的state中:123456789101112131415161718autoplane=Sprite3D:create(plane.c3b);plane-setRotation3D(Vec3(90,0,0);autoshader=GLProgram:createWithFilenames(simple_shadow.vert,simple_shadow.frag);autostate=GLProgramState:create(shader);plane-setGLProgramState(state);/passmeshsattributetoshaderlongoffset=0;autoattributeCount=plane-getMesh()-getMeshVertexAttribCount();for(autoi=0;igetMesh()-getMeshVertexAttribute(i);state-setVertexAttribPointer(s_attributeNamesmeshattribute.vertexAttrib,meshattribute.size,meshattribute.type,GL_FALSE,plane-getMesh()-getVertexSizeInBytes(),(GLvoid*)offset);offset+=meshattribute.attribSizeBytes;接着我们要将角色的坐标传入这个shader:1plane-getGLProgramState()-setUniformVec3(u_target_pos,orc-getPosition3D();目前我们无法获得平面在世界坐标系下的位置,我们将地面的模型变换的矩阵传入shader内1state-setUniformMat4(u_model_matrix,plane-getNodeToWorldTransform();这样前期的准备工作就已经做好了,接下来,我们来看一下shader内部是如何处理的,首先我们看一看顶点着色器部分:123456789101112attributevec4a_position;attributevec2a_texCoord;uniformmat4u_model_matrix;varyingvec2TextureCoordOut;varyingvec4v_position;voidmain(void)gl_Position=CC_PMatrix*CC_MVMatrix*a_position;TextureCoordOut=a_texCoord;TextureCoordOut.y=(1.0-TextureCoordOut.y);v_position=u_model_matrix*a_position;请注意加粗的部分,u_model_matrix,就是我们之前传入的模型变换的矩阵,v_position是我们自己定义的一个易变变量,我们用平面的顶点的局部坐标的位置与u_model_matrix相乘,得出平面的世界坐标,并将其插值,传给片段着色器阶段,使其能够获得平面上每个像素点的世界坐标。现在我们来看看像素着色器部分:1234567891011121314151617181920#ifdefGL_ESvaryingmediumpvec2TextureCoordOut;varyingmediumpvec4v_position;#elsevaryingvec2TextureCoordOut;varyingvec4v_position;#endifuniformvec3u_target_pos;#defineRANGE1.5voidmain(void)floatdist=distance(v_position.xz,u_target_pos.xz);if(distRANGE)gl_FragColor=vec4(0,0,0,1);elsegl_FragColor=texture2D(CC_Texture0,TextureCoordOut);像素着色器里的原理很简单,首先我们将从顶点着色器插值而来的平面的世界坐标的位置与角色的世界坐标的位置计算一个距离,然后设置一个阈值RANGE ,若所得的距离小于这个RANGE,则将该片段涂黑,否则保持其纹理的颜色。最后显示的结果如下:简单改进:这个效果看起来并不好,因为在现实生活中,影子的边缘通常来说是比较量,比较柔和的,即所谓的半影效果,我们可以在前述的片段着色器中稍加修改,在一定范围内计算一下当前距离与范围的比值,然后与地面的颜色相混合,就可以达到这种效果了,修改后的片段着色器的代码如下:1234567if(distgetTextureCache()-addImage(shadowCircle.png);Texture2D:TexParamstRepeatParams;/settextureparameterstRepeatParams.magFilter=GL_LINEAR;tRepeatParams.minFilter=GL_LINEAR;tRepeatParams.wrapS=GL_CLAMP_TO_EDGE;tRepeatParams.wrapT=GL_CLAMP_TO_EDGE;shadowTexture-setTexParameters(tRepeatParams);state-setUniformTexture(u_shadowTexture,shadowTexture);请注意12tRepeatParams.wrapS=GL_CLAMP_TO_EDGE;tRepeatParams.wrapT=GL_CLAMP_TO_EDGE;这两个部分,因为我们这个方式依赖的通过UV坐标将阴影的纹理与地面的纹理混合,所以对于S、T(UV)坐标的寻址方式一定要设置成CLAMP,否则对于非阴影的区域它也会采样上阴影的颜色。这种方式在顶点着色器里与上一种没有任何区别,在这里我们主要是看看片段着色器部分:1234567891011voidmain(void)floatRadius=4;/投影范围vec3UVector=vec3(1,0,0)/(2*Radius);/将世界坐标变换到纹理投影空间坐标并规范化到0-1之间(正投影)vec3VVector=vec3(0,0,-1)/(-2*Radius);/同上float2coord;coord.x=dot(v_position-u_target_pos,UVector)+0.5;coord.y=dot(v_position-u_target_pos,VVector)+0.5;gl_FragColor=texture2D(CC_Texture0,TextureCoordOut)*texture2D(u_shadowTexture,coord);在这里我们来解释一下如何片段着色器代码的原理。(v_position u_target_pos)计算的是从角色的位置指向地面上一点的向量,然后让其点乘相当于分别计算了到UVector和VVector的投影,因为这里假设是从上方往下望的,如果你想实现的结果并不是这样,比方说地面的法线法向与Y轴不平行,请传入以阴影大小范围单独设置的投影矩阵记做proj,然后以角色的位置并朝向该地面做出一个视图矩阵记做view,再计算UV坐标记做UVCoords:1234vec3ProjCoords=proj*view*v_position;ve
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号