今天我妈还在打电话和我说一定要拿毕业证书的事情。
我给她说,有一个人和我是同一年上大学。然后他大一后就休学了,现在在阿里巴巴实习。照这样算下去,等到大部分人大四按部就班又啥也不会地毕业,他估计都已经有两年的工作经验了,这个差距该有多大。
我妈说,那是特例。
我就觉得很好笑的一点是,小孩子还小的时候,家长抢着要让赢在起跑线上,结果长大了,孩子想比别人先走一步,家长却怕的不能行。
还有就是特例这个词,我很烦这个词,因为一般都带有宿命论的意味:某某人技术很厉害,简直是天才,那就是天生的有才华。然后一众人心安理得继续碌碌无为下去,该打游戏打游戏,毕竟 —— 人家是天生的啊,怎么能赶得上呢。
事实是,这些人懒罢了。互联网行业是个很幸运的行业,没有这么多阶层固化,至少是相对传统行业,向上流动的机会大了很多。就这样学校里面还有很多人整天懒得不行,口口声声想做项目然后啥也不学,API 文档都不愿意花时间查,那还指望什么呢。
Virtual Terrain Project
网站地址
Virtual Terrain Project 是一个有关星球在计算机图形上的集合:从地形生成/LOD,大气散射模拟,海洋模拟到过程生成城市布局,应有尽有。
很多东西在我做 Epoch 的时候提供了很多思路,虽然我暂时没能力按照 Paper 直接手动实现一遍。
挑几个有趣的:
Spherical Textures Mapping
http://vterrain.org/Textures/spherical.html
Terrain LOD: Runtime Regular-Grid Approaches
http://vterrain.org/LOD/Implementations/
Sky / Atmospheric Rendering
http://vterrain.org/Atmosphere/
Clouds
http://vterrain.org/Atmosphere/Clouds/
Water
Procedural Building Implementations
Epoch Dev Blog 4.5
Unity 的 编辑器 bug 仍在继续,5.3.4f1 及 5.4.0 beta 确认。
所以我没有对核心的东西继续开发(因为一旦调试 Editor 就崩溃啊摔),而是做两件事情。
一个是写 SceneKit 版本的 Epoch,Github 地址 https://github.com/FinGameWorks/Epoch-Remastered,当然这个东西是不可能很漂亮的,毕竟 SceneKit 本身没有提供很有力的工具,不像 Unity 那么容易做出漂亮的效果,只是作为没法继续 Unity 的无聊的替代品。
一个是给 Unity 的 Epoch 添加了 Cardboard 支持,效果真的非常震撼。
以下是两段在 iPhone 6S 上录制的视频
https://www.youtube.com/watch?v=W-R63Cd05bM
https://www.youtube.com/watch?v=NEUoIn9SnlQ
如果有人想要尝试一番的话,请 Twitter/E-mail 联系我告知我您的 Apple ID 邮箱,我会把你加入 Epoch 的 testflight public beta program。
以上。
2016.3.16

新学期新气象 重修科目要缴费,一个学分八十块,一门课四点五个学分,立马就是几百块。
Apple Developer 账号开始提醒我续期了,这么算下来又是几百块。
手机 Home 按键坏了,换了手机,这么算下来....
穷。以后就是为了省钱,也是要去听听课的....
上周 去看了 疯狂动物城,Zootopia --> Utopia,很明显是有一些寓意的,不同人看的内容和观点也不一样,不细说了。
昨天给 Epoch 加了 Cardboard 支持,感觉很不一样 —— 以往很难表现出太空船的体积,但在 Cardboard 里面转动下头,整个空间感就出来了。
2016.3.13
....我才发现原来 WWDC Scholarship 是不需要写什么特殊的 app 的,之前没注意看 Guidelines,现在才发现原来就是要写一个“个人简介”的软件。
WTF?
最近的情况大致就是,Epoch 在 Unity Editor 里 Crash 的问题仍然严重,从 5.1.3f1 到 5.3.3p3 都试了,没有一个可用,只能说要么是 Unity 的这个问题太隐蔽了,要么就是我的项目文件彻底地 corrupt 了
(顺便 敬请关注推特账号 @Unity 今天崩溃了么,欢迎 DM 投稿)
于是我闲的无聊,开始把 Epoch 的一些东西往 SceneKit 上搬。大致就是 用 libnoise 生成各种图,Height,Normal,Color 一类的,然后做一个可以根据 Height Map 更新 Mesh 的星球,过程中槽点挺多:
- SceneKit 作为一个游戏引擎,竟然基本的运算符重载都不给,比如
SCNVector3 * float都不行 - WWDC 里面一个 Session 工程师说的大致意思就是 Model I/O 和 SceneKit 无缝结合,但是实际情况是可以互相转化,但是基本没用,因为该不支持的还是不支持,比如带相机全屏特效的 MDLCamera 转换成 SCNCamera 就没特效了,PBR 管道的 MDLMaterial 转换成 SCNMaterial 还是只能用非 PBR 的 Light Model
- GLSL to SCNProgram / shaderModifier 这块文档略少,我还本来就不会写 Shader,更是看不懂(摊手
然后除去 这些事情 最近还做了
- 投了腾讯的实习申请
- 睡觉
Create a Cube Sphere in SceneKit
前言
Cube Sphere 是一种奇特的球体,不同于 Geodesic Sphere 和一般 Sphere,更像是一个 Cube 通过某种变换得到的 Sphere。

Cube Sphere 有个好处,就是更适合来做过程生成的星球,因为每个面都可以用 QuadTree 无限细分(详见:https://acko.net/blog/making-worlds-4-the-devils-in-the-details/)
过程
1.新建一个 SCNBox
2.对其修改顶点(vertices)
3.重新计算 Normal
4.刷新 SCNode 的 Geometry
1.新建 SCNBox
SCNBox *SCNBoxToSphereMapping = [SCNBox boxWithWidth:60.0f height:60.0f length:60.0f chamferRadius:0.0f];
SCNBoxToSphereMapping.widthSegmentCount = 16;
SCNBoxToSphereMapping.heightSegmentCount = 16;
SCNBoxToSphereMapping.lengthSegmentCount = 16;
SCNNode *PlanetNode = [SCNNode nodeWithGeometry:SCNBoxToSphereMapping];
[PlanetSceneKitView.scene.rootNode addChildNode:PlanetNode];
[SCNTransaction flush];
- SegmentCount 是 2 的 n 次方 因为后面(当然不是这篇文章)要做 QuadTree
- [SCNTransaction flush]; 是很关键的一步,(详见http://stackoverflow.com/questions/17760275/geometry-from-scenekit-primitives?lq=1 简单说来,就是不 flush 的话,获取的 geometry data 就是 SegmentCount = 1 的默认 SCNBox 数据,而默认的 SCNBox 顶点只有八个,不足以变换成球体)
2.对其修改顶点
// Get the vertex sources
NSArray *vertexSources = [PlanetNode.geometry geometrySourcesForSemantic:SCNGeometrySourceSemanticVertex];
// Get the first source
SCNGeometrySource *vertexSource = vertexSources[0]; // TODO: Parse all the sources
long stride = vertexSource.dataStride; // in bytes
long offset = vertexSource.dataOffset; // in bytes
long componentsPerVector = vertexSource.componentsPerVector;
long bytesPerVector = componentsPerVector * vertexSource.bytesPerComponent;
long vectorCount = (long)vertexSource.vectorCount;
SCNVector3 vertices[vectorCount]; // A new array for vertices
// for each vector, read the bytes
for (long i=0; i<vectorCount; i++)
{
// Assuming that bytes per component is 4 (a float)
// If it was 8 then it would be a double (aka CGFloat)
//xyz 3 componet
float vectorData[componentsPerVector];
// The range of bytes for this vector
NSRange byteRange = NSMakeRange(i*stride + offset, // Start at current stride + offset
bytesPerVector); // and read the lenght of one vector
// Read into the vector data buffer
[vertexSource.data getBytes:&vectorData range:byteRange];
// At this point you can read the data from the float array
//
float x = vectorData[0] / SCNBoxToSphereMapping.width * 2.0f;
float y = vectorData[1] / SCNBoxToSphereMapping.width * 2.0f;
float z = vectorData[2] / SCNBoxToSphereMapping.width * 2.0f;
float SphereX = x*sqrt(1-pow(y,2)/2.0f-pow(z,2)/2.0f + pow(y*z,2)/3.0f) * SCNBoxToSphereMapping.width / 2.0f;
float SphereY = y*sqrt(1-pow(z,2)/2.0f-pow(x,2)/2.0f + pow(x*z,2)/3.0f) * SCNBoxToSphereMapping.width / 2.0f;
float SphereZ = z*sqrt(1-pow(x,2)/2.0f-pow(y,2)/2.0f + pow(y*x,2)/3.0f) * SCNBoxToSphereMapping.width / 2.0f;
// ... Maybe even save it as an SCNVector3 for later use ...
vertices[i] = SCNVector3Make(SphereX, SphereY, SphereZ);
// ... or just log it
NSLog(@"x:%f, y:%f, z:%f", x, y, z);
NSLog(@"SphereX:%f, SphereY:%f, SphereX:%f", SphereX, SphereY, SphereZ);
}
- vertices(顶点)通过 SCNGeometrySource 获取(详见:http://stackoverflow.com/questions/17250501/extracting-vertices-from-scenekit)
- 获取的 vertices 是正方体上的,需要做一个 Mapping 到球体的位置上,就是修改 vertices 的 xyz 值,方法引用自 http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
3.重新计算 Normal
SCNGeometrySource *DeformedGeometrySource = [SCNGeometrySource geometrySourceWithVertices:vertices count:vectorCount];
NSArray *SCNGeometrySourceArray = [NSArray arrayWithObject:DeformedGeometrySource];
NSArray *DeformGeometryElement = [PlanetNode.geometry geometryElements];
SCNGeometry *DeformedGeometry = [SCNGeometry geometryWithSources:SCNGeometrySourceArray elements:DeformGeometryElement];
MDLMesh *DeformedGeometryUsingMDL = [MDLMesh meshWithSCNGeometry:DeformedGeometry];
[DeformedGeometryUsingMDL addNormalsWithAttributeNamed:MDLVertexAttributeNormal creaseThreshold:1.0f];
- 一个自定义 SCNGeometry 需要两样东西,SCNGeometrySource 和 SCNGeometryElements,SCNGeometryElements 在我的理解中就是用来描述顶点之间连接成三角形的顺序。当然实际肯定并非如此简单,只是便于理解我们只是修改了顶点的位置,但连接顺序并没有改变,因此 SCNBox 的 SCNGeometryElements 是可以继续用在新的 Sphere 上的
- MDLMesh 是 Model I/O 的东西,用的时候和 SceneKit 一起记得导入以下头文件:
#import <SceneKit/SceneKit.h>
#import <ModelIO/ModelIO.h>
#import <SceneKit/ModelIO.h>
- MDLMesh 可以计算 Normal 和 Tangent,详见https://developer.apple.com/library/prerelease/ios/documentation/ModelIO/Reference/MDLMesh_Class/index.html
4.刷新 Geometry
DeformedGeometry = [SCNGeometry geometryWithMDLMesh:DeformedGeometryUsingMDL];
PlanetNode.geometry = DeformedGeometry;
记得打开 Debug 的线框预览功能
PlanetSceneKitView.debugOptions = SCNDebugOptionShowWireframe;
效果如下:

Build libnoise on iOS!
libnoise 是一个 Cpp 的噪声库 写了一个简易的教程 怎么把这个东西做成一个可以 iOS 用的 lib
1.Download libnoise from http://libnoise.sourceforge.net/
2.Navigate to libnoisesrc-1.0.0/noise/src, and select files like this:
No makefile, just .h and .cpp files, and don't select win32 folder, you are building in Xcode.

3.On your current Xcode project menu, Select File/New/Target/iOS/Frameworks & Library/Cocoa Touch Static Library, hit next and name it "libnoise" or whatever :-)
4.Now, Drag files you selected in Finder to Xcode like this:

Things to remember to check:
- Copy items if needed
- Create Groups
- Add to targets, just select the new library we have created.
And now our project will looks like this: (I made a group from these files so you will see a top folder named libnoise)

5.Switch your target to libnoise (or whatever you named it when creating library target), we will check something.

6.Navigate to Build Phases/Compile Sources, see if all .cpp files are in there.

7.Jump back the target to your app, make sure Build Phases/Compile Sources have these:

- Xcode's target are on your app
- Target Dependencies have libnoise
- Link Binary With Libraries have libnoise.a
8.Add libc++.tbd in General Tab, or in Build Phases.
9.Create a UIViewController (like NoiseDebuggerViewController), and change NoiseDebuggerViewController.m to NoiseDebuggerViewController.mm
10.In NoiseDebuggerViewController.mm:
-
import "noise.h"
- paste these codes to viewDidLoad():
noise::module::Perlin myModule;
double value = myModule.GetValue(1.25, 0.75, 0.5);
NSLog(@"Value : %f",value);
and Press Run, make sure you have real iDevice plugged in instead of Simulator.
See the Log!
Value : 0.686347
Now you have libnoise on iOS! We are ready to use it for procedural planet generation on iOS!

Epoch Dev Blog 4

👆用来提交崩溃的 Bug Report 都崩溃
Unity 关于 PrepareShadowMaps 还有 Occlusion Culling 崩溃的 bug 在5.3的最新 Patch 版本上仍然存在 让我的进度延缓了不少 因为没办法实时 Editor 预览了 只能自己写一堆东西 试着 build 到 iPhone 上看
所以最近没做什么事情 大致有这几个
1.加了God Ray(Sun Shafts)

2.让游戏根据不同机型调整分辨率 比如 iPad mini 2 这种 A7+大屏Retina 的组合 就运行在 0.75倍率原始分辨率上 然后更老的机型就使用Non-Retina
3.改进了SpeedTree的树木,准备了很多花花草草还有大树

4.研究了下 Noise 图生成 HeightMap 后怎么在 Runtime 生成 Splatmap 留给地面贴图用
5.试着重写树木生成的脚本(但失败了),等脑子清醒并且 Unity 不会那么容易崩溃的时候再试着重写一遍 主要是准备直接从 HeightMap 中 GetPixels 后 把根据 Alpha 值随机出的树木样式数据固化到某个地方 然后做一个 Pool Manager 来管理 Spawn 和 Destroy
多说几句 因为 Unity 工作不正常的原因 最近又看了会 WWDC 学习用了下 ModelIO里面的 Voxel 感觉可以试着用 ModelIO 和 SceneKit 写一个类似的东西(根据噪声的过程星球生成) 如果能写出来的话倒是有个东西可以提交 WWDC 奖学金了
晚安

星球的UV坐标到三维坐标的转换(以及反过来)
a little tool to transform UV to Cartesian (in Unity).
忘了之前从哪看的一个Snippet里面只有三维转UV 后面自己加了两个方法 实现了互相转换 做太空游戏有些用处
2016.3.1
二月底开学 回到了长沙 热得冒汗 感觉都要到了夏天
EPOCH 放在电脑里面总觉得不放心 而且现在两台电脑也不好协作 于是想着用 git 传到服务器上去 但是文件数目太多 即使是用 git shell 也会在 commmit 的时候卡死 于是作罢 改为买 Dropbox 空间 扔到上面自动同步 好处是全自动 坏处是没办法做特定文件的同步规则 以及潜在的被墙风险
生日也过去了 19岁 早晨醒来看到 Twitter 客户端上飘着满屏幕的生日气球 觉得挺好玩 于是多按了几次
Fin GameWorks 算是有了一个小小的网站 http://fingameworks.github.io/ 花了一晚上乱改模板 CSS 做出来的 惨不忍睹 看来有必要学习下前端
最近在看 Vimeo 上面的一些 VFX 视频 比如特效的 breakdown 或者 工作室的 ShowReel 当然也有一些惊人的 SpeedArt 看的人心痒痒 于是跑去申请 Octane Render 的学生证书 但是 OTOY 并不支持国内教育邮箱 对方也一直没有回复