Blog logoJustZht

Blog logo

Unity 后期处理保证背景颜色

 • 

Unity 后期处理中如果用了 Color Grading 之类的效果器同时要保证相机背景颜色不变(比如 Unity 作为一个 View 挂在手机客户端中),就要费些功夫,因为使用多相机(一个背景相机+一个实物渲染相机)仍然是无法保证相机背景不被 depth 较高的相机上的效果器处理的,因此写了个根据相机渲染深度信息来填充特定颜色,挂在 Color Grading 后面即可。

namespace FinGameWorks.Scripts.PostProcess  
{
    using System;
    using UnityEngine;

    [RequireComponent(typeof(Camera))]
    [ExecuteInEditMode]
    public class MaskedFirstPass : MonoBehaviour
    {
        [Range(0f, 3f)] public float depthLevel = 0.5f;
        public Color backgroundColor = Color.white;

        public Shader _shader;

        private Shader shader
        {
            get { return _shader != null ? _shader : (_shader = Shader.Find("MaskedFirstPassShader")); }
        }

        private Material _material;

        private Material material
        {
            get
            {
                if (_material == null)
                {
                    _material = new Material(shader);
                    _material.hideFlags = HideFlags.HideAndDontSave;
                }

                return _material;
            }
        }

        private void Start()
        {
            if (!SystemInfo.supportsImageEffects)
            {
                print("System doesn't support image effects");
                enabled = false;
                return;
            }

            if (shader == null || !shader.isSupported)
            {
                enabled = false;
                print("Shader " + shader.name + " is not supported");
                return;
            }

            GetComponent<Camera>().depthTextureMode = DepthTextureMode.Depth;
        }

        private void OnDisable()
        {
            if (_material != null)
                DestroyImmediate(_material);
        }

        private void OnRenderImage(RenderTexture src, RenderTexture dest)
        {
            if (shader != null)
            {
                material.SetFloat("_DepthLevel", depthLevel);
                material.SetColor("_BGColor",backgroundColor);
                Graphics.Blit(src, dest, material);
            }
            else
            {
                Graphics.Blit(src, dest);
            }
        }
    }
}
Shader "MaskedFirstPassShader"  
{
   Properties
     {
         _BGColor ("Background Color", COLOR) = (1.0,1.0,1.0,1.0)
         _DepthLevel ("Depth Level", Range(1, 3)) = 1
         _MainTex ("Source", 2D) = "white" {}
     }
     SubShader
     {
         Pass
         {
             CGPROGRAM

             #pragma vertex vert
             #pragma fragment frag
             #include "UnityCG.cginc"

             uniform sampler2D _CameraDepthTexture;
             uniform half4 _MainTex_TexelSize;
             uniform float4 _BGColor;
             uniform fixed _DepthLevel;

             struct input
             {
                 float4 pos : POSITION;
                 half2 uv : TEXCOORD0;
             };

             struct output
             {
                 float4 pos : SV_POSITION;
                 half2 uv : TEXCOORD0;
             };

               output vert(input i)
             {
                 output o;
                 o.pos = UnityObjectToClipPos(i.pos);
                 o.uv = MultiplyUV(UNITY_MATRIX_TEXTURE0, i.uv);
                 #if UNITY_UV_STARTS_AT_TOP
                 if (_MainTex_TexelSize.y < 0)
                         o.uv.y = 1 - o.uv.y;
                 #endif

                 return o;
             }

              sampler2D _MainTex;
                float4 _MainTex_ST;

             fixed4 frag(output o) : COLOR
             {
                 float depth = UNITY_SAMPLE_DEPTH(tex2D(_CameraDepthTexture, o.uv));
                 depth = pow(Linear01Depth(depth), _DepthLevel);
                 if (depth < 0.5)
                 {
                                float4 color = tex2D(_MainTex, 
                       UnityStereoScreenSpaceUVAdjust(
                       o.uv, _MainTex_ST));    
                       return color;
                 }
                  else
                 {
                    return     _BGColor;
                 }
             }
             ENDCG
         }
     } 
}

Unity 项目打包 Framework 方式嵌入 UnityGetGLView 到 iOS 工程 (1)

 • 

距离上次写这个话题快有一年了,上次也是做外包的时候有嵌入 Unity View 到 iOS 工程的需求。这次为了双方的便捷,参考 unity-ios-framework 采用了打包整个 Unity 为静态 framework 的方法,这种方法对甲方非常友好,一次配置,以后每次只需更新 framework 和 Data 即可,而自己需要多做些配置,为了把这块也自动化,写了个 Build Script。

#!/usr/bin/env bash
if [[ -s "$HOME/.rvm/scripts/rvm" ]] ; then  
source "$HOME/.rvm/scripts/rvm"  
elif [[ -s "/usr/local/rvm/scripts/rvm" ]] ; then  
source "/usr/local/rvm/scripts/rvm"  
else  
printf "ERROR: An RVM installation was not found.\n"  
exit 128  
fi

# rvm default
# ruby -v
# rvm use system
# ruby -v

echo $SHELL  
which ruby  
set -e

export LANG=en_US.UTF-8  
export LANGUAGE=en_US.UTF-8  
export LC_ALL=en_US.UTF-8

if ! which ruby > /dev/null; then  
echo "error: ruby is not installed."  
exit 1  
fi

if ! which xcodeproj > /dev/null; then  
echo "error: xcodeproj 没有安装,请 [sudo] gem install xcodeproj [--user-install],如果通过 rvm 使用了其他版本 ruby 请先 rvm use system 再 install"  
exit 1  
fi

chmod u+x $SRCROOT/UnityOutFramework/UnityPreBuild.rb  
cd $SRCROOT/UnityOutFramework  
ruby UnityPreBuild.rb  

在 $SRCROOT 下面新建文件夹 UnityOutFramework,放置 Info.plist 和 UnityPreBuild.rb,内容如下

require 'xcodeproj'  
include Xcodeproj::Project::Object

puts "检查 Unity 项目所需设定"  
project_path = '../Unity-iPhone.xcodeproj'  
project = Xcodeproj::Project.open(project_path)

deleted_targets, preserved_targets = project.targets.partition{ |target| target.name == 'UnityOutFramework'}

puts 'Deleted : '  
puts deleted_targets  
puts 'Preserved : '  
puts preserved_targets

project.targets.replace(preserved_targets)

puts 'Added : '  
target = project.new_target(:framework,'UnityOutFramework',:ios)  
puts target

puts '-------- Config Names --------'  
target.build_configurations.each { |config|  
    puts config.name

    config.build_settings['HEADER_SEARCH_PATHS'] = '$(inherited) $(SRCROOT)/Classes $(SRCROOT) $(SRCROOT)/Classes/Native $(SRCROOT)/Libraries/bdwgc/include $(SRCROOT)/Libraries/libil2cpp/include'
    config.build_settings['LIBRARY_SEARCH_PATHS'] = '$(inherited) $(SRCROOT) $(SRCROOT)/Libraries'
    config.build_settings['GCC_PRECOMPILE_PREFIX_HEADER'] = 'YES'
    config.build_settings['GCC_PREFIX_HEADER'] = 'Classes/Prefix.pch'
    config.build_settings['ALWAYS_SEARCH_USER_PATHS'] = 'NO'
    config.build_settings['ARCHS'] = '$(ARCHS_STANDARD)'
    config.build_settings['INFOPLIST_FILE'] = 'UnityOutFramework/Info.plist' 
    config.build_settings['CODE_SIGN_STYLE'] = 'Automatic'
    config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = 'com.JustZht.UnityOutFramework'
    config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '8.0'
    config.build_settings['ENABLE_BITCODE'] = 'YES'
    config.build_settings['MACH_O_TYPE'] = 'staticlib'
    config.build_settings['DEFINES_MODULE'] = 'YES'
    config.build_settings['GCC_C_LANGUAGE_STANDARD'] = 'gnu11'
    config.build_settings['GCC_ENABLE_CPP_EXCEPTIONS'] = 'YES'
    config.build_settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'gnu++14'
    config.build_settings['CLANG_CXX_LIBRARY'] = 'libc++'
    config.build_settings['GCC_ENABLE_CPP_EXCEPTIONS'] = 'YES'
    config.build_settings['CLANG_ENABLE_MODULES'] = 'YES'
    config.build_settings['CLANG_ENABLE_OBJC_ARC'] = 'YES'
    config.build_settings['CLANG_ENABLE_OBJC_WEAK'] = 'YES'
    config.build_settings['CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING'] = 'YES'
    config.build_settings['CLANG_WARN__DUPLICATE_METHOD_MATCH'] = 'YES'
    config.build_settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'YES'
    config.build_settings['GCC_THUMB_SUPPORT'] = 'NO'
    config.build_settings['GCC_USE_INDIRECT_FUNCTION_CALLS'] = 'NO'
    config.build_settings['MTL_ENABLE_DEBUG_INFO'] = 'NO'
    config.build_settings['UNITY_SCRIPTING_BACKEND'] = 'il2cpp'

    if  (config.build_settings['OTHER_CFLAGS'] == nil)
        config.build_settings['OTHER_CFLAGS'] = '$(inherited)'
    end

    if !config.build_settings['OTHER_CFLAGS'].include? "$(inherited)"
        config.build_settings['OTHER_CFLAGS'] << ' $(inherited) '
    end

    if !config.build_settings['OTHER_CFLAGS'].include? "-DRUNTIME_IL2CPP=1"
        config.build_settings['OTHER_CFLAGS'] << ' -DRUNTIME_IL2CPP=1'
    end

    # LINKER FLAGS
    if  (config.build_settings['OTHER_LDFLAGS'] == nil)
        config.build_settings['OTHER_LDFLAGS'] = '$(inherited)'
    end

    if !config.build_settings['OTHER_LDFLAGS'].include? "$(inherited)"
        config.build_settings['OTHER_LDFLAGS'] << ' $(inherited) '
    end


    if  !config.build_settings['OTHER_LDFLAGS'].include? "CoreMotion"
        config.build_settings['OTHER_LDFLAGS'] << ' -weak_framework'
        config.build_settings['OTHER_LDFLAGS'] << ' CoreMotion'
    end

    if  !config.build_settings['OTHER_LDFLAGS'].include? "-weak-lSystem"
        config.build_settings['OTHER_LDFLAGS'] << ' -weak-lSystem'
    end

    # Configs

    if config.name == 'Debug'

        if !config.build_settings['OTHER_CFLAGS'].include? "-fembed-bitcode-marker"
            config.build_settings['OTHER_CFLAGS'] << ' -fembed-bitcode-marker'
        end

    elsif config.name == 'Release' || config.name == 'ReleaseForProfiling' || config.name == 'ReleaseForRunning'

        if !config.build_settings['OTHER_CFLAGS'].include? "-fembed-bitcode"
            config.build_settings['OTHER_CFLAGS'] << ' -fembed-bitcode'
        end
    end
}

puts '-------- Build Pharses Names --------'  
target.build_phases.each { |build_phase|  
    puts build_phase.isa
    if (build_phase.isa == 'PBXSourcesBuildPhase')
            build_phase.clear 
    end
}

puts '-------- Objects Names --------'  
project.objects.each { |object|  
    puts object.display_name + ' TYPE: ' + object.isa
}

accepted_compile_sources_formats = [".cpp", ".mm", ".m"]  
unaccepted_compile_sources_file_names = ['Unity_iPhone_Tests.m','RegisterMonoModules.cpp','main.mm']

accepted_header_formats = [".h"]  
accepted_public_header_file_names = ["LifeCycleListener.h",'Preprocessor.h','RegisterFeatures.h','RenderPluginDelegate.h','UnityAppController.h','UnityForwardDecls.h','UnityInterface.h','UnityRendering.h','UnityViewControllerBase.h','UnityViewControllerBase+iOS.h']  
unaccepted_header_file_names = ['RegisterMonoModules.h']

accepted_lib_formats = [".a"]

puts '-------- Add Files --------'  
project.objects.each { |object| 

    if object.isa == 'PBXBuildFile'

        if object.file_ref.path != nil && File.extname(object.file_ref.path) != nil
            ext = File.extname(object.file_ref.path)
            fullname = File.basename(object.file_ref.path)

            if !unaccepted_compile_sources_file_names.include?(fullname) && accepted_compile_sources_formats.include?(ext)
                target.source_build_phase.add_file_reference(object.file_ref,true)
                puts 'ADDED TO COMIPLE SOURCES -> ' + object.file_ref.path
            end

            if !unaccepted_header_file_names.include?(fullname) && accepted_header_formats.include?(ext)
                is_public = false
                file = target.headers_build_phase.add_file_reference(object.file_ref,true)
                if accepted_public_header_file_names.include?(fullname)
                    file.settings = { 'ATTRIBUTES' => ['Public']}
                end
                puts 'ADDED TO HEADERS -> ' + object.file_ref.path + ' via PBXBuildFile PUBLIC -> ' + (is_public ? '1' : '0')
            end

        end

    elsif object.isa == 'PBXFileReference'

        if object.path != nil && File.extname(object.path) != nil
            ext = File.extname(object.path)
            fullname = File.basename(object.path)

            if !unaccepted_compile_sources_file_names.include?(fullname) && accepted_compile_sources_formats.include?(ext)
                target.source_build_phase.add_file_reference(object,true)
                puts 'ADDED TO COMIPLE SOURCES -> ' + object.path
            end

            if !unaccepted_header_file_names.include?(fullname) && accepted_header_formats.include?(ext)
                target.headers_build_phase.add_file_reference(object,true)
                puts 'ADDED TO HEADERS -> ' + object.path + ' via PBXFileReference'
            end

            if accepted_lib_formats.include?(ext)
                target.frameworks_build_phase.add_file_reference(object,true)
                puts 'ADDED TO FRAMEWORKS -> ' + object.path
            end
        end

    end
}

deleted_phases, preserved_phases = target.build_phases.partition{ |phase| phase.isa == 'PBXShellScriptBuildPhase' && phase.name == 'Replace Headers'}  
target.build_phases.replace(preserved_phases)  
uuid = Digest::MD5.hexdigest('Replace Headers').upcase[0,24]  
run_script_phase = PBXShellScriptBuildPhase.new(project, uuid)  
run_script_phase.initialize_defaults  
run_script_phase.name = 'Replace Headers'  
run_script_phase.shell_script = 'inputDirectory=$PROJECT_DIR/${TARGET_NAME}/FlatPathHeaders  
outputDirectory=${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET_NAME}.framework/Headers

echo "in $inputDirectory"  
echo "out $outputDirectory"

if [ ! -d "$outputDirectory" ]; then  
echo "no out path,and create: $outputDirectory"  
mkdir $outputDirectory  
fi

cp -R $inputDirectory/. $outputDirectory/'  
target.build_phases.insert(target.build_phases.length, run_script_phase)

# names = [ 'Foundation', 'CoreFoundation', 'MediaPlayer', 'CoreMotion', 'MediaToolBox', 'AudioToolbox', 'AVFoundation', 'CoreMedia', 'CoreLocation' ]
# names.each do |name|
#     target.add_system_framework(name)
# end

project.save

使用时将 Run Script 添加到导出的 Xcode 项目默认 target 中(其实这块也可以直接在 Unity 内通过 PBXProject 自动添加到 target 里去),然后直接 Run。项目并不会 Run 而是会 Cancel,因为 ruby 脚本在最后保存了工程。然后就会出现 UnityOutFramework,Build 即可。

2018.6.25

 • 

朋友圈里面不停有人发毕业典礼和离校,看得我总算是有点伤感的感觉了,然而我还有一堆学校的事情要处理,去检查了次课设试验被自以为是的老师气到不行,再一回想起之前被学校各种刁难,遂又回到了对毕业没有感觉的状态。

我真正关心的是由于课程和考试的安排在第一期毕业证发放之后,估计要拖到七月初我才能拿到毕业证了。我原本打算把 WWDC 之旅当做毕业旅行,这样即使我七月才能拿到毕业证也算是已经提前放松了一段时间,如此七月二十二立刻入职腾讯也不算什么对我而言太紧迫之事。但是 WWDC 由于签证被我错过,我一下子就感觉不爽了,这样刚毕业就去工作,让我想起了前一年在百度时不太好的感觉,而我本性难改,一旦觉得自己不自由就会不停折腾,直到我自己满意为止。

刚好上次 Hackathon 有一个推荐 MSRA 的机会,虽然应该是推不进去,但是给我了一个启发就是我还是能再往上争取一把的。因此我又动了心思想再看看机会,而且如果找到厉害的新东家还能九月份入职就更好了。我和同学说了这个事情,他们笑:你都拿腾讯当保底了。我说是,我现在是拿腾讯当保底了,但是一年前这个时候我可没这个胆量,这种事情自然是走一步看一步。

然后今天去寝室拿琐碎的东西,比如活动衫,原本是毕业典礼要穿的,结果我压根就没参加毕业典礼,因此一直放在班长那里;比如优秀论文证书,也是班长帮我拿的;比如一个厚册子,貌似是给同学之间写寄语和放照片用的,我拿到之后哭笑不得,这东西看起来情真意切但放到全是手机的现在怕是留着吃灰。

不管怎样,我的大学如果考过重修就应该还差一两周就结束了。
回想一下这四年,第一年还没什么具体的头绪,后面就一直在尽力地当一个了不起的盖茨比。
我爸妈没上过大学,对于现在的大学是什么样子什么做派也并不清楚,因此在我大学中和制度摩擦的时候也没有能力提供相应的指导,比如很多和学校硬碰硬的事情其实找个人就好办很多,但是我不知道,我爸妈也没有解决的思路,因此也是我慢慢上了四年才领悟到一些事情,如果早明白一些事情,也许我会保持自己在自己喜欢做的事情上的投入,同时在学校能够做出一个好学生的样子,甚至被当做学生学和做皆优的代表,少却很多麻烦,多了很多便利。因为没上过大学,我爸妈对我完成学业有一种执念,因此在我想要退学的时候反弹比较激烈,我也答应了至少要保证大学毕业,因此好歹和学校保持着联系,偶尔在学校露一次面,以完成这个保证。临近毕业和我爸妈说后面的发展,爸妈又说要考个研究生吧。我当然是有研究生的打算的,毕竟自己也没在这个学校里学到什么真的 CS 的东西,一个是学校没教,一个是教了也厌学,那自然有很多不会的内容,需要后面上学去补,而我的计划就是工作一两年,好歹逃离学校这种地方喘息一会,等到本科 GPA 对我的影响降低之后就去申请出国看看。虽然我研究生计划是这样的,但我和爸妈说的时候总会说不确定,因为我不想到时候再保证一次了,本来上学这种事情我都快有阴影了。
爸妈的这些反应我倒也明白,也没有觉得拖累,毕竟能定义拖累的前提是能够放下,而显然我之前也说过断绝关系这种事情我是做不来的,更何况虽然看起来最近半年全靠自己挣的钱过活没花过爸妈的,但是之前也说了这种看似买买买的自由的假象是建立在有爸妈的后备基础上的,目前简单的财务状况也不是能和真正成人前瞻后顾的财务计划能比的。因此我大学中也尽力缓和家人的关系,让家人理解我看似逃学一样的事情的动机,至少不再拦着我干活,然后我再想办法找时间去改变他们。
我越是想办法往上走越是想让我的父母理解我并且帮助我,特别是最近一次 WWDC 签证的事情之后,因为我和父母都觉得如果很早之前一家人一起办十年旅游签证就不会有我现在一个人被审查的事情了,而这种事情说实话是眼界的问题,但家长的态度和眼界这是个看运气的事情,自然会有家庭出身比我所在的境遇更糟糕,比如初中的那些同学们,而我也没什么可以抱怨的,即使最后爸妈不愿意改变,那也是他们自己的事情,但我至少要去尝试罢了。

大学最后一次课程设计检查

 • 

写了个项目去检查
我:老师我大四的,请问能不能这节课检查下,然后早点登记分数
老师:我是不可能给你一个人登记分数的,你要等大家都结束才行
我:那老师能不能先提前检查下,毕竟我也大四了
老师:不行,大四唯一的例外是有几个外语院的同学要回家了所以提前检查
我:但是昨天毕业典礼后大家都可以回家了,所以老师我也是想着能不能早点结束
老师:那你检查最多只能及格
我:好的好的
(老师翻点名册没找到我)
老师:你不是大四的吗,我这里只有一五级一六级的,你是怎么进来的?
(我同学帮我指了下我在花名册里面的位置)
老师看了下花名册里面的签到表:看你三次课里面两次都没来,你可以不用检查了(意指我可以挂科了)
我:老师我第一次和您在 QQ 上请假了,当时我和您说要去办签证参加 WWDC,第二次就是今天您刚才下午点名的时候我在改代码。
老师:行吧你给我看看你的东西
(看完我的项目)
老师:你刚才我只准备给你个及格,但是我听你讲了之后可以给你个中等
我:谢谢老师

大学其他对话系列:辅导员 | 软件外包赛校内答辩经过

2018.6.13

 • 

昨天签证 issue 了。还没寄回来,不过估计是一年签。虽然 WWDC 都结束了,不过考虑着今年还是要去美国一趟(比如找 Cee 玩),就是不知今年内还有没有大片的空闲时间。
答辩论文申请了校级本科优秀论文,最后拿了二等。总共有一等,二等,优秀三个等级,学院内三个等级加起来有 20 人。也不清楚具体是什么水平,反正我妈应该会高兴点,毕竟我大学四年没怎么给她拿过学校内部的荣誉,好不容易临毕业了有个学校认证的东西。
还有三门考试,目前事情一堆还没复习,也不轻松。不过因为学校人事带来的关于体测的乱七八糟的事情总算是过去了。
Golf GO (Scholarship Edition) 和由 Lonely Planet 改名后重新提交的 Epoch Core 都上架了。

2018.6.7

 • 

我的签证果然没有在武汉飞旧金山的航班飞走前结束审查。我发了十几封催签邮件,给 DOS 打了几次电话,甚至想着如果 WWDC 开幕式前一天签证下来了我就直接定北京到圣何塞的机票还能赶得上发布会,结果也没发生。
所以这就是我大学的第一个 WWDC 奖学金,也是最后一个,也是压根就没去成的一个。有点无奈,但也没办法。去不成自然会错过很多机会,少面基很多人,但是这个世界又不是绕着我转的,而且我还有其他事情不得不忙。
五月份筹备 WWDC 的行程时发现和毕设答辩撞了车,结果导师人很好让我可以提前答辩,因此提前准备了很多东西,结果签证没有如期发下来,最后我还是跟着大家一起正常答辩,也就是昨天下午。对别人来说答辩完就是大学结束了,对于我来说还有三门要考的试。啊不管怎么样算是告一段落,等真正毕业后估计还要写四年的所见,暂先不表。


五月底又打了把 hackathon,湖南大学办的华中 HHHackathon。和李霖及李霖的女朋友组队,基于 CoreML 和 ARKit 弄了个简单的三维维基百科,最后拿了第二和京东单项奖。
作为一个好歹在国内 hackathon 组队拿过六七次前三名的半职业打手(误),我觉得还是有点资格评判下湖大这次的组织和流程的。总而言之,湖大是把 hackathon 当成校赛来办。
校赛意味着两件事:第一是学校牵扯其中,自然会有很多学校的特殊规定,如不让人擅自离场吃饭(只能吃会场内的盒饭),不让人回宿舍睡觉,当然这些是出于学校对安全的一些硬性要求,情理上也能理解,但如果外加场地条件很差就是个灾难了,本身第一次办 hackathon 的组织都会对网络估计不足,这次也一样,外加晚上强制让睡会场,还好我们队不管规则纪律晚上照样回自己家休息了(毕竟不是湖大的学生,也处分不到我们头上),不然估计要和其他人一样在会场喂蚊子。这第二呢,就是校赛自然有很多说不清道不明的东西,比如有的队伍提前一周就开始开发了,主持人还说既然题目有公布,这种事情自然是允许的;比如有的队伍自带湖大的带队老师;比如大部分队伍的实现程度都没有到代码的程度,然后看到了熟悉的墨刀流(做个原型说自己有成品之流);比如赛后的官方新闻稿全篇都在说第一和第三名两个湖大的项目,第二名反正不是湖大的一笔带过,这对于学校宣传来说自然是无可厚非的,但既然是 hackathon 基本的平台中立还是要有的,学校可以单独发新闻稿,但是把参赛的包括武汉和南京远道而来的大家都裹挟到一篇只提到湖大自己的文章里面一笔带过就有些让我不太爽了,不过考虑到这个比赛也许就是按照校内比赛来办的,倒也是能说得通。只是我不太喜欢吧,毕竟这次比赛可是套着 hackathon 的头衔,然而只学到了 24 小时现场编程这个规定,而没学到真正让 hackathon 成为 hackathon 的东西,总让我们这些人感觉是到贵校“万国来朝”的,仅此而已
写完觉得还是说的有点刻薄了,毕竟话说吃别人的嘴软,但事实也就我描述的这样,外加我的确很反感校赛,这个不满的情绪怕是从大一就开始积攒了。我讨厌各种华而不实的校赛,讨厌各种吹上天的 PPT 和 BP,讨厌拿墨刀原型当成品,讨厌校内带队老师和评委之间说不清的照顾,讨厌纯学生组队没有带队老师的无力感,就这样


我把 Cetacea 开源了。实在是没精力折腾下去了,之前选用的 Bundle Based NSDocument,正则做 MD 解析外加 iCloud 的方案现在看起来有点蠢,不如等后面从头写一个基于 CMark,不管文件同步而是纯编辑器的小项目,再慢慢拓展,不然对于这种较大的 macOS 项目我现在仍然没有足够的能力去理清头绪,更别提两年前开始这个项目的时候了。

然后 Lonely Planet 被出版社发邮件说商标侵权后我自己 take down 了相关的各种东西,包括上架了的软件和相关视频,这几天估计会以 Epoch Core 的名字重新上线,内容还是一年前的 Epoch Core,而最近在 Epoch 上取得的进展估计要到七月底才有时间往 Core 里面整理了。

接下来就是 Skyline。因为毕设和之前一个一言难进的外包,Skyline 推迟了很多次更新,最近会关注下了。基于 Unity 2018.1 轻量级渲染管道和 Marklight 实现 UI 的版本估计会在六月底发包,然后等 Unity 出纯 ECS 的超小引擎包(参见 Unity at GDC - ECS for Small Things)的时候我再迁移上去,但是 Mapbox 的 C# SDK 还不知道会什么时候迁移到基于 ECS 的架构上去(说到这个他们公司之前和我接触了下但是我貌似忘了回邮件了 -。-),因此要这么做的话我还要自己写一个基本的请求层实现,那么要做的工作和我基于 LibGDX 重写的 Skyline GO 已经差不多了。总而言之,一个因为一开始脑抽用了 Unity + Android 的混合架构所以我目前还是不太想碰的老 code base,和目前还是烂摊子的重写计划,哪一个都不是个容易的事情。但我总觉得不能赚了一笔就跑路,虽然我事实上估计已经是了(


买了个 iPod Classic 6th gen,塞了很多音乐进去。最近听了 Soulection Radio Tour - Live at the El Rey Soulection Radio Show #343Coral City | Vol. 1Road TripBack to Life,此外看了一个有趣的视频 Evolution Simulator

美签面试经过

 • 

(之前我的 MBP 15 被我打翻一杯奶茶泼上去了,因此陈叔陪着我先带 MBP 去了 Apple Store 修,然后吃了饭下午就去美签的地点。)

排了一会队,录了指纹,然后被分到一个女面试官前面。我前面的一位女性在面试的时候靠的离玻璃特别近,当时还纳闷为什么这么近,后来才明白 —— 这位面试官声音特别小,不靠近根本听不见。

面试官:你好
我:您好
面试官:请问您来美国是做什么
我:去参加苹果邀请的 WWDC 会议
面试官:文件出示一下
(面试官收下 visa letter 看了会,然后继续看终端屏幕 )
面试官:ZHANG PENG 是谁?
我:我的同行人
面试官:您准备呆几天?
(我没听清)
我:Pardon?
(面试官用英语重复了下)
我:About 7 or 8 days
面试官:您的行程单 (我只给了行程单,但是忘了给机票订单了。面试官看了下行程单,和 visa letter 一起收了起来)
面试官:您的费用有谁来负担?
我:机票是由我父亲提供的,门票和住宿由苹果公司提供。
面试官:你和 CENG JI SHAN 什么关系?
(我:??????)
我:抱歉,能再说一遍吗?
面试官:你和 CE JI SHAN 什么关系?
(如此总共反复了两次中文,一次英文,说英文的时候我才明白面试官说的是我父亲,但是我父亲明明姓 ZHENG,后面的名也读得差强人意)
我:(英文)他是我父亲
面试官:他住在美国吗?
我:不,他住在中国安徽省
面试官:好的,我需要临时离开下 (面试官离开工位差不多两分钟,然后带了一位白色制服男性过来,两个人在聊着我的材料,然后翻看我的护照(我是白本),大约有三分钟)
(面试官将我的行程单,visa letter,护照用橡皮筋捆在一起收在了她那边,然后拿了张黄色纸在上面画了个叉)
面试官:您好,这是您的结果,请稍等三到四天,谢谢!
然后我就拿到了一张 (g)221 行政审查单。
总觉得自己的表现有些窝囊,以及自己的说话习惯太简略了,这种情况下反而不利于自己。不过护照被收走了也没办法重新申请面签了,只能耐心等待。尚不知道能不能在 WWDC 开幕(和我的航班飞走前)前通过审查拿到护照。

2018.4.28

 • 

WWDC Scholarship

获得了 WWDC 奖学金,今年可以实地去看 Keynote 了。预约了五月初的面签,机票也定了,武汉飞旧金山。除了不确定的期末考试时间以外基本都有准备了。

今年的提交作品其实和去年一样,是一个使用 Noise Map 生成高尔夫球场的高尔夫游戏,至于有什么区别,估计最大的就是我在生成地形的某个步骤之间添加了一个 Thread.Sleep() 罢,如此在较新的 iPad 上获得的结果便是正确的。这看起来像是一个苹果的 bug,我也的确提交了 radar,结果是工程师判断和之前的 radar 重复,但是自去年至少一年过去,这个问题仍然没修,就有点迷了。
对这个 bug 好奇的同学可以去搜下 openradar 上的 #39027796,具体内容是:对于 SceneKit 内的一个 SCNPlane 来说,如果改变其 SegmentWidth/Height,其 vertex 数目是没有立刻更改的,这对于过程生成的计算真的是一个比较严重的问题了(

Lonely Planet

Lonely Planet 目前已经从 Google Play 和 App Store 下架,包括 Youtube 上的宣传视频也暂时私享。原因是 Lonely Planet 商标的注册公司(卖杂志的那个)说我的软件侵犯他们的商标,而我没有十足的把握怼回去也没有足够的经历准备材料,就先下架求个安宁。后面 Lonely Planet 会直接用 Epoch Core 的名字重新上架。至于 Epoch,目前我在基于 Epoch Core 做 Google Earth 为题的毕设,Epoch 本身完工只能说是遥遥无期。不过在做毕设的过程中倒是发现了一个很像 vuejs 的 Unity UI 库:MarkLight,最近在基于这个库封装一些组件。

2018.4.20

 • 

学校

体育分数被教务系统弄丢的事情之前写了校长信箱,回信也不尽人意。回学校后需要继续去找老师处理。

比赛

上海宜家 hackathon 第一名,1.5 万欧元孵化器奖金。和队友做的是 2015 年 fix++ 的宜家版。

毕设

因为一个一言难尽的学校相关事情,毕设进度拖了一些,不过技术上直接拿 Epoch 肯定能毕业了,主要是纸面上的内容(论文,报告),抓紧下应该也没问题

21

 • 

21 岁的第一天因为吃了不卫生的饭店,发烧又拉肚子。

想了想自己的 20 岁,大部分时间是在焦虑和压抑,以及因此而产生的要发泄的怒气中度过。也没有生产太多有价值的东西,大部分时间都在看,看人与人之间的冲突,利益各方暗自的角力,过于懈怠和过于热情的奇怪的人们,因为钱而撕破脸的冲突,团队的聚和散,意气风发的光景和陷入绝地的状况。
而我也足够幸运,做了一些比较正确的决定,虽然事情仍然缠身,但尚不至于没有出路。至于选择本身,有的时候没有选择比有选择看起来还更好些,会少却很多顾虑和念想。
很多时候不想说模棱两可的话,但一旦指名道姓说出去又会得罪人,因此各种平台上也不怎么活跃了。
秉承着一贯模棱两可的状态,总结下自己的 20 岁(或许还有前面几年)里学到的东西:

关于钱
我对钱一贯的看法就是,在没有足够的钱之前谈钱的虚无是很荒谬的。我还记得村上春树在哪部小说里写到“天生丽质的女生可以说自己今天不好看而不愿意出门,但资质平平的女生这么说就会被人笑掉大牙”。这句话描述出来或许有些政治不正确的意味,但事情就是这样,钱也同理。

关于价值
创造价值在很多时候约等于赚钱,因此从某种功利的角度说来说提供了一个支持创造价值的观点。理想的状态是一个人创造他所爱的价值,然后通过创造的价值兑换和消费其他人创造的事物。
提防拿着实现人生价值的口号却让他人从事批量生产的人。

关于学校
这里对学校的定义是:国内的国家认可的高等教育学府。
学校和企业其实并无二样,学校只会做对学校整体最好的事情,至于个体的发展并不是学校所关心的,公司会有的利益相关,僵化死板,学校也会有。
但在某些方面,学校相较于企业能造成的破坏更甚,因为学校曾经在道义上负担着某种高尚的责任,学校一般也乐意去接受这种高尚的赞美,即使在背地里这种高尚是被当着面砸碎给学生看的,称之为:进入社会前的准备。