Making Sky's Stylized Grass with Compute Shader in Unity
Sky: Children of the Light is one of my favorite games I am playing recently. During the pandemic, it is a great place where we are able to meet people (or even friends) from all over the world. Beyond the plot, music, and cosmetics, I enjoyed every second when I was sliding on those beautiful lands, especially the stylized grass on top of them. In this post, I will share my experience in reproducing the grass in Unity under Universal Render Pipeline (v7.5.3). You will get result like the follow ...
Understand Interface and Abstract Class in Java
Interface and abstract class are similar that I was sometimes confused about their differences, or didn’t know when I should use each. There are a lot of posts about their differences in terms of usage details, but many of them do not cover differences in design. I looked up on the internet and summarized some key points I learned.
Reference:
接口和抽象类有什么区别?
Java 廖雪峰基础教程
CS 61B | Part 2
Top 50+ Core Java Interview Questions And Answers
Java 8接口有default method后是不是可以放弃抽象类了?
Design AspectFirst, w ...
A General Approach to Convert Recursion to Iteration
Generally, we prefer to write recursive solutions for tree, linked list, backtracking, and DFS/BFS problems since the structure of these problems could be recursively defined.
Recursion is good choice for search, enumeration, and divide-and-conquer. — EPI
Thus, the steps that lie in the recursive function correspond to the way we think of the problem. Later, we will see how the code of preorder traversal works and then convert it to an iterative version, and finally to an optimized iterative v ...
注意 Java 中数组和范型的协变性(Covariant)
数组的协变性如果类Base是类Derived的父类,那么Base[]就是Derived[]的父类。
因此,我们的代码可以这么写:
123456789Number[] array1 = new Number[2];array1[0] = Integer.valueOf(1);array1[1] = Integer.valueOf(2);System.out.println(array1[0]); // okNumber[] array2 = new Integer[2];array2[0] = Integer.valueOf(1);array2[1] = Integer.valueOf(2);System.out.println(array2[0]); // ok
但是,数组的协变性可能会导致一些难以发现的错误,比如下面的代码:
123/* Error A */Object[] array3 = new String[10];array3[0] = 10; // -> array[0] = Integer.valueOf(10)
Error A可以通过编译,Objec ...
好好调戏 Java 范型中的通配符以及边界限定规则
通配符 ? 与 T 的区别T:作用于模版上,用于将数据类型进行参数化,不能用于实例化对象。?:在实例化对象的时候,不确定泛型参数的具体类型时,可以使用通配符进行对象定义。(有点像 C++ 的 auto、C 语言的 void * 指针)
<T>等同于<T extends Object><?>等同于<? extends Object>
<? super MyClass>以set的角度去看待。
MyClass是我们知道的提示(一个边界):
不允许调用 get 方法获得 MyClass 的引用(这里是指 MyClass 的 get/set 方法)
因为你不知道用什么去「接收/容纳」这个? super MyClass(不能确定上界),只能用Object。1Object abc = <? super MyClass>.get();
允许调用 set 方法传入 MyClass 的引用
因为<? super MyClass>表示的类对象不是 MyClass,就是它的父亲。(作为「左值」)1<? sup ...
《码农翻身》公众号文章的摘抄笔记
个人很喜欢《码农翻身》公众号里面的文章,因此想把一些好的句子记录下来,方便以后阅读。此外,作者刘欣还将大部分文章整理到一本书里,推荐大家去阅读!豆瓣链接(评分:9.1 分)
程序人生做一个普通人
想想我这 10 多年的发展,可以简单地用一个词来概括:专注技术!
技术宅的性格。
在《明朝那些事儿》的结尾,当年明月写了这么一句话:是的,这就是我想说的,这就是我想通过徐霞客所表达的,足以藐视所有王侯将相,最完美的结束语:成功只有一个——按照自己的方式,去度过人生。
15 年编程生涯,资深架构师总结的 7 条经验
我和很多人交流过一个有趣的现象,那就是刚毕业到 30 岁这段时间,会觉得时间过得很慢,总觉得自己还很年轻,但是一旦过了 30 岁,时间就如白驹过隙,一年又一年飞逝而过。
好奇心
刘慈欣在《朝闻道》中描绘过这么一个情节:在古老的非洲大陆上,有个原始人无意中抬头仰望星空,凝视的时间稍微长了一些,超过了外星人设置的阈值,立刻拉响了人类即将产生文明的警报。因为外星人认为,人类已经产生了对宇宙的好奇心,文明的产生,科技的发展不过是一瞬间的事情。
养成计算机的思维方式
养 ...
ANSI C 标准中关于指针赋值的约束条件
先看一段包含警告的代码:
123456void foo(const char **p) { } int main(int argc, char **argv) { foo(argv);}// warning: argument is incompatible with prototype
我们可能认为,由于实参char *s与形参const char *p应该是相容的(标准库中所有的字符串处理函数都是这样写的),那么,为什么实参char **argv与形参const char **p却不能相容呢?
容易混淆的 const回答上述问题前先看一下关键字 const 的用法和实际使用的含义。注意,它不能把变量变成常量!在一个符号前加上 const 限定符只是表示这个符号不能被赋值。
这意味着,我们可以取一个 const 变量的地址,并且可以改变它的值(但最好还是不要这样)。回首往事,const 关键字原先如果命名为 readonly 就好多了,因为 readonly 没有不能改变的意思(外部可以去改变),而 const 只表示自身不会变。c ...
英语鬼才:小笨霖英语笔记学习记录
好棒 & 抱怨It's cool!:Cool 很好用(几乎在什么情况下都能用),还可以说I'm cool with sth,表示我同意啥。类似于Awesome。It’s neat! = It’s righteous!That’s great/wonderful/incredible/awesome/gorgeous/terrific!She is pretty.
Suck:动词。Today is very sucky, everything sucks.I am sick and tired of:I am sick and tired of doing homework.I am terrible/horrible:我很糟糕!
Turn-off:That movie is a turn-off / Sth turns me off!Pissed-off:I’m pissed-off with … = I’m angry with…Shaky:He is shaky / He has a shaky start / He has a bumpy rideDon ...
我是如何高效地使用 MacBook?
Junhao: In which way I can use my Mac efficiently?Friend: Install Windows OS?Junhao: ……
自从 6 年前开始使用 Mac 系统,我就再也没有关过机了。Kidding!不过说真的,关机的次数可能不超过 30 次吧?在大二的时候,我换了一台新的 MacBook,也因此重装了一次系统,当时还不太会用 Time Machine 进行备份,弄得非常麻烦。现在嘛,如果我买新的 MacBook(如果有钱的话),我肯定直接恢复备份了,因为这几年来我的 MacBook 留下了很多配置和使用痕迹,如果让我重新手动配置,我会疯掉的~
直接进入正题,本文从使用心得和应用推荐两个方面做介绍。介绍中难免主观性很强,大家可以选择性地采纳我的建议,或者还是装个 Windows 吧(逃)。
在开始之前,我先贴一下电脑的基本信息:
按键说明:⌘:Command⌃:Control⌥:Option(Alt)⇧:Shift
PS:我的系统是英文的,大家自行翻译啊。
使用心得基本操作我不使用多屏,也基本不会使用触摸板的手势功能,因为 ...
边界计算与不对称边界(Asymmetric Bounds)的设计思想
如果一个数组有 10 个元素,那么这个数组下标的允许取值范围是什么?
对于 Fortran 语言,数组的下标取值缺省从 1 开始,且允许编程者另外指定数组下标的起始值。
对于 Algol 和 Pascal 语言,数组下标没有缺省的起始值,编程者必须明确指定每个数组的上下界。
对于标准的 Basic 语言,声明一个拥有 10 个元素的数组,实际上编译器分配了 11 个元素空间,下标范围从 0 到 10。
在 C 语言中,一个拥有 n 个元素的数组,却不存在下标为 n 的元素,它的元素的下标范围是从 0 到 n - 1。
1234int i, a[10];for (i = 1; i <= 10; ++i) { a[i] = 0;}
这段代码的本意是将数组 a 中所有的元素赋值为 0。但代码中的 a[10] 将数组 a 之后的一个字(word)的内存被设置为 0。如果用来编译这段程序的编译器按照内存地址递减的方式来给变量分配内存,那么内存中数组之后的一个字实际上是分配给了整型变量 i。此时,本来循环计数器 i 的值为 10,a[10] = 0使得 i 的 ...
如何记住 C 语言运算符优先级表?
在开发中,我们很少关注运算符优先级的问题,因为我们可以滥用括号,而且我觉得用括号可以厘清逻辑思路,也方便其他人阅读代码。常见的几种与优先级有关的代码如下:
123if (a && b != 0) { } // Aif (flags & FLAG != 0) { } // Br = high<<4 + low; // C
A 是比较常见的写法,先进行!=运算,再做&&运算。但我一般会写成(a && (b != 0))。
写 B 的本意是先计算flag & FLAG,再将结果与 0 比较。然而,由于!=优先级高于&,上述式子会被解释为(flag & (FLAG != 0)),违背了本意。
因为移位运算符的优先级比加法运算符低,C 中的式子实际被解释为r = high << (4 + low);,会得到意想不到的结果。
用添加括号的方式虽然可以完全避免这类问题,但是表达式中有了太多的括号反而不容易理解(上面这种不算多)。因此,记住 C 语言中运算符 ...
隐式转换:把 C 语言数组转换为指针
在某些情况下,C 语言中的数组会被隐式转换为指针类型,使得程序员对数组的操作更加灵活。在函数参数传递中,隐式转换总是在发生。比如:
12345678void foo1(int *b) { printf("%lu\n", sizeof(b)); }void foo2(int c[]) { printf("%lu\n", sizeof(c)); }int main() { int a[5]; // 5 x 4 = 20 Bytes foo1(a); // -> 8 Bytes foo2(a); // -> 8 Bytes}
在 main 函数中,a 是一个数组。我们可能会认为在 foo2 中 b 的类型是整型数组类型(输出为 20),而实际上,无论是在 foo1 还是 foo2 中,b 的类型均为指向整型的指针类型,即输出的结果均为指针类型的大小(8 个字节)。
实参:Actual Parameter形参:Formal Parameter
参数传递的隐式 ...