HLSL之环境光

     一直想学习Shader,却总是断断续续的,触及不到精髓部分。于是,决定从最基础的开始学习,做好笔记,尽快成为Shader达人.....既然选择了学习,就要风雨兼程,一路向前~

      第一篇之环境光:

      环境光是没有方向的,在一个空间中所有模型照射到的环境光的颜色都是相同的,比如在一个漆黑的房间里什么也看不到,环境光通常为0,而在一个明亮的房间里,就能够看到物体,此时让物体可以进入你视觉的即是因为环境光不为0。

      环境光除了颜色以外,通常还有个用来表示光照的强弱的强度参数

      环境光的公式是: I = Aintensity* Acolor

      其中I是光的实际颜色,Aintensity是光的强度(通常在0.0和1.0之间),Acolor环境光的颜色,这个颜色可以是硬编码的值,参数或纹理。

   

      接下来用XNA4.0+VS2010来实现一个简单的程序,并贴出其效果图。

      

       第一步:新建fx文件(Ambient.fx)

       首先需要在项目的Content目录下建立这个文件,在自动生成好的fx文件中,已经帮我们定义好了基本的模板,包括顶点的输入结构(VertexShaderInput)和顶点输出结构(VertexShaderOutput),同时定义好了顶点着色方法(VertexShaderFunction)以及像素着色方法(PixelShaderFunction)。除此之外还有三个4*4的矩阵,分别是world,view,project。

      Vertex shader:顶点渲染,处理从顶点缓冲区加载的模型顶点信息传递到shader中,顶点结构中通常可以包括:位置、颜色、法线、切线等信息,由于环境光只需要对位置进行处理,所以这里我们只定义了一个位置信息。

struct VertexShaderInput
{
    float4 Position : POSITION0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
};

       在shader中,数据之间的传值借助寄存器,比如上面代码中出现得POSITION0,表示位置信息会放在名称叫POSITION这个寄存器里面。

       接着,则是处理获取到的模型位置并进行转换 (将默认的VertexShaderFunction改成了VertexShaderAmbient)

VertexShaderOutput VertexShaderAmbient(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    return output;
}

 

    通过三个矩阵的转换,模型的顶点位置已经正确的转换到当前空间了,下一步则是像素着色,添加光照信息。

    Pixel Shader:逐像素渲染,对给定的模型、对象、顶点额所有像素进行处理,将Vertex Shader的输出值作为它的输入值

float4 PixelShaderAmbient(VertexShaderOutput input) : COLOR0
{
    float aIntensity= 0.4f; //颜色强度
    float4 aColor= {1,0,0,1}; 

    return aColor*aIntensity;
}

     同样,对于返回值,我们保存在COLOR寄存器里面。

     最后,我们必须定义technique并将pixel shader和vertex shader函数绑定到technique上

technique AmbientLight
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 VertexShaderAmbient();
        PixelShader = compile ps_2_0 PixelShaderAmbient();
    }
}

 

    到此,一个简单的shader就编写完成了,那么下面我们看看在XNA程序中如何调用。

    第一:声明一个Effect对象

  /// <summary>
  /// effect for shader
  /// </summary>
  private Effect effect;

    第二:加载fx文件

 effect = Content.Load<Effect>("Ambient");

    第三:利用effect渲染模型

  effect.CurrentTechnique = effect.Techniques["AmbientLight"];

  //遍历所有的pass
  foreach (EffectPass pass in effect.CurrentTechnique.Passes)
  {
      pass.Apply();
      foreach (ModelMesh mesh in model.Meshes)
      {
            Matrix worldMatrix = modelTransform[mesh.ParentBone.Index] * Matrix.CreateScale(30.0f) * Matrix.CreateRotationY(angle) * Matrix.CreateRotationX(angle);
            foreach (ModelMeshPart part in mesh.MeshParts)
            {
                 effect.Parameters["World"].SetValue(worldMatrix);
                 effect.Parameters["View"].SetValue(viewMatrix);
                 effect.Parameters["Projection"].SetValue(projectMatrix);

                 VertexBuffer vb = part.VertexBuffer;
                 graphics.GraphicsDevice.SetVertexBuffer(part.VertexBuffer);
                 graphics.GraphicsDevice.Indices = part.IndexBuffer;

                graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList , part.VertexOffset , 0 , part.NumVertices , part.StartIndex , part.PrimitiveCount);
            }
        }
    }

       这样就可以达到上面截图的效果,注:一个Shader可以有一个或一个以上的technique。每个technique都有一个唯一的名称,我们可以通过设置Effect类中的CurrentTechnique属性选择使用哪个technique。同时,一个technique可以有一个或多个passes,但请确保处理所有passes以获得我们希望的结果。

posted @ 2013-05-29 10:27  勇者归来  阅读(611)  评论(0编辑  收藏  举报