王小兵 2025-03-11T20:42:06+08:00 spencer.wong@hotmail.com Shadertoy 中文教程 2025-02-17T00:00:00+08:00 王小兵 https://peakcoder.com/shader/shadertoy/2025/02/17/shadertoy 你好!我的朋友,我最近对着色器以及它们的神奇之处很着迷。今天,我们会将讨论如何使用一个名为 Shadertoy 的出色在线工具创建像素着色器,该工具由两位非常有才华的人 Inigo QuilezPol Jeremias 创建。

我大概花了三周,翻译整理了作者 Nathan Vaughn 在他的博客上的 Shadertoy 英文教程,有兴趣的可以去观摩学习英文原版。

我翻译的中文教程,用 docusaurus 托管在 netlify
地址:shadertoy.peakcoder.com

先贴一个我自己写的 Shadertoy 是我自己头像的 Voxel Art Avatar
Shadertoy 网站至少你应该注册过了吧,Emmm..可以去给我点个赞 :)

另外,本教程的代码仓库地址:github.com/iMemento/shadertoy-tutorial
如果能给个 star ✨ 我会感激不尽。

希望你看完本教程,能有所收获。

-EOF-

]]>
Unity Sentis:Runtime 使用 AI 模型 2024-05-19T00:00:00+08:00 王小兵 https://peakcoder.com/unity/ai/2024/05/19/sentis SentisUnity 推出的一个用于在 Unity 环境中运行机器学习模型的框架,可以简化将机器学习模型集成到 Unity 项目中的过程。

使用方法

1. 安装 Sentis

打开 Window > Package Manager
点击 + 选择 Add package by name
输入 com.unity.sentis 安装

2. 导入模型

Hugging Face 选择并下载你需要的模型,或者去 ModelZoo 之类下载。
Hugging Face 上,模型通常以 PyTorchTensorFlow 格式提供,需要转换为 ONNX 格式。

假设你使用的是 PyTorch 模型,可以使用 torch.onnx.export 方法来完成转换。

import torch
from transformers import AutoModel

# Load your Hugging Face model
model = AutoModel.from_pretrained("your-model-name")

# Set the model to evaluation mode
model.eval()

# Dummy input for model export
dummy_input = torch.randn(1, 3, 224, 224)  # Adjust dimensions as needed

# Export the model to ONNX format
torch.onnx.export(model, dummy_input, "model.onnx", opset_version=11)

Tips:

如果不使用 Unity 想直接在 iOS 中使用,则需要再讲 ONNX 转化为 Core Ml 格式。

3. 加载和运行模型

using UnityEngine;
using Unity.Sentis;
using System.IO;

public class SentisExample : MonoBehaviour
{
    private Model runtimeModel;
    private IWorker worker;

    void Start()
    {
        // 加载 ONNX 模型文件
        var modelFilePath = Application.dataPath + "/model.onnx";
        var modelData = File.ReadAllBytes(modelFilePath);

        // 加载模型到 Sentis
        runtimeModel = ModelLoader.Load(modelData);
        worker = WorkerFactory.CreateWorker(WorkerFactory.Type.ComputePrecompiled, runtimeModel);

        // 准备输入数据(示例)
        // 根据模型调整维度
        var inputTensor = new Tensor(1, 3, 224, 224); 

        // 执行推理
        worker.Execute(inputTensor);
        var outputTensor = worker.PeekOutput();

        // 处理输出数据
        Debug.Log(outputTensor);

        // 清理资源
        inputTensor.Dispose();
        outputTensor.Dispose();
        worker.Dispose();
    }
}

模型优化技术

为了在移动设备上高效运行,模型通常需要经过优化,包括:

1. 量化(Quantization)

将模型从32位浮点数表示转换为8位整数表示,可以显著减少模型的大小和计算需求。

2. 模型剪枝(Pruning)

移除模型中冗余的权重和节点,减少计算复杂度。

3. 知识蒸馏(Knowledge Distillation)

将复杂模型的知识转移到一个较小的模型中。

最新的iPhone能够运行包含数百万到数千万参数的优化模型。例如,MobileNetTinyBERT 等模型经过量化和其他优化技术处理后,可以在iPhone上高效地运行。

–EOF–

]]>
分花:愿你有无数的鲜花与浪漫 2024-04-22T00:00:00+08:00 王小兵 https://peakcoder.com/indie/2024/04/22/petals

发一个年初做的 APP「分花」 凑一篇 Blog 吧。
大概这辈子再也不会做这种类型的软件了…



有人要内购兑换码吗:)
可以邮件: zaijing@alu.hit.edu.cn
小红书: peakcoder
愿你有无数的鲜花与浪漫

–EOF–

]]>
Git .gitattributes 使用指北 2024-01-05T00:00:00+08:00 王小兵 https://peakcoder.com/git/2024/01/05/gitattributes .gitattributes 文件在 Git 仓库中用于定义各种属性,以指定 Git 如何处理仓库中的文件。
这个文件可以用于多种用途,包括但不限于以下几种:

1. 行尾转换 (End-of-Line Conversion)

指定文件的行尾风格,例如,强制在 Windows 和 UNIX 系统之间一致地使用 LF 或 CRLF。

*.txt text eol=lf
*.bat text eol=crlf

2. 合并策略 (Merge Strategies)

为特定文件或路径指定合并策略,比如使用文本方式合并或使用特定的合并驱动。

*.png merge=theirs

3. 大文件存储 (Large File Storage, LFS)

将大文件如视频、音频或大型二进制文件交给 Git LFS 管理。

*.mp4 filter=lfs diff=lfs merge=lfs -text

4. 导出忽略 (Export Ignore)

指定在使用 git archive 时应该忽略的文件。

*.log export-ignore

5. 语言统计 (Language Statistics)

控制 git 命令如何统计语言使用情况,可以用于排除某些文件。

*.md linguist-documentation

6. 差异展示 (Diff)

指定文件的差异展示方式,如是否应该被 Git 识别为文本,并如何显示差异。

*.jpg binary
*.html diff=html

7. 禁用压缩 (Disable Compression)

禁用对特定文件的 Git 压缩。

*.jpg -filter

8. 自定义过滤器 (Custom Filters)

为文件设置自定义的清理(clean)和还原(smudge)过滤器。

*.json filter=jsonFilter

9. 核对属性 (Check Attributes)

在提交前检查文件是否符合特定的属性要求。

*.py check=python

10. 文本属性 (Text Attributes)

指定文件是否应被视为文本,对行尾进行规范化,或者被视为二进制文件。

*.txt text
*.bin binary

–EOF–

]]>
Open Source a Pixel-Art Game 'PuppyTouch' 2023-03-06T00:00:00+08:00 王小兵 https://peakcoder.com/cocos2d-x/2023/03/06/puppy-touch 开源一个游戏 PuppyTouch 这是我在大学刚毕业时候做的,是一个2d像素风的小游戏,使用cocos2d-x引擎开发的。手写识别使用的是华盛顿大学的 $1 Unistroke Recognizer 算法。

之前在AppStore上架过,长久不更新现已下架。
代码不多,大量的时间都在美术上消耗掉了,年少时的我是真的很爱画像素画 :)

–EOF–

]]>
Unity Editor 添加 Custom Shortcuts 2023-01-31T00:00:00+08:00 王小兵 https://peakcoder.com/unity/2023/01/31/editor-shortcut 1. 在 MenuItem 标签内使用特殊字符
  • % (ctrl on Windows and Linux, cmd on macOS),
  • ^ (ctrl on Windows, Linux, and macOS),
  • # (shift),
  • & (alt).

例如以下代码的快捷键为 CTRL + G

[MenuItem("Test/example %g")]
private static void Test()
{
    Debug.Log("TEST!");
}

2. ShortcutManager(Editor -> Shortcuts) 直接添加全局快捷键

–EOF–

]]>
Non-Convex MeshCollider 设备上不响应碰撞 2023-01-09T00:00:00+08:00 王小兵 https://peakcoder.com/unity/2023/01/09/mesh-collider 非凸多边形的 MeshCollider,在 Editor 下响应碰撞,设备上不响应。
并且会报错 CollisionMeshData couldn’t be created because the mesh has been marked as non-accessible.
需要在 FBX 导入的设置开启 Read/Write

这可能是以下情况导致的:

  • When you read from or write to the Mesh data in your code.
  • When you pass the Mesh to StaticBatchingUtility.Combine() to combine the Mesh at run time.
  • When you pass the mesh to CanvasRenderer.SetMesh.
  • When you use the Mesh to bake a NavMesh using the NavMesh building components at run time.
  • When the Mesh is convex, you use the Mesh with a Mesh Collider, and the Mesh Collider’s Transform has negative scaling (for example, (–1, 1, 1)).
  • When you use the Mesh with a Mesh Collider, and the Mesh Collider’s transform is skewed or sheared (for example, when a rotated Transform has a scaled parent Transform).
  • When you use the Mesh with a Mesh Collider, and the Mesh Collider’s Cooking Options flags are set to any value other than the default.
  • When using a Mesh with a Particle System’s Shape module or Renderer module ·when not using GPU instancing.

–EOF–

]]>
Shader Support VR Single Pass Instanced 2022-07-13T00:00:00+08:00 王小兵 https://peakcoder.com/unity/2022/07/13/single-pass 在 VR 中,有时只有一只眼睛可以看见,另一只眼睛没有渲染
是因为 Shader 没有支持 Single Pass Instanced Render Mode
不用怕性能损失的话,可以 直接使用 Multi-pass Mode 解决

否则需要以下操作让 Shader 在 Single Pass Instanced 模式下让渲染 compatible

1. #include "UnityCG.cginc" - near the top of the CGPROGRAM block

2. UNITY_INSTANCE_ID - should be in the the vert input data struct (ex: appdata)

3. UNITY_SETUP_INSTANCE_ID(v); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); - should be in the vert function

4. UNITY_VERTEX_OUTPUT_STEREO - should be in the frag input data struct (ex: v2f)

–EOF–

]]>
Custom UnityAppController 2022-05-10T00:00:00+08:00 王小兵 https://peakcoder.com/unity/2022/05/10/custom-appcontroller 之前项目都是编译后处理脚本里做文件替换 UnityAppController.mm
以下是更优雅的方式:

/path/to/unity/project/Assets/Plugins/iOS/CustomAppController.mm
注意,文件名必须是 ___AppController,前缀可自选,但不能省略;否则在 Build 项目的时候,会被移动到错误的目录中去
使用宏 IMPL_APP_CONTROLLER_SUBCLASS (CustomAppController) 定制启动调用

#import "UnityAppController.h"
#import <UIKit/UIKit.h>
#import <FIRApp.h>
@interface CustomAppController : UnityAppController
@end

IMPL_APP_CONTROLLER_SUBCLASS (CustomAppController)

// 如果使用 modules import,则不能用.mm混编 只能用.m
@import GoogleMobileAds;

@implementation CustomAppController

- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    [super application:application didFinishLaunchingWithOptions:launchOptions];
    [FIRApp configure];
    [[GADMobileAds sharedInstance] startWithCompletionHandler:nil];
    return YES;
}

@end

–EOF–

]]>
Find and remove missing components 2022-03-09T00:00:00+08:00 王小兵 https://peakcoder.com/unity/2022/03/09/remove-missing
public static void RemoveInGo(GameObject g)
{
    var components = g.GetComponents<Component>();
    
    var r = 0;
    
    for (var i = 0; i < components.Length; ++i)
    {
        if (components[i] != null) 
            continue;
        
        var s = g.name;
        var t = g.transform;
        while (t.parent != null) 
        {
            s = t.parent.name +"/"+s;
            t = t.parent;
        }
        
        Debug.Log ($"{s} has a missing script at {i}", g);
        
        var serializedObject = new SerializedObject(g);
        
        var prop = serializedObject.FindProperty("m_Component");
        
        prop.DeleteArrayElementAtIndex(i-r);
        r++;
    
        serializedObject.ApplyModifiedProperties();
    }
    
    foreach (Transform childT in g.transform)
    {
        RemoveInGo(childT.gameObject);
    }
}

官方解决方案可以使用
GameObjectUtility.RemoveMonoBehavioursWithMissingScript

–EOF–

]]>