精华内容
下载资源
问答
  • shader编程

    2010-12-14 22:09:00
    XNA Shader编程教程1-环境光照 原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!424.entry。没有实用价值,但这应该是最简单的shader,可以帮助理解shader的基本工作原理。源代码Tuto

    2010-03-13 16:56 来自 【组长】独孤残云      : 

    Shader教程系列

    XNA Shader编程教程1-环境光照

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!424.entry。没有实用价值,但这应该是最简单的shader,可以帮助理解shader的基本工作原理。源代码Tutorial1_Ambient.rar下载。

    XNA Shader编程教程2-漫反射光照

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!426.entry。简单的游戏漫反射够用了,开始涉及基本数学原理了。源代码Tutorial2_Diffuse.rar下载。

    XNA Shader编程教程3-镜面反射光照

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!437.entry。可以模拟光滑、有光泽或磨光的表面。源代码Tutorial3_Specular.rar下载。

    XNA Shader编程教程3.1-纹理

    觉得原文的教程有点跳跃,所以在教程3和4之间整理了一下使用纹理的基本方法。源代码Tutorial31_Texture.rar下载。

    XNA Shader编程教程3.2-逐顶点和逐像素光照

    解释了逐顶点和逐像素光照的区别,其他源代码好像都是使用逐像素光照模型。源代码Tutorial3.2_PerPixelLight.rar下载。

    XNA Shader编程教程3.3-多纹理

    这个例子比较简单。源代码Tutorial3.3_MultiTexture.rar下载。

    XNA Shaders 编程教程4-法线映射

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!442.entry。使用法线映射可以让少量多边形构成的模型看起来具有丰富的细节,而视觉效果大量多边形构成的几乎一样,现今很多游戏都使用了法线映射,不过我总觉得这个示例有错误。源代码Tutorial4_NormalMapping.rar下载。

    XNA Shaders 编程系列5-变形

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!447.entry。建议你可以试着用键盘控制物体沿xyz方向的变形。源代码Tutorial5_Deform.rar下载。

    XNA Shader编程教程6-Shader演示

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!450.entry。在前几个教程的基础上实现了天空球和水面。源代码Tutorial6_ShaderDemo.rar下载。

    XNA Shader编程教程7-卡通渲染

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!420.entry。这是一项将3D物体转为类似2D手绘的卡通风格的技术。源代码Tutorial7_ToonShader.rar下载。

    XNA Shader编程教程8-光泽贴图(Gloss Map)

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!462.entry。通过光泽贴图可以控制模型不同部位的镜面反射强度。源代码Tutorial8_GlossMap.rar下载。

    XNA Shader编程教程8.1-颜色,发光,凹凸和反射纹理贴图

    这个例子来自于http://xna-uk.net/,原文地址:http://xna-uk.net/blogs/randomchaos/archive/2008/11/24/basic-hlsl-lighting-techniques-episode-3-colour-glow-bump-and-reflective-texture-maps.aspx。使用了四种技术:颜色贴图,就是教程2的漫反射;发光贴图是新的,用一张额外的贴图控制漫反射强度,这个例子中表现出地球上的大城市的灯光效果;凹凸贴图,就是教程4的法线贴图,严格地说法线贴图只是凹凸贴图的一种,凹凸贴图还包含视差映射(Parallax Mapping)等;反射贴图就是教程8的光泽贴,通过一张额外的纹理控制模型不同部位的镜面反射强度,这个例子中让地球上的海面反射强度比陆地大。源代码GenericXNALightAndShadeIII.zip下载。

    XNA Shader编程教程9-Post process波动效果

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!511.entry。《Professional XNA Game Programming: For Xbox 360 and Windows》一书中用了一章的篇幅介绍了PostScreen Shader,有些地方把PostScreen翻译成离屏或后屏,我就保留英文了。这个shader的基本思路就是先将场景绘制到一张纹理中(这叫做Render To RenderTarget,渲染到渲染目标),想了解工作原理,请见3.8 将场景绘制到纹理,然后对这个纹理施加各种滤镜效果,熟悉Photoshop的人对滤镜肯定不陌生,原理不难,唯一的限制就是用什么算法和你的想象力了,《Professional XNA Game Programming》一书的后三个游戏都使用了PostScreen Shader让画面更漂亮。源代码Tutorial9_1_PostProcess.rar下载。

    XNA Shader编程教程10-Post process图片反相

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!513.entry。非常简单的一个算法,实现了反相的效果。这让我想起了《生化危机3》中当“追击者”出现时伴随着一声心脏跳动的声音,画面暂停并反相,表现出吃了一惊的效果。源代码Tutorial9_2_PostProcess.rar下载。

    XNA Shader编程教程11-Post process图片灰度

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!516.entry。使用两种不同的算法实现了图片灰度。源代码Tutorial9_3_PostProcess.rar下载。

    XNA Shader编程教程12-Post process噪点扭曲

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!518.entry。通过随机函数实现噪点效果。源代码Tutorial9_4_PostProcess.rar下载。

    XNA Shader编程教程13-Alpha映射

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!558.entry。通过一张Alpha贴图控制模型的透明程度。源代码Tutorial13_AlphaMapping.rar下载。

    XNA Shader编程教程14-透射

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!580.entry。此教程涉及了Framebuffer,BackBuffer,ZBuffer,DepthBuffer,StencilBuffer,我总结了一下,放在本文的最后部分。源代码Tutorial14_Transmittance.rar下载。

    XNA Shader编程教程15-动态环境映射

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!585.entry。这个教程有点难,我认为讲得也不够清晰,下次我会整理一个简单的反射、折射、动态反射例子的,还有源代码中可以使用X360手柄控制一些变量,我自己添加了键盘控制,用上下左右控制世界矩阵,用ADWS控制Du变量和C变量。源代码Tutorial15_DynamicEnvironmentMap.rar下载。

    XNA Shader编程教程16-折射

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!590.entry。只需使用HLSL的内置refract函数计算折射向量。源代码Tutorial16_Refraction.rar下载。

    XNA Shader编程教程21-过渡:淡入淡出

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!667.entry。主要思路是将两个场景绘制到两个渲染目标中,并使用HLSL的内置lerp函数对两者进行插值。源代码Tutorial21_TransitionFade.rar下载。

    XNA Shader编程教程22 – 过渡:左右揭开

    原文地址:http://digierr.spaces.live.com/blog/cns!2B7007E9EC2AE37B!683.entry。在前一个教程基础上还使用了另一个HLSL内置函数smoothstep。源代码Tutorial22_TransitionCross.rar下载。

    感谢网友roujiao将这个HLSL教程编译成了电子书,HLSL.chm下载。截止到2009年10月14日,教程已经更新到第24篇,而且作者也修复了教程4法线映射中的错误,有时间我会把它补齐的。

    至此shader的基本实现方法已经告一段落了,想进一步学习,强烈推荐Nvidia网站,把http://developer.download.nvidia.com/shaderlibrary/webpages/shader_library.html上的shader都弄懂了,你就是高手了。

    ShaderX

    ShaderX:Direct3D ShaderX Vertex and PixelShader Tips and Tricks

    学习Shader编程的经典图书系列,2002年出版,不过好像太老了,里面的代码都是用汇编实现的。 电子书下载,英文版,pdf格式,10.5MB。

    ShaderX2Toturial

    ShaderX2:Introductions&Tutorials with DirectX9

    学习Shader编程的经典图书系列,2004年出版。电子书下载(英文版,pdf格式,6.8MB),C++源代码下载(38MB)。主要内容有:

    • DirectX HLSL语言介绍
    • vs_3_0和ps_3_0 Shader Models介绍
    • 使用Direct3D9的高级光照和着色
    • 不同的雾化效果
    • 阴影映射
    • Stencil ShadowVolumes理论
    • 使用RenderMonkey开发Shader
    • 创建对Shader友好的模型技巧
    ShaderX2Tips

    ShaderX2:Shader Programming Tips&Tricks with DirectX9

    学习Shader编程的经典图书系列,2004年出版。电子书下载(英文版,pdf格式,15.3MB),C++源代码下载(187MB)。主要内容有:

    • 第一部分—几何体创建技巧Geometry Manipulation Tricks
    • 第二部分—渲染技术Rendering Techniques
    • 第三部分—Software Shaders和ShaderProgramming技巧
    • 第四部分—图像处理Image Space
    • 第五部分—阴影Shadows
    • 第六部分—3D引擎和工具设计3D Engineand Tools Design
    ShaderX3

    ShaderX3: Advanced Rendering with DirectX and OpenGL

    学习Shader编程的经典图书系列,2004年出版。电子书下载(英文版,pdf格式,30.6MB)。

    ShaderX系列目前已出到ShaderX8,名称已变为GPU Pro,上述电子书和源码的来源地址为http://tog.acm.org/resources/shaderx/

    GpuGem2

    GPU Gems 2: Programming Techniques for High-Performance Graphics and General-Purpose Computation

    学习Shader编程的经典图书系列,2005年出版。电子书下载(英文版,chm格式,14.4MB)。

    GpuGem3

    GPU Gems 3

    学习Shader编程的经典图书系列,2007年出版。电子书下载(英文版,chm格式,26.2MB)。

    GPU编程与CG语言

    作者:半山工作室的康玉之,发表于2009年9月,电子书下载(简体中文版,3MB)。应该去看看这篇文章的前言,真知灼见,现在中国搞基础研究的太少,比起外国,在图形学方面我们落后太多了。

    展开全文
  • Shader编程

    千次阅读 2017-12-22 09:15:35
    Shader编程有那几种? CG:与DirectX 9.0 以上以及OpenGL 完全兼容。运行时或事先编译成GPU汇编代码 HLSL: 主要用于Direct3D。平台:Windows GLSL: 主要用于OPenGL。 平台:移动平台(IOS,Android),Mac...

    管线渲染

    定义:图形数据在GPU上经过运算处理,最后输出到屏幕的过程

    1. 顶点处理: 接收模型顶点数据、坐标系装换

    2. 图元装配: 组装面、连接相邻的顶点,绘制为三角面

    3. 光栅化 :    计算三角面上的像素,并为后面着色阶段提供合理的插值参数(以及深度值)

    4. 像素处理: 对每个像素区域进行着色、写入到缓存

    5.  缓存:        一个存储像素数据的内存块,最重要的缓存是帧缓存与深度缓存

     帧缓存:存储每个像素的色彩(缓冲)

     深度缓存Z-buffer:前后排序(深度信息,物体到摄像机的距离)

    6. Draw Call  绘制调用:每帧调用显卡渲染物体的次数


    什么是缓冲?

    一个像素有如下缓冲

    颜色缓冲Color buffer/prixel buffer: 储存该点即将显示的颜色,RGBA值

    深度缓存 depth buffer/Z buffer: 储存该点的深度Z

    模板缓存stencil buffer  : 通常作用限制渲染区域。更高级用法需结合深度缓存,例如某像素的模板缓冲值会随着其是否通过深度缓冲测试而改变


    什么是图元装配(Primitive Assembly)

    经过变换的顶点 被装配成几何(三角形等)图集 


    什么是光栅化(栅格化)(Rasterization)

    栅格化这个术语:可以用于任何将矢量图形转化成栅格图像的过程

    在3D渲染中主要是指,三角形等图元(矢量)转化成像素碎片的过程。或者说决定哪些像素几何图元覆盖的过程。栅格化的结果是像素位置的集合和片段的集合


    什么是光栅操作(Raster Operation)

    指在碎片fragment处理后,在更新帧缓存前最后执行的一系列操作。通过包括裁剪,深度测试,alpha测试,alpha混合等。


    Shader常见术语

    Alpha 透明的(黑透白不透、灰色半透半不透)

    Bump凹凸 (法线贴图)

    Specular (高光)

    Shader主要看Game视窗

    Shader显示名称与Shader名不冲突


    什么是GPU?

    GPU:Graphic Processing Unit,中文翻译为“图形处理器”。显卡包括(GPU,显存,显卡BLOS,显卡PCB板)


    什么是Shader?

    Shader程序:GPU执行的,针对3D对象进行操作的程序

    Shader编程有那几种?

    CG:与DirectX 9.0 以上以及OpenGL 完全兼容。运行时或事先编译成GPU汇编代码

    HLSL: 主要用于Direct3D。平台:Windows

    GLSL: 主要用于OPenGL。 平台:移动平台(IOS,Android),Mac(only use when you target Mac OS X or OpenGL ES 2.0)


    为什么Shader中选择CG?

    因为CG/HLSL 比GLSL支持更多的平台。



    Unity3d 里CG输出什么?

    Windows平台:Direct3D,GPU汇编代码

    Mac: OpenGL GPU汇编代码

    Flash: Flash GPU 汇编代码

    IOS/Android : unity 会将CG转换成GLSL代码。

    总结:也就是除了移动平台会把CG转换成GLSL代码,其余平台都是转化成汇编代码。


    Unity 中的三种自定义Shade:

    1.surface shaders, 表面着色器(最常用,比固定功能管线高级)(之前默认创建的shader类型)它是 Vertex and fragment shaders 的包装,让我们可以不用关心这些顶点和片段程序的细节,可以直接得到我们想要的着色器。

    2.Vertex and fragment shaders 顶点和片元着色器(细节处理,偏底层)

    3.fixed function shaders.  固定功能管线着色器(更简单),在可编程渲染管线硬件出现之前,很多光照都会放在硬件级处理(可以理解为对固定管线硬件的操作),一般放在项目前绝大多数硬件都可支持,应用就可以使用,比如光照、纹理采样

    //Shader中没有注明是前两种shader,即为第三种shader

    先从ShaderLab基本语法开始入手,再去阅读surface shader,或者vertex and fragment shaders


    ShaderLab 基本结构

    Unity中的Shader 都是要通过ShaderLab的基本语法进行编写,unity就是想通过Shaderlab的方案进行Shader的编写。将三种定义的Shader通过同一种格式进行编写,避免不同Shader使用不同的方法。

    Shader "name"
    {
        //[Properties] 属性 查看ShaderLab:Properties 
        //作用:在可视化面板提供美工可使用的属性
    	Properties  
    	{
    		
    	}
        //[Subshader] 算法用于执行给定的数据
    	SubShader
    	{
    		
    	}
        //[FallBack] 后退 一般会填写所有硬件都支持的渲染方式
        FallBack "Diffuse"
    }


    关于SubShaders (处理ShaderLab中的语言片段) 在ShaderLab中至少有一个SubShader,当然也可多个。但是,显卡每次渲染处理的时候只能选择一个SubShaders执行。那多个SubShader的作用是为了不同的硬件的渲染支持,为了Shader能在比较老的图形显卡中也能支持。一般比较往下的Subshader要简化,运算指令要简单。



    Fixed function shader固定功能管线

    所有硬件平台都可支持,针对硬件能够执行的基本命令的Shader,当然有,但是,速度最快

    Properties 属性

    Material 材质

    Lighting 光照

    Settexture  设置纹理

    Pass通道(存储图像的色彩RGB)(只有Surface 可以不写)



    Surface shaders

    surfaceOutPut输出

    Input 输入

    Lighting 光照



    常用公式

    环境反射

    Ambient= Ka*globalAmbient;

    Ka是材质的环境反射系数

    globalAmbient是入射环境光的颜色


    漫反射

    Diffuse=Kd*lightColor*max(N*L,0);

    Kd 是材质的漫反射颜色

    lightColor是入射漫反射光的颜色

    N 是规范化的表面法向量

    L 是规范化的纸箱光源对的向量;


    镜面反射

    Specular=Ks * lightColor *facing*max((N*H),0) shininess

    Ks 是材质的镜面反射颜色;

    lightColor是入射镜面反射光的颜色

    N是规范化的表面法向量

    V是指向视点的规范化的向量

    L是指向光源的规范化的向量

    H是V和L的中间向量的规范化向量

    P是要被着色的点

    Faceing是1如果N*L是大于0的,否者为0


    写Shader不区分大小写

    和灯光有呼应的  ------ 漫反射  高光   背光    阴影   环境光


    固定着色器格式

    hader "Unlit/Test2"//不区分大小写
    {
        //声明属性
    	Properties
    	{
            //默认颜色颜色
            //变量名    在监视面板显示的名称    类型=值
    		_Color("MyColor",Color)=(1,0,0,1)
            //环境光
            _Ambient("Ambient",Color)=(1,0,0,1)
            //高光
            _Specular("Specular",Color)=(1,0,0,1)
            _Shininess("Shininess",Range(0,1))=0.5 //range 0-8的值
            //自发光
            _Emission("Emission",Color)=(1,0,0,1)
            //
            _MainTexture("Main Texture",2D)="white"{}
            //默认颜色
    
    	}
    	SubShader
    	{
    
        pass
        {
    
    		Color[_Color]   //使用默认颜色进行颜色的写入
          
            Material{
                //漫反射
                Diffuse[_Color]
                //环境光
                Ambient[_Ambient]
                //亮度
                Shininess[_Shininess]
                //高光反射系数
                Specular[_Specular]
                //自发光
                Emission[_Emission]
            }
            //启动光照
            Lighting On 
            //启动高光反射
            SeparateSpecular On
            SetTexture[_MainTexture]
            {
              Combine Texture*primary double
            }
    	}
        }
        FallBack "Diffuse"
    }
    

    表面着色器格式

    Shader "Custom/Test1" {
        //属性 
        //属性变量
    	Properties {
             //变量名  面板中的名字  类型
    		_Color ("Color", Color) = (1,1,1,1)
    		_MainTex ("Albedo (RGB)", 2D) = "white" {}
    		_Glossiness ("Smoothness", Range(0,1)) = 0.5
    		_Metallic ("Metallic", Range(0,1)) = 0.0
    	}
        //算法
    	SubShader {
    		Tags { "RenderType"="Opaque" } //描述渲染类型,当前是不透明的物体
            //Tags{"RenderType"="Opaque" "queue"="transparent"}//透明的物体
    		LOD 200  //层级细节
    		
    		CGPROGRAM  //CG代码块 CG开始
    		// Physically based Standard lighting model, and enable shadows on all light types
            //如果是Standard fullforwardshadows光照模型,则对应用SurfaceOutputStandard,
            //如果是Lambert光照模型(其他版本Unity默认的光照模型),则对应SurfaceOutput。
            //对应的SurfaceOutputStandard/SurfaceOutput结构体不用写出来
            #pragma surface surf Standard fullforwardshadows//编译指令
            //surface表面着色器 surf调用的方法 Standard基于物理的光照模型(原来是漫反射 Lambert)
            //fullforwardshadows 阴影表现(平行光、点光、聚光都是有阴影的)
            // Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0  //GPU硬件支持3.0 (不写默认是2.0)
    
    		sampler2D _MainTex; //CG中图片的类型
    
    		struct Input {
    			float2 uv_MainTex; //记录uv纹理坐标
    		};
    
    		half _Glossiness; //CG中的浮点型
    		half _Metallic;   
    		fixed4 _Color;    //CG中的四阶向量(0,0,0,0)rgb
    
    		// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    		// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    		// #pragma instancing_options assumeuniformscaling
    		UNITY_INSTANCING_CBUFFER_START(Props)
    			// put more per-instance properties here
    		UNITY_INSTANCING_CBUFFER_END
            //Input 传入值    inout 传出值(基于物理的要加Standard)
    		void surf (Input IN, inout SurfaceOutputStandard o) {
    			// Albedo comes from a texture tinted by color
    			fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    			o.Albedo = c.rgb;
    			// Metallic and smoothness come from slider variables
    			o.Metallic = _Metallic;  //金属光泽表现
    			o.Smoothness = _Glossiness; //高光光泽度
    			o.Alpha = c.a;
    		}
    		ENDCG //CG结束
    	}
    	FallBack "Diffuse"
    }
    




    表面着色器示例练习

    Shader "Custom/Test5" {
    	Properties {
            //2D ---图片    white----默认格式  “”内也可以不写
            //大括号也可以不写(大括号内可以给值)
    		_MainTex("Texture",2D)="white"{}
            _BumpMap("Bumpmap",2D)="bump"{}
            //cube 立方体贴图
            _Cube("Cubemap",CUBE)=""{}
    	}
    	SubShader {
            //不透明
    		Tags { "RenderType"="Opaque" }
    		LOD 200
    		
    		CGPROGRAM
    		// Physically based Standard lighting model, and enable shadows on all light types
            //如果是Standard fullforwardshadows光照模型,则对应用SurfaceOutputStandard,
            //如果是Lambert光照模型(其他版本Unity默认的光照模型),则对应SurfaceOutput。
            //对应的SurfaceOutputStandard/SurfaceOutput结构体不用写出来
            #pragma surface surf Lambert
    
    		// Use shader model 3.0 target, to get nicer looking lighting
    		#pragma target 3.0
    
    		struct Input {
                //只要是纹理相关都需要UV
    			float2 uv_MainTex;
                float2 uv_BumpMap;
                float3 worldRef1;
                INTERNAL_DATA  //反射与法线效果配合
    		};
    
            //再次声明变量
            sampler2D _MainTex;
            sampler2D _BumpMap;
            samplerCUBE _Cube;
    
    
    		// Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    		// See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    		// #pragma instancing_options assumeuniformscaling
    		UNITY_INSTANCING_CBUFFER_START(Props)
    			// put more per-instance properties here
    		UNITY_INSTANCING_CBUFFER_END
    
    		void surf (Input IN, inout SurfaceOutput o) {
    			o.Albedo=tex2D(_MainTex,IN.uv_MainTex).rgb;
                //不需要法线的反射效果
                //o.Emission=texCUBE(_Cube,IN.worldRefl).rgb;
                //法线与反射效果配合
                //需要将INTERNAL_DATA添加到Input结构中
                o.Normal=UnpackNormal(tex2D(_BumpMap,IN.uv_BumpMap));
                //反射
                o.Emission=texCUBE(_Cube,WorldReflectionVector(IN,o.Normal)).rgb;
    		}
    		ENDCG
    	}
    	FallBack "Diffuse"
    }
    

    介绍:【Unity5.x Shaders】最基本的Surface Shader-Diffuse shader以及Surface中的三种输出结构

    展开全文
  • Unity Shader编程

    2018-03-27 17:25:32
    Unity Shader编程
  • Shader编程资源

    2017-09-06 11:28:39
    这个系列的文章将逐步介绍shader编程,并面向几乎没有任何shader知识的开发者。本篇文章逐渐引入了两种类型的Unity3D shader,并说明何时需要使用。接下来四篇文章,将介绍实现它们的细节。还有一个附加篇,将介绍...
  • Shader编程教程

    2019-07-07 01:53:41
    Shader编程教程1-环境光照 您好,欢迎来到XNA Shader教程1。我的名字叫Petri Wilhelmsen,是Dark Codex Studios的成员。我们经常会参加各种图形/游戏开发的竞赛,如Gathering,Assembly,Solskogen,...

     

    2010-05-13 11:37:14|  分类: DirectX 3D学习|举报|字号 订阅

     
     
    Shader编程教程1-环境光照

    您好,欢迎来到XNA Shader教程1。我的名字叫Petri Wilhelmsen,是Dark Codex Studios的成员。我们经常会参加各种图形/游戏开发的竞赛,如Gathering,Assembly,Solskogen,Dream-Build-Play和NGA等。

    本XNA Shaders编程教程将讨论XNA的不同方面的知识以及如何使用XNA和GPU编写HLSL。我将从一些基本理论开始,然后深入到shader编程的实际方法。

    理论部分不会面面俱到,但足以让你开始使用shader并自己实践。它将涵盖HLSL的基础,HLSL语言如何工作和一些必须知道的关键字。

    今天,我将介绍XNA和HLSL以及一个简单的环境光照算法。

    程序截图

    先决条件

    XNA的编程基础,因为我们将涉及到加载纹理,三维模型,矩阵和一些数学知识。

    Shader简史

    在DirectX8之前,GPU使用固定方式变换像素和顶点,即所谓的“固定管道”。这使得开发者不可能改变像素和顶点转化和处理的进程,使大多数游戏的图像表现看起来非常相似。

    DirectX8提出了顶点和像素着色器,这让开发者可以在管道中决定如何处理顶点和像素,使他们获得了很强的灵活性。

    一开始shader编程使用汇编语言程序使用的着色器,这对shader开发者来说相当困难,Shader Model 1.0是唯一支持的版本。但DirectX9发布后这一切改变了,开发者能够使用高级着色语言(HLSL)取代了汇编语言,HLSL语法类似C语言,这使shader更容易编写,阅读和学习。

    DirectX 10.0提出了一个新的shader——Geometry Shader作为Shader Model 4.0的组成部分。但这需要一个最先进的显卡和Windows Vista才能支持。

    XNA支持Shader Model 1.0至3.0,可以在XP,Vista和XBox360!上运行。

    Shader?

    嗯,历史已经说得够多了……那么什么是shader?

    正如我所说的,shader可以用来定制管道的步骤,使开发者能够决定如何处理像素/顶点。

    如下图所示,应用程序在渲染时启动并使用shader,顶点缓冲区通过向pixel shader发送所需的顶点数据与pixel shader协同工作,并在帧缓冲中创建了一个图像。

    图1

    但请注意许多GPU不支持所有的shader模式,在开发shader时应引起足够重视。一个shader最好要有一个类似/简单的效果,使程序在较旧的计算机上也能工作正常。

    Vertex shader

    Vertex shaders用来逐顶点地处理顶点数据。例如可以通过将模型中的每个顶点沿着法线方向移动到一个新位置使一个模型变“胖”(这称之为deform shaders)。

    Vertex shaders从应用程序代码中定义的一个顶点结构获取数据,并从顶点缓冲区加载这个结构传递到shader。这个结构描述了每个顶点的属性:位置,颜色,法线,切线等。

    接着Vertex shader将输出传递到pixel shader。可以通过在shader中定义一个结构包含你想要存储的数据,并让Vertex shader返回这个实例来决定传递什么数据,或通过在shader中定义参数,使用out关键字来实现。输出可以是位置,雾化,颜色,纹理坐标,切线,光线位置等。

    struct VS_OUTPUT  {      float4 Pos: POSITION;   };  VS_OUTPUT VS( float4 Pos: POSITION )   {      VS_OUTPUT Out = (VS_OUTPUT) 0;       ...       return Out;  }  // or   float3 VS(out float2 tex : TEXCOORD0) : POSITION  {       tex = float2(1.0, 1.0);       return float3(0.0, 1.0, 0.0);  }

    Pixel Shader

    Pixel Shader对给定的模型/对象/一组顶点处理所有像素(逐像素)。这可能是一个金属盒,我们要自定义照明的算法,色彩等等。Pixel Shader从vertex shaders的输出值获取数据,包括位置,法线和纹理坐标:

    float4 PS(float vPos : VPOS, float2 tex : TEXCOORD0) : COLOR  {      ...      return      float4(1.0f, 0.3f, 0.7f, 1.0f);  }

    pixel shader可以有两个输出值:颜色和深度。

    HLSL

    HLSL是用来开发shader的。在HLSL中,您可以声明变量,函数,数据类型,测试(if/else/for/do/while+)以及更多功能以建立一个顶点和像素的处理逻辑。下面是一些HLSL的关键字。这不是全部,但是最重要的。

    数据类型:

    • bool true or false
    • int 32-bit integer
    • half 16bit integer
    • float 32bit float
    • double 64bit double

    向量:

    • float3 vectorTest
    • float vectorTest[3]
    • vector vectorTest
    • float2 vectorTest
    • bool3 vectorTest

    矩阵:

    • float3x3: 3x3矩阵,float类型
    • float2x2: 2x2矩阵, float类型

    还有很多辅助函数处理复杂的数学表达式:

    • cos( x ) 返回x的余弦值
    • sin( x) 返回x的正弦值
    • cross( a, b ) 返回向量a和向量b的叉乘
    • dot( a,b ) 返回向量a和向量b的点乘
    • normalize( v ) 返回一个归一化的向量v(v / |v|)

    完整列表请看:http://msdn2.microsoft.com/en-us/library/bb509611.aspx (译者:推荐看clayman的博客中的The Complete Effect and HLSL Guide连载)

    HSLS提供了大量的函数让你使用!它们能帮助你解决不同的问题。

    Effect文件

    Effect文件(.fx)让开发shader变得更容易,你可以在.fx文件中存储几乎所有关于着色的东西,包括全局变量,函数,结构,vertex shader,pixel shader,不同的techniques/passes,纹理等等。

    我们前面已经讨论了在shader中声明变量和结构,但什么是technique/passes?这很简单。一个Shader可以有一个或一个以上的technique。每个technique都有一个唯一的名称,我们可以通过设置Effect类中的CurrentTechnique属性选择使用哪个technique。

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

    在这里,我们设置“effect”使用technique“AmbientLight”。一个technique可以有一个或多个passes,但请确保处理所有passes以获得我们希望的结果。

    这个例子包含一个technique和一个pass:

    technique Shader   {     pass P0     {         VertexShader = compile vs_1_1 VS();          PixelShader = compile ps_1_1 PS();      }  }

    这个例子包含一个technique和两个pass:

    technique Shader  {      pass P0      {          VertexShader = compile vs_1_1 VS();           PixelShader = compile ps_1_1 PS();       }      pass P1      {          VertexShader = compile vs_1_1 VS_Other();          PixelShader = compile ps_1_1 PS_Other();       }  }

    这个例子包含二个technique和一个pass:

    technique Shader_11  {     pass P0     {         VertexShader = compile vs_1_1 VS();          PixelShader = compile ps_1_1 PS();     }  }  technique Shader_2a   {      pass P0      {          VertexShader = compile vs_1_1 VS2();          PixelShader = compile ps_2_a PS2();       }  }

    我们可以看到,一个technique有两个函数,一个是pixel shader,另一个是vertex shader。

    VertexShader = compile vs_1_1 VS2();   PixelShader = compile ps_1_1 PS2();

    这告诉我们,这个technique将使用VS2()作为vertex shader,PS2()作为pixel shader,并且支持Shader Model 1.1或更高版本。这就让GPU支持更高版本的shader变得可能。在XNA中实现Shader 在XNA中实现Shader很简单。事实上,只需几行代码就可以加载和使用shader。下面是步骤:

    1. 编写shader

    2. 把shader文件(.fx)导入到“Contents”

    3. 创建一个Effect类的实例

    4. 初始化Effect类的实例。

    5. 选择使用的technique

    6. 开始shader

    7. 传递不同的参数至shader

    8. 绘制场景

    9. 结束shader

    更详细的步骤:

    1.记事本和Visual Studio等都可以用来编写shader。也有一些shader的IDE可用,我个人喜欢使用nVidias的FX Composer:http://developer.nvidia.com/object/fx_composer_home.html 。(译者:还推荐一个shader的IDE:AMD公司的RenderMonkey,可在http://ati.amd.com/developer/rendermonkey/downloads.html下载最新版本1.81(93.9MB,2008年4月8日),个人用下来的感觉好像nvidia实力更强一些,文档也很详实,而RenderMonkey上手更容易。)

    2.当shader建立后,将其拖放到“Content”目录,自动生成素材名称。

    3.XNA框架有一个Effect类用于加载和编译shader。要创建这个类的实例可用以下代码:

    Effect effect;

    Effext属于Microsoft.Xna.Framework.Graphics类库,因此,记得添加using语句块:

    using Microsoft.Xna.Framework.Graphics

    4.要初始化shader,我们可以使用Content从项目或文件中加载:

    图2

    effect = Content.Load("Shader");

    “Shader”是你添加到Content目录的shader名称。

    5.选择使用何种technique:

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

    6.要使用Effect,请调用Begin()函数:

    effect.Begin();

    此外,您必须启动所有passes。

    foreach (EffectPass pass in effect.CurrentTechnique.Passes)   {      // Begin current pass      pass.Begin();

    7.有很多方法可以设置shader的参数,但对这个教程来说下列方法够用了。注:这不是最快的方法,在以后的教程中我将回到这里:

    effect.Parameters["matWorldViewProj"].SetValue(worldMatrix * viewMatrix*projMatrix);

    其中“matWorldViewProj”是在shader中定义的:

    float4x4 matWorldViewProj;

    将matWorldViewProj设置为worldMatrix * viewMatrix * projMatrix。

    SetValue设置参数并将它传递到shader,GetValue 从shader获取值,Type是获取的数据类型。例如,GetValueInt32()得到一个整数。

    8.渲染你想要这个shader处理/转换的场景/对象。

    9.要停止pass,调用pass.End(),要停止shader,调用Effect的End()方法:

    pass.End();  effect.End();

    为了更好地理解步骤,可参见源代码。

    环境光照(Ambient light)

    OK,我们终于到了最后一步,实现shader!不坏吧?首先,什么是“Ambient light” ? 环境光是场景中的基本光源。如果你进入一个漆黑的屋子,环境光通常是零,但走到外面时,总是有光能让你看到。环境光没有方向(译者:所以也将其称为“全局光照模型”),在这里应确保对象不会自己发光,它有一个基本的颜色。环境光的公式是:

    I = Aintensity* Acolor

    其中I是光的实际颜色, Aintensity是光的强度(通常在0.0和1.0之间),Acolor环境光的颜色,这个颜色可以是固定值,参数或纹理。好吧,现在开始实现Shader。首先,我们需要一个矩阵表示世界矩阵:

    float4x4 matWorldViewProj ;

    在shader顶端声明这个矩阵(作为全局变量)然后,我们需要知道vertex shader向pixel shader传递了哪些值。这可以通过建立一个结构(可以命名为任何值)实现:

    struct OUT  {      float4 Pos: POSITION;   };

    我们创建了一个名为OUT的结构,其中包含一个float4类型的名叫Pos的变量。“:”后面的POSITION告诉GPU在哪个寄存器(register)放置这个值?嗯,什么是寄存器?寄存器是GPU中保存数据的一个容器。GPU使用不同的寄存器保存位置,法线,纹理坐标等数据,当定义一个shader传递到pixel shader的变量时,我们必须决定在GPU的何处保存这个值。 看一下vertex shader:

    OUT VertexShader( float4 Pos: POSITION )  {      OUT Out = (OUT) 0;       Out.Pos = mul(Pos, matWorldViewProj);       return Out;  }

    我们创建了一个OUT类型的函数,它的参数是float4类型的Pos:POSITION。这是模型文件/应用程序/游戏中定义的顶点位置。然后,我们建立一个名叫OUT的OUT结构实例。这个结构必须被填充并从函数返回,以便后继过程处理。输入参数中的Pos不参与后继过程的处理,但需要乘以worldviewprojection矩阵使之以正确放置在屏幕上。由于Pos是OUT中的唯一变量,我们已经返回它并继续前进。现在开始处理pixel shaders,我们声明为一个float4类型的函数,返回存储在GPU中的COLOR寄存器上的float4值。我们在pixel shader中进行环境光的算法:

    float4 PixelShader() : COLOR  {      float Ai = 0.8f;      float4 Ac = float4(0.075, 0.075, 0.2, 1.0);       return Ai * Ac;   }

    这里我们使用上面的公式计算目前像素的颜色。Ai是环境光强度,Ac是环境光颜色。最后,我们必须定义technique并将pixel shader和vertex shader函数绑定到technique上:

    technique AmbientLight  {      pass P0      {          VertexShader = compile vs_1_1 VertexShader();          PixelShader = compile ps_1_1 PixelShader();      }  }

    好了,完成了!现在,我建议你看看源代码,并调整各个参数更好地理解如何使用XNA实现shader。

    转载于:https://www.cnblogs.com/lifesteven/p/3601077.html

    展开全文
  • 本文的第一部分系列文章的前言,然后第二部分介绍了这个系列文章中我们会使用的游戏场景创建方式,最后一部分讲解了如何在Unity中创建和使用Shader,为后面专注于介绍如何在Unity中进行Shader编程打好了基础。...



    本系列文章由@浅墨_毛星云 出品,转载请注明出处。  

    文章链接: http://blog.csdn.net/poem_qianmo/article/details/40723789

    作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442

    邮箱: happylifemxy@163.com

     

     

    作为一个系统介绍Unity3D中Shader编写的系列文章的开篇,本文的第一部分为系列文章的前言,然后第二部分介绍了这个系列文章中我们会使用的游戏场景创建方式,最后一部分讲解了如何在Unity中创建和使用Shader,为后面专注于介绍如何在Unity中进行Shader编程打好了基础。

     

    因为后面推出的系列文章会着重介绍各种Shader的写法和实现,不会再具体讲解如何创建场景和写出Shader代码后如何使用,相信这篇文章作为本系列的开篇,发表出来肯定还是会对大家多少有些帮助的。大家以后阅读稍后推出的Unity Shader系列文章的时候,有场景创建或者Shader代码写好了如何使用方面的疑问的话,可以随时回过头来查阅这篇文章。

     

    OK,就让我们从这篇文章开始一趟精彩万分的Shader游戏编程旅途。

    依旧国际惯例,看几张文章中实现的场景美图先:



     

     





    上图中展示的文本配套Unity工程的可运行exe浅墨也为大家准备好了,有兴趣的朋友们可以点击 这里进行下载、运行和探索:


    PS:文章配套的三个unitypackage和最终的工程源码在文章末尾处提供下载。

     







    一、系列文章前言





    在这个系列开头,浅墨想说的是,其实这个系列文章中我们学的主要是着色器编程技术,重点不是学Unity。

    甚至可以这样说,我们学的是HLSL——没错,就是DirectX中的那个HLSL。


    为什么这样讲,让我们来捋一捋。

    首先,Unity中编写Shader的语言叫做ShaderLab,而ShaderLab说白了就是裹着一层皮的CG着色器语言而已。Cg,即C forgraphics,即用于图形的C语言,是微软Microsoft和英伟达NVIDIA相互协作在标准硬件光照语言的语法和语义上达成的一种一致性协议。

    HLSL和CG其实是同一种语言(参见Cg教程_可编程实时图形权威指南29页的致谢部分)。很多时候,我们会发现用HLSL写的代码可以直接当中Cg代码使用。

    Microsoft和NVIDIA联手推出CG语言,想在经济和技术上实现双赢,从而通过这种方式联手打击他们共同的对手GLSL。


    既然Unity主打Shader编程的语言ShaderLab是CG语言披上一层皮,而CG语言又约等于HLSL。这就是说,在Unity中写Shader约等于用HLSL写Shader,也就约等于给DirectX写Shader。虽然有点绕orz,最后总结一下也就是:

    在Unity中写Shader约等于给DirectX写Shader


    而Unity又是这样一个集万千宠爱于一身的可见即所得的目前在移动互联网时代火到不行的游戏引擎。可以说,Unity可见即所得的开发环境非常适合Shader的学习,而且在Unity分分钟可以创建出来一个漂亮的场景里面写写Shader,心情都会好很多。不再是苦逼地面朝代码背朝天了。

    所以浅墨决定开始在Unity中进行这个shader学习系列,毕竟Unity、CG、HLSL不分家。

    另外促成这个系列文章的成型的一个原因是Unity的Asset store。浅墨很喜欢Unity引领的Asset store这样一站式的游戏素材商店,里面有数不尽的游戏插件、素材、资源、脚本代码参考、shader资料等等,甚至现成的游戏工程范例。Asset store给开发者们带来了很大的便利,简直就是游戏开发界的大宝库。

    但需要说明的是,Unity这款引擎的缺点也是很明显的。比如Unity不对外开源,我们看不到源码,坑比较多,遇到坑了看不到

    源码给解决带来了很大难度。执行效率还是不太行,渲染大场景和做高级渲染的时候还是显得力不从心。比如渲染大片的近乎

    真实的动态水面时,帧数就立马降下来了,需要后期做很多的优化。就画面质量来说和Unreal Engine和cryEngine等次时代

    引擎比还是有差距。是最近几年互联网的浪潮和得屌丝者的天下商业模式促进了其最近几年如此的成功。


     

    说了这么多,总结一下。

    Unity只是我们学习CG、HLSL编程可见即所得的好帮手好工具而已。我们主要还是利用它来更好的学计算机图形学和Shader编程,顺便掌握目前热门的Unity引擎的基本使用和研发思路。

    我们还是忘不了C++和DirectX,我们还是渴望通过自己的努力,最终有能力用C/C++一句一句写出自己的游戏引擎,我们还是想从零开始造轮子,毕竟那样一句一句写出来的代码都是自己的,而不是那些别人为我们准备好的现成的API函数。

    谨以此前言,与诸君共勉。

     

     


     

     

     




    二、用Unity创建第一个美丽的游戏场景





    首先要说明的是,作为一个从入门内容开始逐渐深入介绍的系列教程,这一部分在Unity下创建场景的内容是为还不太熟悉Unity的朋友们准备的,如果你已经熟悉了Unity的使用,这部分可以快速跳读。

     

     

    OK,正式开始吧。

     





    2.1 【第一步】当然是新建一个项目

     



    大家肯定都知道,每次新建项目后或者新建场景后,会得到一片Unity中默认为全蓝的场景。想要场景变得有生机,一般都是去菜单栏的GameObject里面新建Terrain(地形)然后进行编辑。Terrain的制作很耗时而且水很深,想要精通也是得花一些功夫。

    甚至Unity Asset Store中有各种可以辅助快速生成AAA级大作风格的真实场景的插件,如Terrain Composer,配合着Unity中有名的Relief Terrain Pack v3地形辅助着色渲染工具,可以生成近乎以假乱真的三维自然风光出来。

    漂亮地形的创建当然不属于我们讲解的重点,网络上有数不清的文章和视频讲这方面的内容,有需要的话,大家去学一些基础,或者直接用Asset Store中现成的各种漂亮场景。反正浅墨是各种在网上下载AssetStore中美工大牛们做场景,然后简单的修改,为自己测试和平常调数值所用。

    这不,浅墨为了写这篇博客,就为大家再加工“创作“了一个夏威夷风格的场景来:)


     




    2.2 【第二步】导入Hawaii Environment.unitypackage场景包



    上文讲到,为了节约时间,浅墨提前为大家修改好了一个场景,然后这个场景已经打包,叫做“HawaiiEnvironment.unitypackage “,在文章末尾提供下载。(限于Unity对中文的支持拙计,无奈只能取英文名,不然直接导入就报错)。

          HawaiiEnvironment.unitypackage单独下载请点我】

     

    双击这个包,导入到我们空空如也的工程中,经过一段时间的读条,就导入完毕了。然后我们双击打开出现在Project面板中Assets文件夹下的场景文件Hawaii Environment.unity

     

    接着便打开了场景,如果打开成功,Scene面板中应该便出现了如下类似的场景画面:

     


     

    因为略去了场景编辑部分,直接导入,所以过程是非常简单的。但是,这还完全不够。让我们在场景中添加一个可以自由控制的摄像机吧。

     

     




    2.3 【第三步】添加第一人称摄像机



    浅墨准备的这个场景包是没有摄像机的,单单就是场景,所以我们还需要在场景中添加一个摄像机。

     

    大家应该清楚,比较常见添加摄像机的做法是通过菜单栏中的GameObject->CreateOther->Camera来添加。但这种方式的摄像机是固定的,不合我们的要求。我们想添加的是一个在游戏运行时可以自由移动视角的第一人称摄像机。其实Unity自带的资源包中刚好可以满足我们的要求。于是我们在Project面板中右键【Import Package】,或者菜单栏中Assets->ImportPackage->Character Controller来导入官网为我们准备的的角色控制资源包。如下图:

     

     

     

     

    点击之后,会弹出如下的资源导入确认窗口,我们直接点确定就行了:

     

     

     

    因为这个包很小,所以很快就导入完成,这时Assets根文件夹下会出现一个名为Standard Assets的文件夹,展开它或者点进去,就是名为【CharacterControllers】的文件夹,继续点进去,发现了一个胶囊状的叫【First PersonController】的家伙,这就是我们需要的了。

    然后我们先在Scene面板中利用【右键+键盘W、A、S、D】以及滚轮等操作调整好场景,然后在我们刚才的【CharacterControllers】下点击这个胶囊装的【First Person Controller】按住不放,拖动到Scene场景中,选到合适的地方(如草坪上)后就放手,操作如下:

    Unity会自动将这个【CharacterControllers】的中心位置依附到地形表面。

     

    这个时候我们会发现之前是黑屏的Game面板中也有了画面:

     

     

    这时我们还要将这个 First Person Controller的底部向上拖动一点,不然运行游戏时我们会不停的往下掉,因为在Unity默认情况下First Person Controller的中心位于中部,这会照成它的底部已经穿透地形,悬空位于地形的下方,自然一运行就往下掉。

     

    我们Hierarchy面板中选中First Person Controller,工具栏中选择【移动】工具

    然后对着场景中胶囊上的代表Y轴的绿色箭头向上适当拖动,让胶囊的底部确保位于草地之上就行了。

     

    这时候我们点击unity中间三角尖的【运行】按钮,就可以自由地在场景中观察和移动了~



    Unity第一人称控制器默认操作方式类似CS,CF一类的FPS游戏。W、A、S、D前后左右移动,空格跳跃,鼠标移动调整视角,非常有亲切感有木有~

    这就很好地体现了Unity的入门容易的特点,只用点点鼠标一个漂亮的场景就展现在眼前。





     

    2.4 【第四步】在游戏场景中加入背景音乐

     

     


    话说这么美丽的场景怎么能没有音乐?

    不妨就让我们添加一段优美的钢琴曲吧。曲子浅墨都为大家准备好了,上文已经导入的HawaiiEnvironment.unitypackage包中,在Assets根目录下包含了一首林海的《日光告别》。

     

    我们要做的只要是把这个音乐文件拖拽到第一人称摄像机First PersonController上就可以了,就像箭头中指的这样:

     

     

    拖拽完成后,First Person Controller的Inspector面板中就应该会多了一个Audio Source组件。


    运行场景,伴随着美丽的场景,“吹着海风”,优美的钢琴曲入耳,非常怡人。

     

    先放两张测试过程中的场景美图,再继续我们下一部分的讲解吧:




    非常逼真的水效,采用大名鼎鼎的NGUI工作室Tasharen Entertainment出品的水面插件:



     






     

     

     

    三、导入QianMo’s Toolkit并使用







    3.1 认识QianMo's Toolkit

     



    所谓的QianMo's Toolkit,其实就是浅墨为场景测试写的一个小脚本工具集,打包成一个unitypackage方便多次使用而已。若有需要,浅墨会在其中添加更多的功能。

    以后我们每次新建工程的时候,只要导入这个小工具就可以使用我们之前已经写好的各种特性,非常便捷。


    QianMo's Toolkit v1.0.unitypackage单独下载请点我】


    QianMo's Toolkit v1.0版的内容如下:

     

    也就是包含了五个脚本文件,两张图片。这五个脚本文件的功能分别为:

     

    ShowFPS:在游戏运行时显示帧率相关信息

    ShowObjectInfo:在场景中和游戏窗口中分别显示添加给任意物体文字标签信息。隐藏和显示可选,基于公告板技术实现。

    ShowGameInfo:在游戏运行时显示GUI相关说明

    ShowLogo:在游戏运行时显示Logo

    ShowUI:在游戏运行时显示简单的镶边UI。

     

    这个五个脚本的代码浅墨都已经详细注释,在后续文章中有机会我们会介绍其具体写法。这篇文章中就先简单的认识一下他们就好。PS:下文第四节中贴出了ShowGameInfo脚本的全部代码。

     

     

     

     




    3.2 使用QianMo's Toolkit




    上文已经说了,既然这是一个unitypackage,那么只用双击它导入到我们当前的项目中就行了。导入完成之后。Assets文件夹下就又多了一个名为” QianMo's Toolkit v1.0“的文件夹,内容就是我们刚才介绍的5个脚本文件两张图:

     

     

    暂时我们要使用的是ShowGameInfo、ShowLogo、ShowUI这三个脚本文件,把它们一起拖到我们之前创建的第一人称摄像机First Person Controller上就行了:

     

     


    拖动完成后,我们在First Person Controller的Inspector面板中发现其多了三个组件,就是我们给他添加的这个三个脚本:

     

    其实Show Logo无关紧要,就是显示了浅墨自己的logo而已,当然你可以换成自己的logo。show UI也无关紧要,就是显示了一个顶部的镶边png。主要的是这个ShowGameInfo,它是用于显示帧率等相关文字消息的。(其实简约党会觉得三个都无关紧要,orz)

     

    拖动完成之后,再次运行,我们来看一看效果:


     

    可以发现,游戏窗口的边边角角多了一些说明和图片,以及有了帧率的显示。

     

     

     

     

     

     


     

     

    四、书写和使用第一个Shader

     




    上文讲解的都是一般的场景构建过程,接下来就要正式开始我们的核心部分,书写第一个Shader了。在完成上文中讲解的创建好漂亮的场景之后,我们首先可以在Assets根目录下创建一个文件夹,用于以后Shader和Material文件的存放。创建过程可以是在Project面板的空白处右键->Create->Folder,也可以是点击Project面板中的Create下拉菜单->Folder

     

     

     

    给新出来的这个文件夹取名Shaders,然后回车。然后再用同样的方法在Assets根目录下创建一个名为Textures的文件夹,用于稍后素材图片的存放。那么,如果你按照浅墨按照目前描述的步骤来的话,Assets根目录到现在就是这样的5个文件夹:

     

     

    接着,进去到我们创建的Shader文件夹。同样在空白处右键->Create->Shader,或者是直接点Create下拉菜单->Shader,创建一个Shader文件,取名为   “0.TheFirstShader”。然后双击打开它,Unity会默认使用名为MonoDevelop的编辑器打开这个Shader文件。


    小tips:可以在菜单栏中Edit->Preferences->ExternalTools中调成默认用Visual Studio打开,但未经修改配置文件的Visual Studio对Shader后缀的文件是不支持语法高亮的,浅墨修改了部分配置文件才让Visual Studio支持了Unity Shader书写的语法高亮。对于不太清楚如何修改的朋友,可以善用搜索引擎,或者过些天浅墨会单独发一篇名为《Unity中使用Visual Studio编写shader并设置代码高亮》的文章来专门讲解。

     

     

    作为初次写Shader,我们暂且先用MonoDevelop顶一顶,后面的文章再换用修改了配置文件的Visual Studio。

     

    好了,用MonoDevelop打开我们新建的这个Shader文件,发现Unity已经为我们写好了很多代码。

    我们不妨自己重新写点不一样的东西。删掉原本的这些代码,拷贝浅墨写的如下代码到编辑器中:

     

     

    //-----------------------------------------------【Shader说明】----------------------------------------------
    //		Shader功能:   凹凸纹理显示+自选边缘颜色和强度
    //     使用语言:   Shaderlab
    //     开发所用IDE版本:Unity4.5 06f 、Monodevelop   
    //     2014年11月2日  Created by 浅墨    
    //     更多内容或交流请访问浅墨的博客:http://blog.csdn.net/poem_qianmo
    //---------------------------------------------------------------------------------------------------------------------
    
    
    Shader "浅墨Shader编程/0.TheFirstShader" 
    {
    	//-------------------------------【属性】-----------------------------------------
    	Properties 
    	{
    		_MainTex ("【纹理】Texture", 2D) = "white" {}
    		_BumpMap ("【凹凸纹理】Bumpmap", 2D) = "bump" {}
    		_RimColor ("【边缘颜色】Rim Color", Color) = (0.17,0.36,0.81,0.0)
    		_RimPower ("【边缘颜色强度】Rim Power", Range(0.6,9.0)) = 1.0
    	}
    
    	//----------------------------【开始一个子着色器】---------------------------
    	SubShader 
    	{
    		//渲染类型为Opaque,不透明
    		Tags { "RenderType" = "Opaque" }
    
    		//-------------------开始CG着色器编程语言段-----------------
    		CGPROGRAM
    
    		//使用兰伯特光照模式
    		#pragma surface surf Lambert
    		
    		//输入结构
    		struct Input 
    		{
    			float2 uv_MainTex;//纹理贴图
    			float2 uv_BumpMap;//法线贴图
    			float3 viewDir;//观察方向
    		};
    
    		//变量声明
    		sampler2D _MainTex;//主纹理
    		sampler2D _BumpMap;//凹凸纹理
    		float4 _RimColor;//边缘颜色
    		float _RimPower;//边缘颜色强度
    
    		//表面着色函数的编写
    		void surf (Input IN, inout SurfaceOutput o)
    		{
    			//表面反射颜色为纹理颜色
    			o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    			//表面法线为凹凸纹理的颜色
    			o.Normal = UnpackNormal (tex2D (_BumpMap, IN.uv_BumpMap));
    			//边缘颜色
    			half rim = 1.0 - saturate(dot (normalize(IN.viewDir), o.Normal));
    			//边缘颜色强度
    			o.Emission = _RimColor.rgb * pow (rim, _RimPower);
    		}
    
    		//-------------------结束CG着色器编程语言段------------------
    		ENDCG
    	} 
    
    	//“备胎”为普通漫反射
    	Fallback "Diffuse"
    }


     


    由于这是第一篇Shader系列文章,已经涉及到很多内容了,所以浅墨不可能展开讲解这段代码的具体思路和写法,不过已经详细注释,大家应该会多少有点明白。随着稍后文章的深入,这段代码就显得很简单易懂了。

    拷贝完成,保存一下这段代码,unity会自动检测和编译被保存的代码,我只需返回Unity窗口,等待编译完成即可。若没有错误,在“0.TheFirstShader”的inspector面板中得到的结果应该是有红色的错误提示的。

     

    需要注意的是,Shader想要使用到游戏物体上,一般得有个媒介,这个媒介就是我们的老朋友——材质(Material)。我们把Shader作用于材质,接着再把材质对应地作用于给游戏物体,这样写的Shader就间接地给物体表面使用了。


     


    而这一层关系,在Unity中完全可以通过点点鼠标,拖动来完成。下面我们就来讲一讲如何将一个着色程序的结果显示到物体表面上。

     

    知道以上原理了就很简单了,在“0.TheFirstShader.shader”的同一目录下创建一个Material。同样是可以通过Create下拉菜单->Material或者空白处右键->create->Material来完成。


    为了到时候方便对应,我们将这个材质也取名为0.TheFirstShader。

     

     

    接着,将0.TheFirstShader.shader拖动到0.TheFirstShader材质身上然后释放。

     

     

    拖动完成后,我们单击0.TheFirstShader材质,打开他的面板,发现他已经和一开始不一样了,泛着蓝光:




    还没完,接下来我们还得给这个材质添加两张纹理图片。图片浅墨也已经提前准备好了,在名为Textures01 by QianMo.unitypackage的Unity包中,同样双击这个包然后打开导入到项目中。


    Textures01 by QianMo.unitypackage单独下载请点我】


    我们在Textures文件夹下找到这两张纹理,接下来做的就是将他们拖动到0.TheFirstShader材质对应的纹理区域中,如下:

     

     

    或者点击这里的Select分别选择,操作如下:


     

    两张纹理选择完毕后,我们的材质就准备好了,最后的结果,有点黑科技,如各种科幻游戏和电影中发光的矿石,非常炫酷:

     

     


    OK,那么就只剩下最后一步了,就是在场景中创建一个物体,然后将我们做好的材质拖拽到物体身上赋给这个物体就行了。

     

    菜单栏【GameObject】->【Create Other】->【Capsule】或者【Create】下拉菜单->【Capsule】来在场景中创建一个胶囊装的物体。把他拖动到和我们的第一人称摄像机【First Person Controller】很近的地方,这样方便观察,接着就可以把我们的“0.TheFirstShader”材质直接拖拽给场景中的这个胶囊,或者Hierachy面板中【Capsule】名字上就行了,操作如下图中的箭头所示:

     

     

     

     

    经过拖拽,Capsule加上Material后的效果如下:



     

     




     

    4.1 给使用Shader的物体加上文字说明




    为了以后介绍多个Shader写法时能更清晰更方便,浅墨专门在QianMo’s Toolkit中做了一个可以在场景中和游戏窗口中分别显示附加给任意物体文字标签信息的工具脚本,叫做ShowObjectInfo,其详细注释的代码如下:

     


     

    //-----------------------------------------------【脚本说明】-------------------------------------------------------
    //      脚本功能:    在场景中和游戏窗口中分别显示给任意物体附加的文字标签信息
    //      使用语言:   C#
    //      开发所用IDE版本:Unity4.5 06f 、Visual Studio 2010    
    //      2014年10月 Created by 浅墨    
    //      更多内容或交流,请访问浅墨的博客:http://blog.csdn.net/poem_qianmo
    //---------------------------------------------------------------------------------------------------------------------
    
    //-----------------------------------------------【使用方法】-------------------------------------------------------
    //      第一步:在Unity中拖拽此脚本到某物体之上,或在Inspector中[Add Component]->[浅墨's Toolkit v1.0]->[ShowObjectInfo]
    //      第二步:在Inspector里,Show Object Info 栏中的TargetCamera参数中选择需面向的摄像机,如MainCamera
    //      第三步:在text参数里填需要显示输出的文字。
    //      第四步:完成。运行游戏或在场景编辑器Scene中查看显示效果。
    
    //      PS:默认情况下文本信息仅在游戏运行时显示。
    //      若需要在场景编辑时在Scene中显示,请勾选Show Object Info 栏中的[Show Info In Scene Editor]参数。
    //      同理,勾选[Show Info In Game Play]参数也可以控制是否在游戏运行时显示文本信息
    //---------------------------------------------------------------------------------------------------------------------
    
    
    //预编译指令,检测到UNITY_EDITOR的定义,则编译后续代码
    #if UNITY_EDITOR    
    
    
    //------------------------------------------【命名空间包含部分】----------------------------------------------------
    //  说明:命名空间包含
    //----------------------------------------------------------------------------------------------------------------------
    using UnityEngine;
    using UnityEditor;
    using System.Collections;
    
    //添加组件菜单
    [AddComponentMenu("浅墨's Toolkit v1.0/ShowObjectInfo")]
    
    
    //开始ShowObjectInfo类
    public class ShowObjectInfo : MonoBehaviour
    {
    
        //------------------------------------------【变量声明部分】----------------------------------------------------
        //  说明:变量声明部分
        //------------------------------------------------------------------------------------------------------------------
        public string text="键入你自己的内容 by浅墨";//文本内容
        public Camera TargetCamera;//面对的摄像机
        public bool ShowInfoInGamePlay = true;//是否在游戏运行时显示此信息框的标识符
        public bool ShowInfoInSceneEditor = false;//是否在场景编辑时显示此信息框的标识符
        private static GUIStyle style;//GUI风格
    
    
    
        //------------------------------------------【GUI 风格的设置】--------------------------------------------------
        //  说明:设定GUI风格
        //------------------------------------------------------------------------------------------------------------------
        private static GUIStyle Style
        {
            get
            {
                if (style == null)
                {
                    //新建一个largeLabel的GUI风格
                    style = new GUIStyle(EditorStyles.largeLabel);
                    //设置文本居中对齐
                    style.alignment = TextAnchor.MiddleCenter;
                    //设置GUI的文本颜色
                    style.normal.textColor = new Color(0.9f, 0.9f, 0.9f);
                    //设置GUI的文本字体大小
                    style.fontSize = 26;
                }
                return style;
            }
    
        }
    
    
    
    
        //-----------------------------------------【OnGUI()函数】-----------------------------------------------------
        // 说明:游戏运行时GUI的显示
        //------------------------------------------------------------------------------------------------------------------
        void OnGUI( )
        {
            //ShowInfoInGamePlay为真时,才进行绘制
            if (ShowInfoInGamePlay)
            {
                //---------------------------------【1.光线投射判断&计算位置坐标】-------------------------------
                //定义一条射线
                Ray ray = new Ray(transform.position + TargetCamera.transform.up * 6f, -TargetCamera.transform.up);
                //定义光线投射碰撞
                RaycastHit raycastHit;
                //进行光线投射操作,第一个参数为光线的开始点和方向,第二个参数为光线碰撞器碰到哪里的输出信息,第三个参数为光线的长度
                collider.Raycast(ray, out raycastHit, Mathf.Infinity);
                
                //计算距离,为当前摄像机位置减去碰撞位置的长度
                float distance = (TargetCamera.transform.position - raycastHit.point).magnitude;
                //设置字体大小,在26到12之间插值
                float fontSize = Mathf.Lerp(26, 12, distance / 10f);
                //将得到的字体大小赋给Style.fontSize
                Style.fontSize = (int)fontSize;
                //将文字位置取为得到的光线碰撞位置上方一点
                Vector3 worldPositon = raycastHit.point + TargetCamera.transform.up * distance * 0.03f;
                //世界坐标转屏幕坐标
                Vector3 screenPosition = TargetCamera.WorldToScreenPoint(worldPositon);
                //z坐标值的判断,z值小于零就返回
                if (screenPosition.z <= 0){return;}
                //翻转Y坐标值
                screenPosition.y = Screen.height - screenPosition.y;
                
                //获取文本尺寸
                Vector2 stringSize = Style.CalcSize(new GUIContent(text));
                //计算文本框坐标
                Rect rect = new Rect(0f, 0f, stringSize.x + 6, stringSize.y + 4);
                //设定文本框中心坐标
                rect.center = screenPosition - Vector3.up * rect.height * 0.5f;
    
    
                //----------------------------------【2.GUI绘制】---------------------------------------------
                //开始绘制一个简单的文本框
                Handles.BeginGUI();
                //绘制灰底背景
                GUI.color = new Color(0f, 0f, 0f, 0.8f);
                GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
                //绘制文字
                GUI.color = new Color(1, 1, 1, 0.8f);
                GUI.Label(rect, text, Style);
                //结束绘制
                Handles.EndGUI();
            }
        }
    
        //-------------------------------------【OnDrawGizmos()函数】---------------------------------------------
        // 说明:场景编辑器中GUI的显示
        //------------------------------------------------------------------------------------------------------------------
        void OnDrawGizmos()
        {
            //ShowInfoInSeneEditor为真时,才进行绘制
            if (ShowInfoInSceneEditor)
            {
                //----------------------------------------【1.光线投射判断&计算位置坐标】----------------------------------
                //定义一条射线
                Ray ray = new Ray(transform.position + Camera.current.transform.up * 6f, -Camera.current.transform.up);
                //定义光线投射碰撞
                RaycastHit raycastHit;
                //进行光线投射操作,第一个参数为光线的开始点和方向,第二个参数为光线碰撞器碰到哪里的输出信息,第三个参数为光线的长度
                collider.Raycast(ray, out raycastHit, Mathf.Infinity);
                
                //计算距离,为当前摄像机位置减去碰撞位置的长度
                float distance = (Camera.current.transform.position - raycastHit.point).magnitude;
                //设置字体大小,在26到12之间插值
                float fontSize = Mathf.Lerp(26, 12, distance / 10f);
                //将得到的字体大小赋给Style.fontSize
                Style.fontSize = (int)fontSize;
                //将文字位置取为得到的光线碰撞位置上方一点
                Vector3 worldPositon = raycastHit.point + Camera.current.transform.up * distance * 0.03f;
                //世界坐标转屏幕坐标
                Vector3 screenPosition = Camera.current.WorldToScreenPoint(worldPositon);
                //z坐标值的判断,z值小于零就返回
                if (screenPosition.z <= 0) { return; }
                //翻转Y坐标值
                screenPosition.y = Screen.height - screenPosition.y;
                
                //获取文本尺寸
                Vector2 stringSize = Style.CalcSize(new GUIContent(text));
                //计算文本框坐标
                Rect rect = new Rect(0f, 0f, stringSize.x + 6, stringSize.y + 4);
                //设定文本框中心坐标
                rect.center = screenPosition - Vector3.up * rect.height * 0.5f;
    
    
    
                //----------------------------------【2.GUI绘制】---------------------------------------------
                //开始绘制一个简单的文本框
                Handles.BeginGUI();
                //绘制灰底背景
                GUI.color = new Color(0f, 0f, 0f, 0.8f);
                GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
                //绘制文字
                GUI.color = new Color(1, 1, 1, 0.8f);
                GUI.Label(rect, text, Style);
                //结束绘制
                Handles.EndGUI();
    
            }
    
        }
    
    }
    
    //预编译命令结束
    #endif

     

    这个脚本的用法倒是很简单,在代码的说明部分已经详细写出,在这里我们再列出一遍:

     

    第一步:在Unity中拖拽此脚本到某物体之上,或在Inspector中[Add Component]->[浅墨's Toolkit v1.0]->[ShowObjectInfo]

    第二步:在Inspector里,ShowObject Info 栏中的TargetCamera参数中选择需面向的摄像机,如Main Camera,FirstPerson Controller等

    第三步:在text参数里填需要显示输出的文字。

    第四步:完成。运行游戏或在场景编辑器Scene中查看显示效果。

     

     

    也就是拖拽ShowObjectInfo脚本或者直接添加组件给需要附加文字的物体,然后在Inspector中输入需要显示的文字,然后选择其面对的摄像机就可以了。

     

     

     

    我们将ShowObjectInfo脚本拖拽给上文中刚刚变得炫酷外形黑科技的Capsule:

     

    那么他在Inspector就多了一个“ShowObject Info(Script)”组件,将该组件的Text项中填上“凹凸纹理+边缘发光效果”,TargetCamera中填上First Person Controller的子物体Main Camera:

     

     

    最后,得到的效果就是这样:


     









     


    五、总结、配套资源&最终工程下载

     




    好了,本篇的文章到这里就大概结束了。

     

    今天讲的内容还是非常多的,对于新接触Unity的朋友们来说或许还得好好消化消化,而熟悉Unity的朋友应该很快就可以看懂,或者觉得浅墨讲了一堆废话,orz。

     

    这篇文章的内容说白了就非常简单,也就是新建工程,然后导入三个浅墨提前准备好的unitypackage游戏资源,点一点鼠标拖动拖动脚本,新建一个Shader,写点代码,再创建一个Material,Shader赋给这个Material,最后创建一个胶囊状Capsule,Material赋给这个Capsule,点运行查看最终效果。一切,就是这么简单。:)

     

     

    本文配套的三个unitypackage打包请点击此处下载:


    【浅墨Unity3D Shader编程】之一 配套的三个unitypackage打包下载




    本文最终的Unity工程请点击此处下载:


    【浅墨Unity3D Shader编程】之一 配套Unity工程




    最后放几张最终的场景美图吧。

     

    站在亭子上看世界:

     

     

    逼真的光晕:

     

     

    漂亮的天空:

     

     

     

    乱真的水面:

     

     

    蓝天和草地树木交相辉映:

     

     

     

    OK,全文到此结束。

    新的游戏编程之旅已经开启,下周一,我们不见不散。


     

    展开全文
  • 【Unity3D Shader编程】之十三 单色透明Shader 标准镜面高光Shader
  • Shader编程学习笔记

    2017-04-10 13:21:39
    转自http://www.cnblogs.com/maple-share/p/5382228.html 里面有Shader编程相关,可以看看
  • Shader编程一直是一个比较难入门难上手的主题,本篇对Unity Shader编程的一些基础和要点进行了总结。 包括Shader编程相关知识图谱、Shader编程相关数据类型、Shader核心结构体等(后续继续补充)。 每个部分...
  • 【Unity Shader编程】之十四 边缘发光Shader Rim Shader 的两种实现形态
  • 课程介绍: Shader在游戏中的作用非常重要,然而学习shader的路却不是那么容易,它涉及到方方面面的知识和基础, 比如:3D数学,计算机图形学甚至硬件。很多朋友为了达到一种特别的功能,往往在互联网上四处搜索别人...
  • Unity Shader编程(2)Unity Shader初步 Unity通过ShaderLab来组织Shader。 下面我们通过分析上一节中的Shader代码来学习Unity Shader的组织形式。 Shader "husheng/Shader" { Properties { _Color ("Color", ...
  • Shader编程——高光漫反射模型

    千次阅读 2018-07-28 11:19:05
    在实现该模型之前,我对shader和计算机图形学的知识可谓...一个基础的Shader编程,实现高光漫反射模型。 在正式编写shader代码前,我们首先得对一些基础知识做相应的了解,这里涉及到GPU的渲染流程和Shader编程的数...
  • QT5.9.2+OpenGL,使用最新的QOpenGLWidget框架shader编程,原始的框架都采用QGLWidget,这是即将被QT淘汰的框架,现在使用的QOpenGLWidget框架,简单明了,代码通俗易懂,能够很好的入门。代码实现了用OpenGL Shader...
  •  本文由@浅墨_毛星云 出品,首发于知乎专栏,转载请注明出处  ... 本文是【GPU精粹与Shader编程】系列的第七篇文章。文章盘点、提炼和总结了...同时这篇文章,也是【GPU精粹与Shader编程】系列文章对GPU精粹...
  • 【Unity3D】夏威夷场景 for Unity3D Shader编程 by浅墨

    千次下载 热门讨论 2014-11-03 17:02:35
    在此Unity工程中,我们实现了非常美丽的夏威夷海滩场景,用来进行Unity Shader编程的测试所用。测试了凹凸贴图+边缘发光的Shader写法。 场景使用的背景音乐为:林海的《日光告别》 配套博文:《【浅墨Unity3D ...
  • Shader编程学习笔记(五)—— Fixed Function Shader 1 Fixed Function Shader  在学习固定管线着色器中要涉及到的知识点是: PropertiesMaterialLightingSetTexturePass  
  • 6种Shader编程

    2017-10-20 12:31:47
    Shader(着色器)实际上就是一小段程序,它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用,然后输出。绘图单元可以依据这个输出来将图像绘制到屏幕上。输入的贴图或者颜色等,加上对应的...
  • Shader和渲染管线Shader编程学习笔记(二)—— Shader和渲染管线   什么是Shader  Shader,中文翻译即着色器,是一种较为短小的程序片段,用于告诉图形硬件如何计算和输出图像,过去由汇编语言来编写...
  • shader编程教程

    2013-11-25 12:03:38
    shader开发技术工具书,很适合初学者
  • 【Unity Shader编程】之十六 基于MatCap实现适于移动平台的 次时代 车漆Shader
  • 作为可编程Shader系列的第一篇文章,本文将从最简化的可编程Shader开始,逐步变换与实现一个漫反射(也就是实现Lambert光照模型)顶点&片段Shader,可以说,是在讲述一个可编程Shader的进化史。
  • Shader编程教程.txt

    2020-03-30 13:39:18
    是一套关于unity shader的教程,涉及shader的各个基础方面。包括数学,语法,以及特效等。 资源来自互联网,仅限用于学习研究,请勿用于任何商业用途,请支持正版,尊重原版权
  • Shader编程教程 完整

    2018-12-20 14:01:11
    视频教程,上次传过,下载地址都一直有效的,网上花钱买的,分享出来都被下载那么多次了。上次说下载地址无效,重新上传

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,982
精华内容 792
关键字:

shader编程