【Unity 脚本相关】自定义CGInclude 预编译

补充一些零碎的小知识点,为了提高效率我选择更快速的方法,直接引用他人写的不错的文章,复习的时候就可以直接查看啦!

1 自定义cginc工具库 

unity 自定义shader cginc 函数工具库并引用

Unity内置有很多.cginc文件,都是自带的shader工具函数库,例如常用的Lighting.cgincUnityCG.cginc等,shader中引用通常是在PASS中添加如下内容:

#include "UnityCG.cginc"

当我们想要自己自定函数工具库时,就要考虑何种格式、shader中如何使用的问题了。

1.1 创建文件

unity内部不能直接创建.cginc文件,文件夹下文件,更改后缀为.cginc

1.2 标准结构格式

#ifndef XXX
#define XXX

// 定义常用的宏、结构体、全局变量、函数等等

#endif

#ifndef 避免双重定义

 当程序文件多了起来,容易出现文件被重复引用的情况,此时最好加上#ifdef #define和#endif,避免双重定义的错误,拿最近做庄懂赛博小人有个自定义的插值环境光.cginc文件为例:

#ifndef MY_CGINC
#define MY_CGINC

//插值环境光,三个颜色:顶up、侧side、底down
float3 TrinColAmbient (float3 n, float3 uCol, float sCol, float dCol) {
	float uMask = max(0.0, n.g);        // 获取朝上部分遮罩
	float dMask = max(0.0, -n.g);       // 获取朝下部分遮罩
	float sMask = 1.0 - uMask - dMask;  // 获取侧面部分遮罩
	float3 envCol = uCol * uMask +
	                sCol * sMask +
	                dCol * dMask;       // 混合环境颜色
	return enCol;
}

#endif

#ifndef,if ! define,即“如果没定义xx”,整个预编译过程大概是:

如果没定义MY_CGINC这个宏的话,则条件为真,继续进行接下来直到#endif中间的内容,即定义MY_CGINC这个宏,并定义一个方法TrinColAmbient();如果定义过了这个宏,则条件为假,直接跳过内容,endif

1.3 使用

如果.cginc文件在当前shader的相同目录下,直接:

#include "MYcginc.cginc"

但一般我们创建的.cginc文件都会放在跟shader不同的文件目录下,此时就需要相对路径了:

#include "../cginc/Mycginc.cginc"

这里的../表示上一级目录,同样的../../表示上两级目录,具体关于相对路径可以看:什么是相对路径?相对路径的具体写法和用法

2 预编译处理

VS学习c语言笔记记录_九九345的博客-CSDN博客_vs语言符合模式

什么是预编译?何时需要预编译 (C、C++工程师面试题)

既然涉及到了#ifndef、#define的内容,就顺便学习一下预编译处理这个概念。 

2.1 基本概念 

什么是?

预编译也可以叫做预处理,是做些代码文本的替换工作,处理#开头的指令,例如:

#include // 拷贝#include包含的文件代码

#define // 宏定义替换

什么时候开始?

预编译指令发生在程序正式开始编译前,但这个预编译本身可以放在程序的任何位置。

3种功能

  • 宏定义
  • 条件编译
  • 包含文件

2.2 常见的编译指令

这里直接引用了文章避免头文件重复引入和重复定义中的汇总,侵删:

//条件编译
     #define        //  宏定义 
     #undef         //  取消宏 
     #include       //  文本包含 
     #ifdef         //  如果宏被定义就进行编译 
     #if defined    //  与ifdefine的区别在于可以可以组成复杂的判别条件
     #ifndef        //  如果宏未被定义就进行编译 
     #if !defined   //  与if !define的区别在于可以可以组成复杂的判别条件
     #endif         //  结束编译块的控制 
     #if   defined        //  表达式非零就对代码进行编译 
     #else          //  作为其他预处理的剩余选项进行编译 
     #elif          //  这是一种#else和#if的组合选项 
     #elif defined    //  与ifdefine的区别在于可以可以组成复杂的判别条件
	 #elif !defined    //  与ifdefine的区别在于可以可以组成复杂的判别条件
//编译指令
     #line          //  改变当前的行数和文件名称 
     #error         //  输出一个错误信息 
     #pragma        //  为编译程序提供非常规的控制流信息,可跟once,message等许多参数。

2.3 #pragma once 指令

这个指令似乎没怎么见过,它的作用是:使同一个文件不会被包含多次,与上面提到的#ifndef相比更加方便了,遇到已经被引过的文件会直接跳过。但无法剔除不同的2个表达同一个物理意义的文件。

与#ifndef混用

#pragma once

#ifndef  XXX
#define  XXX

#endif

猜你喜欢

转载自blog.csdn.net/qq_41835314/article/details/128835713