自由,
就是不再
寻求认可。
Freedom means no longer seeking for recognition.
/ [日] 岸见一郎 古贺史健 《被讨厌的勇气》
如果代码能跑,那它就不是 bug,
而是未记录的功能。
If the code runs, it's not a bug.
It's an undocumented feature.
在绝大部分时间,我不是懒,
我只是高效地避免了不必要的工作。
2025.02.10
昼寝后有感
浪费时间与愚蠢的人讲道理,
是更加愚蠢的行为。
位置不同,少言为贵。
三观不合,枉费口舌。
欲成大树,莫于草争。
将军有剑,不斩蚊蝇。
中人以上,可以语上也。
中人以下,不可以语上也。
芒格有言,改变蠢人我从未成功过。
于乙巳年正月二十四午后
永远不该为取悦别人,
而使自己失敬于人。
Man is born free,
And everywhere he is in chains.
这里是我的平日工作和 side projects 代码片段记录.
其实就只是单纯想在 comments 里吐槽罢了 (bushi
2024.09.05
// Code is full of bugs, and so is life.
// /\_/\
// ( o.o )
// 妈的,我是一只可爱的小猫该多好啊,人人都会喜欢我
// 王小兵写此段代码于上海 2024.09.01
#include <stdio.h>
int main(int argc, char **argv)
{
printf("hello my friend, welcome.\n");
return 0;
}
人生,
处处是苦涩的试炼,
短暂的欢愉。
Life is full of bitter trials and short pleasures.
希望我也能从 infj 变成 intj
不想内耗了
2024.09.08
// fwidth 函数是一个 GLSL 内置函数
// 用于计算函数在屏幕空间(或者其他坐标系)中 x 和 y 方向的变化率
// 也就是函数沿着 x 和 y 方向的梯度
// 对于输入坐标 p,fwidth(p)的计算公式如下
// fwidth(p) = abs(dFdx(p)) + abs(dFdy(p))
// abs函数表示取绝对值
// dFdx(p) 表示函数在 x 轴上的偏导数
// dFdy(p) 表示函数在 y 轴上的偏导数
// 下面是一个示例片元着色器
// 使用fwidth函数计算表面法线的偏导数,结果用于计算环境光的强度
// 来自 GLSL ES Shader 参考文档 http://www.bimant.com/docs/glsl-es/fwidth/
// 老夫我啊,一独立项目会用 fwdith 函数来实现 sdf 来做边缘检测和抗锯齿
uniform vec3 ambientColor;
uniform vec3 lightColor;
uniform vec3 lightDir;
varying vec3 vNormal;
void main()
{
vec3 n = normalize(vNormal);
vec3 l = normalize(lightDir);
float NdotL = dot(n, l);
float intensity = max(0.0, NdotL);
// 计算法线的偏导数
vec2 derivative = fwidth(gl_FragCoord.xy);
// 加权环境光颜色
vec3 ambient = ambientColor * (1.0 - intensity * intensity);
vec3 color = ambient + intensity * lightColor;
// 应用边缘柔化
color *= exp(-(derivative.x + derivative.y));
gl_FragColor = vec4(color, 1.0);
}
临江仙 - 绝影
加班调试无空调,
八戈解完心难解。
函数堆栈似深海。
错报如血若残阳,
回溯难寻源,
算法乱成线,
无尽循环乱引用,
编程人难眠。
// URP 自定义着色器的 Shadow Receieve
// 自定义 shaderlab 添加 GPU instancing 支持需要在 pass 里添加
// #pragma multi_compile_instancing
// 如果大量绘制的网格都一致,那么建议用 instancing
// 如果用上 instancing,那么你的其他 pass 最好都同步添加上 instancing 的支持
// 如果网格不一致,但是相同 shader,且 shader 变体一致,那么建议用 SRP Batcher
// 支持 SRP Batcher 主要是将 uniform 变量都划分到对应的 CBuffer
// 这篇文章讲的不错 https://blog.csdn.net/linjf520/article/details/120757669
// 有些时候,老夫我真的尽力了
Shader "Custom/ShadowReceieve"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1, 1, 1, 1)
[Toggle] _ALPHATEST ("Alpha Test On", Float) = 0
}
SubShader {
Tags { "RenderType"="Opaque" }
LOD 100
HLSLINCLUDE
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
CBUFFER_START(UnityPerMaterial)
half4 _Color;
float4 _MainTex_ST;
CBUFFER_END
ENDHLSL
Pass
{
HLSLPROGRAM
#pragma multi_compile _ _MAIN_LIGHT_SHADOWS
#pragma multi_compile _ _SHADOWS_SOFT
#pragma multi_compile_instancing
#pragma shader_feature _ALPHATEST_ON
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float4 vertex : SV_POSITION;
float2 uv : TEXCOORD0;
float4 shadowCoord : TEXCOORD1;
float3 positionWS : TEXCOORD2;
};
sampler2D _MainTex;
v2f vert (appdata v)
{
v2f o;
o.positionWS = TransformObjectToWorld(v.vertex.xyz);
o.vertex = TransformWorldToHClip(o.positionWS);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.shadowCoord = TransformWorldToShadowCoord(o.positionWS);
return o;
}
half4 frag(v2f i) : SV_Target
{
half3 ambient = half3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w);
half shadow = MainLightRealtimeShadow(i.shadowCoord);
half4 col = tex2D(_MainTex, i.uv);
half4 finalCol = col * _Color;
finalCol.rgb = lerp(finalCol.rgb * ambient.rgb, finalCol.rgb, shadow);
return finalCol;
}
ENDHLSL
}
}
}
人一旦丧失专注的能力,
稍微动一动,就觉得快累死了。
所以,千万别堕落。
So, don't fall into depravity.
2024.09.05
// 自定义着色器要想 SRP Batcher compatible
// 材质自定义的属性要放在 UnityPerMaterial 的 CBuffer 中
// 逐材质的属性,需要定义在 cbuffer 中,才能在材质切换时直接绑定显存中的 cbuffer
// 老夫是这屎山项目唯一的光,还会去考虑性能问题
CBUFFER_START(UnityPerMaterial)
float4 _BaseMap_ST;
half4 _BaseColor;
half4 _SpecColor;
half4 _EmissionColor;
half _Cutoff;
half _Surface;
CBUFFER_END
// 公司的这脑洞突破天灵盖的项目
// 什么样的奇葩需求都能遇得到,比如这 Cesium 卫星图的 textures 导出
// 内存里创建的贴图无法修改 import settings isReadable
// 要想读取 unreadable texture2d 可以先 blit 到一张 rt 里
// 草,是一种植物,狗是真的狗
private Texture2D ReadUnreadableTexture(Texture2D texture)
{
RenderTexture tmp = RenderTexture.GetTemporary(
texture.width,
texture.height,
0,
RenderTextureFormat.Default,
RenderTextureReadWrite.Linear);
Graphics.Blit(texture, tmp);
RenderTexture previous = RenderTexture.active;
RenderTexture.active = tmp;
Texture2D retTexture2D = new Texture2D(texture.width, texture.height);
retTexture2D.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0);
retTexture2D.Apply();
RenderTexture.active = previous;
RenderTexture.ReleaseTemporary(tmp);
return retTexture2D;
}
// 使用重心坐标在三角形内随机点
// 点的稀疏程度和三角形面积成正比
// 这段代码是为了在草地上随机种树
// 输入是草地 mesh 的 triangles 对应的顶点序列
// 妈的,没错,反正都是些 2b 需求
List<Vector3> RandomPointsInTriangle(Vector3 v1, Vector3 v2, Vector3 v3, float density)
{
var points = new List<Vector3>();
var area = Vector3.Cross(v2 - v1, v3 - v1).magnitude * 0.5f;
var pointCount = Mathf.CeilToInt(area * density);
for (var i = 0; i < pointCount; ++i)
{
var randomPoint = GenerateRandomPointInTriangle(v1, v2, v3);
points.Add(randomPoint);
}
return points;
}
Vector3 GenerateRandomPointInTriangle(Vector3 v1, Vector3 v2, Vector3 v3)
{
var r1 = Random.value;
var r2 = Random.value;
if (r1 + r2 > 1f)
{
r1 = 1f - r1;
r2 = 1f - r2;
}
return v1 + r1 * (v2 - v1) + r2 * (v3 - v1);
}
记住,
摆烂太久是会被收走天赋的。