Unity Shaders 基础篇(二) 基本操作

来源:互联网 发布:idea中导入hadoop源码 编辑:程序博客网 时间:2024/05/16 08:33

本文主要参照CG_WikiBook.

最简vf shader模板

先上一个最简单的vfshader模板.

Shader "Cg basic shader" { // defines the name of the shader    SubShader { // Unity chooses the subshader that fits the GPU best      Pass { // some shaders require multiple passes         CGPROGRAM // here begins the part in Unity's Cg         #pragma vertex vert             // this specifies the vert function as the vertex shader          #pragma fragment frag            // this specifies the frag function as the fragment shader         float4 vert(float4 vertexPos : POSITION) : SV_POSITION             // vertex shader          {            return mul(UNITY_MATRIX_MVP, vertexPos); //把顶点坐标从模型空间转换成投影空间         }         float4 frag(void) : COLOR // fragment shader         {            return float4(1.0, 0.0, 0.0, 1.0); //修改此行去更改颜色 RGBA         }         ENDCG // here ends the part in Cg       }   }}

这是一个红色的cube.
这里写图片描述

修改颜色

fragment指的就是屏幕像素.
现在修改fragment shader中的颜色使其变绿.

         float4 frag(void) : COLOR // fragment shader         {            return float4(0.0, 1.0, 0.0, 1.0); //修改此行去更改颜色 RGBA         }

这里写图片描述

修改形状

因为到frag函数时,已经到了屏幕空间了. 无法更改物体的几何特征.所以更改物体形状只能放在vertex函数中.

float4 vert(float4 vertexPos : POSITION) : SV_POSITION             // vertex shader          {            return mul(UNITY_MATRIX_MVP, float4(1,0.5,1,1)*vertexPos); //把顶点坐标从模型空间转换成投影空间         }

这里写图片描述
由图可看出,模型沿y轴压缩了一半.

让颜色更多变一点

Shader "Cg shader for RGB cube" {    SubShader {       Pass {          CGPROGRAM          #pragma vertex vert          #pragma fragment frag          // 在上文中,我们vert返回的是屏幕的坐标.         // 但是我们也可以返回多个参数.         // 方法就是定义一个struct.         struct vertexOutput {            float4 pos : SV_POSITION;             float4 col : TEXCOORD0;             //这里有一点需要注意一下,这个参数代表的是颜色.而不是纹理的坐标.            //TEXCOORD0(semantics)只是代表了数据的类型,实际用途由我们来定义         };         vertexOutput vert(float4 vertexPos : POSITION)             // vertex shader          {            vertexOutput output; // we don't need to type 'struct' here            output.pos =  mul(UNITY_MATRIX_MVP, vertexPos);            output.col = vertexPos + float4(0.5, 0.5, 0.5, 0.0);            //这里都加0.5的含义是因为我这里取得是单位立方体(边长为1).            //比如顶点(-0.5,-0.5,0.5,1)+(0.5,0.5,0.5,0)=(0,0,1,1)            //所以左下角呈现的就是蓝色了            return output;         }         float4 frag(vertexOutput input) : COLOR // fragment shader         {            return input.col;                // Here the fragment shader returns the "col" input                // parameter with semantic TEXCOORD0 as nameless               // output parameter with semantic COLOR.         }         ENDCG        }   }}

这里的代码演示了vert函数返回多个参数的方法.
效果图如下:
这里写图片描述
大家如果仔细考虑下的话,会发现不仅仅是顶点有颜色,而且这些平面也都获取了颜色.这是由于非顶点的像素颜色会被三角形的顶点进行插值.

这里再次注意下: cube的顶点个数并不为8.而是24.
原因是默认的cube为了让边缘看起来颜色完全不同,所以每个顶点的法向量都是按照面来计算的.即每个顶点的法向量要算三次. 所以每个顶点就会额外计算两次. 所以顶点数为24.

切割立方体

按自己数值

Shader "Cg shader for RGB cube" {    SubShader {       Pass {          CGPROGRAM          #pragma vertex vert          #pragma fragment frag          // 在上文中,我们vert返回的是屏幕的坐标.         // 但是我们也可以返回多个参数.         // 方法就是定义一个struct.         struct vertexOutput {            float4 pos : SV_POSITION;             float4 col : TEXCOORD0;             float4 posInObjectSpace : TEXCOORD1;            //这里有一点需要注意一下,这个参数代表的是颜色.而不是纹理的坐标.            //TEXCOORD0(semantics)只是代表了数据的类型,实际用途由我们来定义         };         vertexOutput vert(float4 vertexPos : POSITION)             // vertex shader          {            vertexOutput output; // we don't need to type 'struct' here            output.pos =  mul(UNITY_MATRIX_MVP, vertexPos);            output.col = vertexPos + float4(0.5, 0.5, 0.5, 0.0);            //这里都加0.5的含义是因为我这里取得是单位立方体(边长为1).            //比如顶点(-0.5,-0.5,0.5,1)+(0.5,0.5,0.5,0)=(0,0,1,1)            //所以左下角呈现的就是蓝色了            output.posInObjectSpace=vertexPos;            return output;         }         float4 frag(vertexOutput input) : COLOR // fragment shader         {             if(input.posInObjectSpace.y>0.0)             {                 discard; //不对像素进行处理              }            return input.col;                // Here the fragment shader returns the "col" input                // parameter with semantic TEXCOORD0 as nameless               // output parameter with semantic COLOR.         }         ENDCG        }   }}

更改的代码主要在于我们加入了一个额外的参数posInObjectSpace. 即我们也传递了模型空间的坐标. 这个参数也会和颜色值一样像上述例子进行插值. 换句话来讲,即我们可以在屏幕空间中获得其对应的模型空间的坐标.
这里写图片描述

按照参照体进行切割

除此之外 我们还可以通过别的GameObject来进行切割. 比如我们拿球体来切割材质.
这里写图片描述
从Sphere取矩阵信息:

using UnityEngine;using System.Collections;public class CutOff : MonoBehaviour {    public GameObject sphere;    // Use this for initialization    void Start () {    }    // Update is called once per frame    void Update () {        Matrix4x4 matrix = sphere.GetComponent<Renderer>().worldToLocalMatrix;        GetComponent<Renderer>().material.SetMatrix("sphereM", matrix);    }}

Shader代码:

Shader "Cg shader for RGB cube" {    SubShader {       Pass {          CGPROGRAM          #pragma vertex vert          #pragma fragment frag          float4x4 sphereM;         // 在上文中,我们vert返回的是屏幕的坐标.         // 但是我们也可以返回多个参数.         // 方法就是定义一个struct.         struct vertexOutput {            float4 pos : SV_POSITION;             float4 col : TEXCOORD0;             float4 posWorldSpace : TEXCOORD1;            //这里有一点需要注意一下,这个参数代表的是颜色.而不是纹理的坐标.            //TEXCOORD0(semantics)只是代表了数据的类型,实际用途由我们来定义         };         vertexOutput vert(float4 vertexPos : POSITION)             // vertex shader          {            vertexOutput output; // we don't need to type 'struct' here            output.pos =  mul(UNITY_MATRIX_MVP, vertexPos);            output.col = vertexPos + float4(0.5, 0.5, 0.5, 0.0);            //这里都加0.5的含义是因为我这里取得是单位立方体(边长为1).            //比如顶点(-0.5,-0.5,0.5,1)+(0.5,0.5,0.5,0)=(0,0,1,1)            //所以左下角呈现的就是蓝色了            output.posWorldSpace=mul(UNITY_MATRIX_M,vertexPos);            return output;         }         float4 frag(vertexOutput input) : COLOR // fragment shader         {             float4 localPos= mul(sphereM,input.posWorldSpace);                 if(localPos.y>0.3||localPos.y<-0.3||                 localPos.x>0.3||localPos.x<-0.3)             {                 discard; //不对像素进行处理              }            return input.col;                // Here the fragment shader returns the "col" input                // parameter with semantic TEXCOORD0 as nameless               // output parameter with semantic COLOR.         }         ENDCG        }   }}

试了大半天, 由于即使用sphere来切割立方体,切口也是个矩形,所以没办法展示特效. 后面想到了再进行补充.

正反面赋色

Shader "Cg shader with two passes using discard" {   SubShader {      // first pass (is executed before the second pass)      Pass {         Cull Front // cull only front faces         CGPROGRAM          #pragma vertex vert           #pragma fragment frag          struct vertexInput {            float4 vertex : POSITION;         };         struct vertexOutput {            float4 pos : SV_POSITION;            float4 posInObjectCoords : TEXCOORD0;         };         vertexOutput vert(vertexInput input)          {            vertexOutput output;            output.pos =  mul(UNITY_MATRIX_MVP, input.vertex);            output.posInObjectCoords = input.vertex;             return output;         }         float4 frag(vertexOutput input) : COLOR          {            if (input.posInObjectCoords.y > 0.0)             {               discard; // drop the fragment if y coordinate > 0            }            return float4(1.0, 0.0, 0.0, 1.0); // red         }         ENDCG        }      // second pass (is executed after the first pass)      Pass {         Cull Back // cull only back faces         CGPROGRAM          #pragma vertex vert           #pragma fragment frag          struct vertexInput {            float4 vertex : POSITION;         };         struct vertexOutput {            float4 pos : SV_POSITION;            float4 posInObjectCoords : TEXCOORD0;         };         vertexOutput vert(vertexInput input)          {            vertexOutput output;            output.pos =  mul(UNITY_MATRIX_MVP, input.vertex);            output.posInObjectCoords = input.vertex;             return output;         }         float4 frag(vertexOutput input) : COLOR          {            if (input.posInObjectCoords.y > 0.0)             {               discard; // drop the fragment if y coordinate > 0            }            return float4(0.0, 1.0, 0.0, 1.0); // green         }         ENDCG        }   }}

这个Shader展示了两个render pass. 正面赋绿,背面赋红. 其余和上面一样.

0 0
原创粉丝点击