├── book.jpg ├── taichi.png ├── Lab2 N-body ├── show.png ├── .vs │ └── PythonApplication │ │ └── v16 │ │ └── .suo ├── README.md ├── PythonApplication.sln └── PythonApplication │ ├── PythonApplication.pyproj │ └── PythonApplication.py ├── Lab4 Dominoes ├── show.png ├── PythonApplication │ ├── imgui.ini │ ├── PythonApplication.pyproj │ └── PythonApplication.py ├── .vs │ └── PythonApplication │ │ └── v16 │ │ └── .suo ├── README.md └── PythonApplication.sln ├── Lab1 Crash-balls ├── show.png ├── .vs │ └── PythonApplication │ │ └── v16 │ │ └── .suo ├── PythonApplication.sln ├── README.md └── PythonApplication │ ├── PythonApplication.pyproj │ └── PythonApplication.py ├── Lab7 Path-tracing ├── show.png ├── PythonApplication │ ├── imgui.ini │ ├── __pycache__ │ │ └── head.cpython-311.pyc │ ├── PythonApplication.pyproj │ ├── PythonApplication.py │ └── head.py ├── .vs │ └── PythonApplication │ │ └── v16 │ │ └── .suo ├── README.md └── PythonApplication.sln ├── Lab8 Stable-fluid ├── show.png ├── .vs │ └── PythonApplication │ │ └── v16 │ │ └── .suo ├── PythonApplication │ ├── __pycache__ │ │ └── head.cpython-311.pyc │ ├── PythonApplication.pyproj │ └── PythonApplication.py ├── README.md └── PythonApplication.sln ├── Lab3 Cloth-simulation ├── fuck.jpeg ├── show.png ├── PythonApplication │ ├── imgui.ini │ ├── PythonApplication.pyproj │ └── PythonApplication.py ├── .vs │ └── PythonApplication │ │ └── v16 │ │ └── .suo ├── README.md └── PythonApplication.sln ├── Lab5 Water-simulation ├── fuck.jpg ├── show.png ├── PythonApplication │ ├── imgui.ini │ ├── PythonApplication.pyproj │ └── PythonApplication.py ├── Position Based Fluids.pdf ├── .vs │ └── PythonApplication │ │ └── v16 │ │ └── .suo ├── README.md └── PythonApplication.sln ├── Lab6 Temperature-diffuse ├── show.png ├── PythonApplication │ ├── imgui.ini │ ├── PythonApplication.pyproj │ └── PythonApplication.py ├── .vs │ └── PythonApplication │ │ └── v16 │ │ └── .suo ├── README.md └── PythonApplication.sln ├── README_zh.md └── README.md /book.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/book.jpg -------------------------------------------------------------------------------- /taichi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/taichi.png -------------------------------------------------------------------------------- /Lab2 N-body/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab2 N-body/show.png -------------------------------------------------------------------------------- /Lab4 Dominoes/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab4 Dominoes/show.png -------------------------------------------------------------------------------- /Lab1 Crash-balls/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab1 Crash-balls/show.png -------------------------------------------------------------------------------- /Lab7 Path-tracing/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab7 Path-tracing/show.png -------------------------------------------------------------------------------- /Lab8 Stable-fluid/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab8 Stable-fluid/show.png -------------------------------------------------------------------------------- /Lab3 Cloth-simulation/fuck.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab3 Cloth-simulation/fuck.jpeg -------------------------------------------------------------------------------- /Lab3 Cloth-simulation/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab3 Cloth-simulation/show.png -------------------------------------------------------------------------------- /Lab4 Dominoes/PythonApplication/imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][Debug##Default] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | -------------------------------------------------------------------------------- /Lab5 Water-simulation/fuck.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab5 Water-simulation/fuck.jpg -------------------------------------------------------------------------------- /Lab5 Water-simulation/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab5 Water-simulation/show.png -------------------------------------------------------------------------------- /Lab6 Temperature-diffuse/show.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab6 Temperature-diffuse/show.png -------------------------------------------------------------------------------- /Lab7 Path-tracing/PythonApplication/imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][Debug##Default] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | -------------------------------------------------------------------------------- /Lab3 Cloth-simulation/PythonApplication/imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][Debug##Default] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | -------------------------------------------------------------------------------- /Lab5 Water-simulation/PythonApplication/imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][Debug##Default] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | -------------------------------------------------------------------------------- /Lab6 Temperature-diffuse/PythonApplication/imgui.ini: -------------------------------------------------------------------------------- 1 | [Window][Debug##Default] 2 | Pos=60,60 3 | Size=400,400 4 | Collapsed=0 5 | 6 | -------------------------------------------------------------------------------- /Lab2 N-body/.vs/PythonApplication/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab2 N-body/.vs/PythonApplication/v16/.suo -------------------------------------------------------------------------------- /Lab4 Dominoes/.vs/PythonApplication/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab4 Dominoes/.vs/PythonApplication/v16/.suo -------------------------------------------------------------------------------- /Lab1 Crash-balls/.vs/PythonApplication/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab1 Crash-balls/.vs/PythonApplication/v16/.suo -------------------------------------------------------------------------------- /Lab5 Water-simulation/Position Based Fluids.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab5 Water-simulation/Position Based Fluids.pdf -------------------------------------------------------------------------------- /Lab7 Path-tracing/.vs/PythonApplication/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab7 Path-tracing/.vs/PythonApplication/v16/.suo -------------------------------------------------------------------------------- /Lab8 Stable-fluid/.vs/PythonApplication/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab8 Stable-fluid/.vs/PythonApplication/v16/.suo -------------------------------------------------------------------------------- /Lab3 Cloth-simulation/.vs/PythonApplication/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab3 Cloth-simulation/.vs/PythonApplication/v16/.suo -------------------------------------------------------------------------------- /Lab5 Water-simulation/.vs/PythonApplication/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab5 Water-simulation/.vs/PythonApplication/v16/.suo -------------------------------------------------------------------------------- /Lab6 Temperature-diffuse/.vs/PythonApplication/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab6 Temperature-diffuse/.vs/PythonApplication/v16/.suo -------------------------------------------------------------------------------- /Lab7 Path-tracing/PythonApplication/__pycache__/head.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab7 Path-tracing/PythonApplication/__pycache__/head.cpython-311.pyc -------------------------------------------------------------------------------- /Lab8 Stable-fluid/PythonApplication/__pycache__/head.cpython-311.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ayinzhang/Taichi-Projects/HEAD/Lab8 Stable-fluid/PythonApplication/__pycache__/head.cpython-311.pyc -------------------------------------------------------------------------------- /Lab7 Path-tracing/README.md: -------------------------------------------------------------------------------- 1 | # Lab7 Path-tracing 2 | 3 | **康奈尔盒子简易路径追踪** 4 | 5 | **~~没想到吧,我又来做渲染了~~** 6 | 7 |
8 | 9 |
10 | 11 | -------------------------------------------------------------------------------- /Lab4 Dominoes/README.md: -------------------------------------------------------------------------------- 1 | # Lab4 Dominoes 2 | 3 | **多刚体碰撞模拟,各式向量运算和罗德里格旋转公式** 4 | 5 | **~~field为什么不能整体自定义赋值?field间嵌套为什么会报错?还有你这UGUI操作怎么这么像OpenGL?~~** 6 | 7 |
8 | 9 |
10 | -------------------------------------------------------------------------------- /Lab8 Stable-fluid/README.md: -------------------------------------------------------------------------------- 1 | # Lab8 Stable-fluid 2 | 3 | **欧拉视角半拉格朗日平流加雅可比投影** 4 | 5 | **~~模拟,渲染,游戏开发......时至今日,依旧迷茫~~** 6 | 7 | *p 暂停模拟* 8 | 9 | *r 重置模拟* 10 | 11 | *Esc 退出模拟* 12 | 13 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /Lab6 Temperature-diffuse/README.md: -------------------------------------------------------------------------------- 1 | # Lab6 Temperature-diffuse 2 | 3 | **隐式线性求解温度传播,稀疏矩阵和线性求解器的初探** 4 | 5 | **~~逃跑未遂,第二弹开始营业。Taichi,启动!~~** 6 | 7 | *Space 暂停模拟* 8 | 9 | *r 重置模拟* 10 | 11 | *Esc 退出模拟* 12 | 13 |
14 | 15 |
16 | -------------------------------------------------------------------------------- /Lab2 N-body/README.md: -------------------------------------------------------------------------------- 1 | # N-body 2 | 3 | **空间数据结构加速的多体天体模型,初始随机体积位置并环绕** 4 | 5 | **~~从O(n^2) 干到O(nlogn),O(n)的自适应快速多级方法不可能的,洗洗睡吧梦里什么都有~~** 6 | 7 | 8 | 9 | *鼠标左键 对所有天体施加引力* 10 | 11 | *鼠标右键 对所有天体施加斥力* 12 | 13 | *Esc 退出程序* 14 | 15 | 16 | 17 |
18 | 19 |
20 | -------------------------------------------------------------------------------- /Lab3 Cloth-simulation/README.md: -------------------------------------------------------------------------------- 1 | # Cloth-simulation 2 | 3 | **布料模拟,运用了基于胡克定律的PBD改进** 4 | 5 | **~~被Taichi的自动并行化和混乱的数据结构整的硬de了一天的bug~~** 6 | 7 |
8 | 9 |

Taichi你个狗杂种!

10 |
11 |
12 | 13 |
14 | -------------------------------------------------------------------------------- /Lab5 Water-simulation/README.md: -------------------------------------------------------------------------------- 1 | # Lab5 Water-simulation 2 | 3 | **PBF流体模拟,Position Based Fluids的复现** 4 | 5 | **~~说的几十万个粒子实时呢?我这开一万个还没模拟就炸了,GTX1650也不算太低吧这~~** 6 | 7 |
8 | 9 |

Taichi再见了您嘞!

10 |
11 |
12 | 13 |
14 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # Taichi项目 2 | 3 | [English Version](README.md) 4 | 5 | **假期及实习间隙做的一些杂项,部分基于Taichi图形课以及《基于物理的建模与动画》** 6 | 7 | *Lab1 GUI碰撞模拟 回溯碰撞解除,五种积分方式* 8 | 9 | *Lab2 GUI多体天体模拟 空间数据结构加速,初始随机体积位置并环绕* 10 | 11 | *Lab3 GGUI布料模拟,基于胡克定律的PBD改进* 12 | 13 | *Lab4 GGUI多刚体碰撞模拟,各式向量运算和罗德里格旋转公式* 14 | 15 | *Lab5 GUI三维PBF流体模拟,Position Based Fluids的复现* 16 | 17 | *Lab6 GUI隐式线性求解温度传播,稀疏矩阵和线性求解器的初探* 18 | 19 | *Lab7 GUI路径追踪,康奈尔盒子简易路径追踪* 20 | 21 | *Lab8 GUI流体扩散,欧拉视角半拉格朗日平流加雅可比投影* 22 | 23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 | -------------------------------------------------------------------------------- /Lab2 N-body/PythonApplication.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PythonApplication", "PythonApplication\PythonApplication.pyproj", "{73E3B394-3719-4284-B58C-3CBFFD15CC5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {F5A7264E-DEB0-4076-BB00-7375D8AE76A3} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /Lab4 Dominoes/PythonApplication.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PythonApplication", "PythonApplication\PythonApplication.pyproj", "{73E3B394-3719-4284-B58C-3CBFFD15CC5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {F5A7264E-DEB0-4076-BB00-7375D8AE76A3} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /Lab1 Crash-balls/PythonApplication.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PythonApplication", "PythonApplication\PythonApplication.pyproj", "{73E3B394-3719-4284-B58C-3CBFFD15CC5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {F5A7264E-DEB0-4076-BB00-7375D8AE76A3} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /Lab7 Path-tracing/PythonApplication.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PythonApplication", "PythonApplication\PythonApplication.pyproj", "{73E3B394-3719-4284-B58C-3CBFFD15CC5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {F5A7264E-DEB0-4076-BB00-7375D8AE76A3} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /Lab8 Stable-fluid/PythonApplication.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PythonApplication", "PythonApplication\PythonApplication.pyproj", "{73E3B394-3719-4284-B58C-3CBFFD15CC5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {F5A7264E-DEB0-4076-BB00-7375D8AE76A3} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /Lab3 Cloth-simulation/PythonApplication.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PythonApplication", "PythonApplication\PythonApplication.pyproj", "{73E3B394-3719-4284-B58C-3CBFFD15CC5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {F5A7264E-DEB0-4076-BB00-7375D8AE76A3} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /Lab5 Water-simulation/PythonApplication.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PythonApplication", "PythonApplication\PythonApplication.pyproj", "{73E3B394-3719-4284-B58C-3CBFFD15CC5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {F5A7264E-DEB0-4076-BB00-7375D8AE76A3} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /Lab6 Temperature-diffuse/PythonApplication.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31829.152 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "PythonApplication", "PythonApplication\PythonApplication.pyproj", "{73E3B394-3719-4284-B58C-3CBFFD15CC5B}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {73E3B394-3719-4284-B58C-3CBFFD15CC5B}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {F5A7264E-DEB0-4076-BB00-7375D8AE76A3} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Taichi-projects 2 | 3 | [中文版](README_zh.md) 4 | 5 | **Miscellaneous works done during holidays and internship breaks, some based on Taichi graphics class and 'Physics based Modeling and Animation'** 6 | 7 | *Lab1 GUI collision simulation backtracking collision release, five integration methods* 8 | 9 | *Lab2 GUI multi-body celestial body simulation space data structure acceleration, initial random volume position and surrounding* 10 | 11 | *Lab3 GGUI Fabric Simulation, PBD Improvement Based on Hooke's Law* 12 | 13 | *Lab4 GGUI Multi Body Collision Simulation, Various Vector Operations, and Rodrigues Rotation Formula* 14 | 15 | *Lab5 GUI 3D PBF fluid simulation, reproduction of Position Based Fluids* 16 | 17 | *Lab6 GUI Preliminary Exploration of implicit Linear Solution for Temperature Propagation, Sparse Matrix, and Linear Solver* 18 | 19 | *Lab7 GUI Path Tracking, Cornell Box Easy Path Tracking* 20 | 21 | *Lab8 GUI fluid diffusion, Euler perspective semi Lagrangian advection with Jacobian projection* 22 | 23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 | -------------------------------------------------------------------------------- /Lab1 Crash-balls/README.md: -------------------------------------------------------------------------------- 1 | # Crash-balls 2 | 3 | **回溯碰撞解除的碰撞球模型,可选择五种积分方式(显式欧拉,隐式欧拉,半隐式欧拉,速度韦尔莱,二阶龙格库塔)** 4 | 5 | **~~但作者本人表示看不出啥区别~~** 6 | 7 | 8 | 9 | *鼠标左键 添加碰撞球* 10 | 11 | *w/s 增加/减少重力分量* 12 | 13 | *d/a 增加/减少风力分量* 14 | 15 | *↑/↓ 增加/减少潮湿度数* 16 | 17 | *→/← 增加/减少风力分量* 18 | 19 | *q 切换欧拉算法* 20 | 21 | *r 清除所有碰撞球* 22 | 23 | *Esc 退出程序* 24 | 25 | 26 | 27 | *Explicit Euler's Method:* 28 | $$ 29 | \vec v(t_1)=\vec v(t_0)+M^{-1}\vec F(t_0)\Delta t 30 | $$ 31 | $$ 32 | x(t_1)=x(t_0)+\vec v(t_0)\Delta t 33 | $$ 34 | *Implicit Euler's Method:* 35 | $$ 36 | \vec v(t_1)=\vec v(t_0)+M^{-1}\vec F(t_1)\Delta t 37 | $$ 38 | $$ 39 | x(t_1)=x(t_0)+\vec v(t_1)\Delta t 40 | $$ 41 | *Semi_Implicit Euler's Method:* 42 | $$ 43 | \vec v(t_1)=\vec v(t_0)+M^{-1}\vec F(t_0)\Delta t 44 | $$ 45 | $$ 46 | x(t_1)=x(t_0)+\vec v(t_1)\Delta t 47 | $$ 48 | 49 | *Velocity Welley* 50 | $$ 51 | x(t_1)=x(t_0)+\vec v(t_0)\Delta t+\frac{1}{2}M^{-1}\vec F(t_0)\Delta t^2 52 | $$ 53 | 54 | $$ 55 | \vec v(t_1)=\vec v(t_0)+\frac{1}{2}M^{-1}(\vec F(t_0)+\vec F(t_1))\Delta t 56 | $$ 57 | 58 | *Runge Kutta2* 59 | $$ 60 | \vec v(t_1)=\vec v(t_0)+M^{-1}\vec F(t_0)\Delta t 61 | $$ 62 | 63 | $$ 64 | x(t_{0.5})=x(t_0)+\frac{1}{2}\vec v(t_0)\Delta t 65 | $$ 66 | 67 | $$ 68 | \vec v(t_{0.5})=\vec v(t_0)+\frac{1}{2}M^{-1}\vec F(t_{0.5})\Delta t 69 | $$ 70 | 71 | $$ 72 | x(t_1) = x(t_0)+\vec v(t_{0.5})\Delta t 73 | $$ 74 | 75 | 76 | 77 |
78 | 79 |
80 | -------------------------------------------------------------------------------- /Lab2 N-body/PythonApplication/PythonApplication.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 73e3b394-3719-4284-b58c-3cbffd15cc5b 6 | . 7 | PythonApplication.py 8 | 9 | 10 | . 11 | . 12 | PythonApplication 13 | PythonApplication 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Lab4 Dominoes/PythonApplication/PythonApplication.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 73e3b394-3719-4284-b58c-3cbffd15cc5b 6 | . 7 | PythonApplication.py 8 | 9 | 10 | . 11 | . 12 | PythonApplication 13 | PythonApplication 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Lab1 Crash-balls/PythonApplication/PythonApplication.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 73e3b394-3719-4284-b58c-3cbffd15cc5b 6 | . 7 | PythonApplication.py 8 | 9 | 10 | . 11 | . 12 | PythonApplication 13 | PythonApplication 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Lab8 Stable-fluid/PythonApplication/PythonApplication.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 73e3b394-3719-4284-b58c-3cbffd15cc5b 6 | . 7 | PythonApplication.py 8 | 9 | 10 | . 11 | . 12 | PythonApplication 13 | PythonApplication 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Lab3 Cloth-simulation/PythonApplication/PythonApplication.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 73e3b394-3719-4284-b58c-3cbffd15cc5b 6 | . 7 | PythonApplication.py 8 | 9 | 10 | . 11 | . 12 | PythonApplication 13 | PythonApplication 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Lab5 Water-simulation/PythonApplication/PythonApplication.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 73e3b394-3719-4284-b58c-3cbffd15cc5b 6 | . 7 | PythonApplication.py 8 | 9 | 10 | . 11 | . 12 | PythonApplication 13 | PythonApplication 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Lab6 Temperature-diffuse/PythonApplication/PythonApplication.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 73e3b394-3719-4284-b58c-3cbffd15cc5b 6 | . 7 | PythonApplication.py 8 | 9 | 10 | . 11 | . 12 | PythonApplication 13 | PythonApplication 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Lab7 Path-tracing/PythonApplication/PythonApplication.pyproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Debug 4 | 2.0 5 | 73e3b394-3719-4284-b58c-3cbffd15cc5b 6 | . 7 | PythonApplication.py 8 | 9 | 10 | . 11 | . 12 | PythonApplication 13 | PythonApplication 14 | 15 | 16 | true 17 | false 18 | 19 | 20 | true 21 | false 22 | 23 | 24 | 25 | Code 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /Lab6 Temperature-diffuse/PythonApplication/PythonApplication.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | ti.init(ti.cpu) 3 | 4 | k = 3000 5 | n = 512 6 | dt = 1e-2 7 | radius = 64 8 | t_min = 0 9 | t_max = 300 10 | paused = False 11 | n2 = n * n 12 | c = dt * k 13 | t = ti.field(ti.f32, n2) 14 | pixels = ti.Vector.field(3, ti.f32, (n, n)) 15 | D_Builder = ti.linalg.SparseMatrixBuilder(n2, n2, 5 * n2) 16 | 17 | @ti.kernel 18 | def fillDiffusionMatrixBuilder(A: ti.types.sparse_matrix_builder()): 19 | for i,j in ti.ndrange(n, n): 20 | num = 0.0 21 | if i - 1 >= 0: 22 | A[i * n + j, (i - 1) * n + j] -= c 23 | num += c 24 | if i + 1 < n: 25 | A[i * n + j, (i + 1) * n + j] -= c 26 | num += c 27 | if j - 1 >= 0: 28 | A[i * n + j, i * n + j - 1] -= c 29 | num += c 30 | if j + 1 < n: 31 | A[i * n + j, i * n + j + 1] -= c 32 | num += c 33 | A[i * n + j, i * n + j] += num + 1 34 | 35 | @ti.kernel 36 | def init(): 37 | for i,j in ti.ndrange(n, n): 38 | if (i - n // 2) ** 2 + (j - n // 2) ** 2 <= radius ** 2: 39 | t[i * n + j] = t_max 40 | else: 41 | t[i * n + j] = t_min 42 | 43 | @ti.kernel 44 | def update_sourse(): 45 | for i in range(n // 2 - radius, n // 2 + radius + 1): 46 | for j in range(n // 2 - radius, n // 2 + radius + 1): 47 | if (i - n // 2) ** 2 + (j - n // 2) ** 2 <= radius ** 2: 48 | t[i * n + j] = t_max 49 | 50 | @ti.kernel 51 | def cook(t: ti.template(), color: ti.template(), t_min: ti.f32, t_max: ti.f32): 52 | for i,j in ti.ndrange(n, n): 53 | color[i, j] = ti.Vector([1, 1, 1]) 54 | d = t_max - t_min 55 | if t[i * n + j] < (t_min + 0.25 * d): 56 | color[i, j][0] = 0 57 | color[i, j][1] = 4 * (t[i * n + j] - t_min) / d 58 | elif t[i * n + j] < (t_min + 0.5 * d): 59 | color[i, j][0] = 0 60 | color[i, j][2] = 1 + 4 * (t_min + 0.25 * d - t[i * n + j]) / d 61 | elif t[i * n + j] < (t_min + 0.75 * d): 62 | color[i, j][0] = 4 * (t[i * n + j] - t_min - 0.5 * d) / d 63 | color[i, j][2] = 0 64 | else: 65 | color[i, j][1] = 1 + 4 * (t_min + 0.75 * d - t[i * n + j]) / d 66 | color[i, j][2] = 0 67 | 68 | gui = ti.GUI("Temperature-diffuse", (n, n)) 69 | init() 70 | fillDiffusionMatrixBuilder(D_Builder) 71 | D = D_Builder.build() 72 | solver = ti.linalg.SparseSolver(solver_type="LLT") 73 | solver.analyze_pattern(D) 74 | solver.factorize(D) 75 | ti.profiler.clear_kernel_profiler_info() 76 | while gui.running: 77 | for e in gui.get_events(ti.GUI.PRESS): 78 | if e.key == ti.GUI.SPACE: 79 | paused = not paused 80 | elif e.key == ti.GUI.ESCAPE: 81 | gui.running = False 82 | elif e.key == 'r': 83 | init() 84 | if not paused: 85 | t.from_numpy(solver.solve(t)) 86 | update_sourse() 87 | cook(t, pixels, t_min, t_max) 88 | gui.set_image(pixels) 89 | gui.show() -------------------------------------------------------------------------------- /Lab2 N-body/PythonApplication/PythonApplication.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | ti.init(ti.gpu) 3 | 4 | n = 300 5 | G = 6.67e-11 6 | block_size = 12 7 | galaxy_size = 0.45 8 | planet_radius = 2 9 | dt = 1e-5 10 | substepping = 10 11 | 12 | r = ti.field(ti.f32, n) 13 | m = ti.field(ti.f32, n) 14 | p = ti.Vector.field(2, ti.f32, n) 15 | v = ti.Vector.field(2, ti.f32, n) 16 | f = ti.Vector.field(2, ti.f32, n) 17 | b = ti.field(ti.i32) 18 | block = ti.root.dense(ti.ij, [block_size, block_size]) 19 | index = block.dynamic(ti.k, n) 20 | index.place(b) 21 | 22 | @ti.kernel 23 | def init(): 24 | center = ti.Vector([0.5, 0.5]) 25 | for i in range(n): 26 | theta = ti.random() * 2 * ti.math.pi 27 | d = (ti.sqrt(ti.random()) * 0.7 + 0.3) * galaxy_size 28 | offset = d * ti.Vector([ti.cos(theta), ti.sin(theta)]) 29 | r[i] = (ti.random() + 0.5) * planet_radius 30 | m[i] = r[i] ** 3; 31 | p[i] = center + offset 32 | b[ti.math.floor(p[i].x * block_size, ti.i32), ti.math.floor(p[i].y * block_size, ti.i32)].append(i) 33 | v[i] = [-offset.y, offset.x] 34 | v[i] *= 120 * (ti.sqrt(ti.random()) + 0.5) 35 | 36 | @ti.kernel 37 | def compute(): 38 | for i in range(n): 39 | f[i] = ti.Vector([0.0, 0.0]) 40 | for i in range(n): 41 | x = ti.math.clamp(ti.math.floor(p[i].x * block_size, ti.i32), 0, block_size - 1) 42 | y = ti.math.clamp(ti.math.floor(p[i].y * block_size, ti.i32), 0, block_size - 1) 43 | for j in range(-1, 2): 44 | for k in range(-1, 2): 45 | if 0 <= x + j and x + j < block_size and 0 <= y + k and y + k < block_size: 46 | for l in range(b[x + j, y + k].length()): 47 | o = b[x + j, y + k, l] 48 | if i != o: 49 | r = ti.math.length(p[i] - p[o]) 50 | force = G * m[i] * m[o] / (r ** 3) * (p[o] - p[i]) 51 | f[i] += force 52 | f[o] -= force 53 | 54 | @ti.kernel 55 | def pull(xpos:ti.f32, ypos:ti.f32): 56 | pos = [xpos, ypos] 57 | for i in range(n): 58 | f[i] += (pos - p[i]) ** 3 * 12000000 59 | 60 | @ti.kernel 61 | def push(xpos:ti.f32, ypos:ti.f32): 62 | pos = [xpos, ypos] 63 | for i in range(n): 64 | f[i] += (p[i] - pos) ** 3 * 12000000 65 | 66 | @ti.kernel 67 | def update(): 68 | for i in range(block_size): 69 | for j in range(block_size): 70 | b[i, j].deactivate() 71 | for i in range(n): 72 | v[i] += dt * f[i] / m[i] 73 | p[i] += dt * v[i] 74 | x = ti.math.clamp(ti.math.floor(p[i].x * block_size, ti.i32), 0, block_size - 1) 75 | y = ti.math.clamp(ti.math.floor(p[i].y * block_size, ti.i32), 0, block_size - 1) 76 | b[x, y].append(i) 77 | 78 | 79 | gui = ti.GUI("n-body", (512, 512)) 80 | init() 81 | while gui.running: 82 | compute() 83 | for e in gui.get_events(ti.GUI.PRESS): 84 | if e.key == ti.GUI.LMB: 85 | pull(e.pos[0], e.pos[1]) 86 | if e.key == ti.GUI.RMB: 87 | push(e.pos[0], e.pos[1]) 88 | if e.key == ti.GUI.ESCAPE: 89 | gui.running = False 90 | update() 91 | gui.clear(0x112F41) 92 | gui.circles(p.to_numpy(), color=0xffffff, radius=r.to_numpy()) 93 | gui.show() -------------------------------------------------------------------------------- /Lab7 Path-tracing/PythonApplication/PythonApplication.py: -------------------------------------------------------------------------------- 1 | from head import * 2 | ti.init(ti.gpu) 3 | 4 | width = 600 5 | height = 600 6 | samples = 16 7 | depth = 16 8 | 9 | @ti.kernel 10 | def render(): 11 | for i, j in canvas: 12 | u = (i + ti.random()) / width 13 | v = (j + ti.random()) / height 14 | color = ti.Vector([0.0, 0.0, 0.0]) 15 | for k in range(samples): 16 | ray = camera.get_ray(u, v) 17 | color += get_color(ray) 18 | color /= samples 19 | canvas[i, j] += color 20 | 21 | @ti.func 22 | def get_color(ray): 23 | color_buffer = ti.Vector([0.0, 0.0, 0.0]) 24 | brightness = ti.Vector([1.0, 1.0, 1.0]) 25 | scattered_origin = ray.origin 26 | scattered_direction = ray.direction 27 | rate = 0.85 28 | for n in range(depth): 29 | if ti.random() > rate: 30 | break 31 | is_hit, hit_point, hit_point_normal, front_face, material, color = scene.hit(Ray(scattered_origin, scattered_direction)) 32 | if is_hit: 33 | if material == 0: 34 | color_buffer = color * brightness 35 | break 36 | else: 37 | if material == 1: 38 | target = hit_point + hit_point_normal 39 | target += random_unit_vector() 40 | scattered_direction = target - hit_point 41 | scattered_origin = hit_point 42 | brightness *= color 43 | elif material == 2 or material == 4: 44 | fuzz = 0.0 45 | if material == 4: 46 | fuzz = 0.5 47 | scattered_direction = reflect(scattered_direction.normalized(), hit_point_normal) 48 | scattered_direction += fuzz * random_unit_vector() 49 | scattered_origin = hit_point 50 | if scattered_direction.dot(hit_point_normal) < 0: 51 | break 52 | else: 53 | brightness *= color 54 | elif material == 3: 55 | refraction_ratio = 1.5 56 | if front_face: 57 | refraction_ratio = 1 / refraction_ratio 58 | cos_theta = min(-scattered_direction.normalized().dot(hit_point_normal), 1.0) 59 | sin_theta = ti.sqrt(1 - cos_theta * cos_theta) 60 | if refraction_ratio * sin_theta > 1.0 or reflectance(cos_theta, refraction_ratio) > ti.random(): 61 | scattered_direction = reflect(scattered_direction.normalized(), hit_point_normal) 62 | else: 63 | scattered_direction = refract(scattered_direction.normalized(), hit_point_normal, refraction_ratio) 64 | scattered_origin = hit_point 65 | brightness *= color 66 | brightness /= rate 67 | return color_buffer 68 | 69 | camera = Camera() 70 | scene = Hittable_list() 71 | canvas = ti.Vector.field(3, dtype=ti.f32, shape=(width, height)) 72 | scene.add(Sphere(center=ti.Vector([0, 5.4, -1]), radius=3.0, material=0, color=ti.Vector([10.0, 10.0, 10.0]))) 73 | scene.add(Sphere(center=ti.Vector([0, -100.5, -1]), radius=100.0, material=1, color=ti.Vector([0.8, 0.8, 0.8]))) 74 | scene.add(Sphere(center=ti.Vector([0, 102.5, -1]), radius=100.0, material=1, color=ti.Vector([0.8, 0.8, 0.8]))) 75 | scene.add(Sphere(center=ti.Vector([0, 1, 101]), radius=100.0, material=1, color=ti.Vector([0.8, 0.8, 0.8]))) 76 | scene.add(Sphere(center=ti.Vector([-101.5, 0, -1]), radius=100.0, material=1, color=ti.Vector([0.6, 0.0, 0.0]))) 77 | scene.add(Sphere(center=ti.Vector([101.5, 0, -1]), radius=100.0, material=1, color=ti.Vector([0.0, 0.6, 0.0]))) 78 | scene.add(Sphere(center=ti.Vector([0, -0.2, -1.5]), radius=0.3, material=1, color=ti.Vector([0.8, 0.3, 0.3]))) 79 | scene.add(Sphere(center=ti.Vector([-0.8, 0.2, -1]), radius=0.7, material=2, color=ti.Vector([0.6, 0.8, 0.8]))) 80 | scene.add(Sphere(center=ti.Vector([0.7, 0, -0.5]), radius=0.5, material=3, color=ti.Vector([1.0, 1.0, 1.0]))) 81 | scene.add(Sphere(center=ti.Vector([0.6, -0.3, -2.0]), radius=0.2, material=4, color=ti.Vector([0.8, 0.6, 0.2]))) 82 | gui = ti.GUI("Ray Tracing", res=(width, height)) 83 | cnt = 0 84 | while gui.running: 85 | render() 86 | cnt += 1 87 | gui.set_image(np.sqrt(canvas.to_numpy() / cnt)) 88 | gui.show() -------------------------------------------------------------------------------- /Lab3 Cloth-simulation/PythonApplication/PythonApplication.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | ti.init(ti.gpu) 3 | 4 | n = 128 5 | dt = 1e-3 6 | substep = int(1 / 60 // dt) 7 | quad_size = 1.0 / n 8 | d = 1e2 9 | g = ti.Vector([0, -9.8, 0]) 10 | spring_y = 1e3 11 | spring_offsets = ti.Vector.field(2, dtype = int, shape = 6) 12 | spring = ti.types.struct(a = int, b = int, c = int, d = int, e = float) 13 | s = spring.field() 14 | block = ti.root.dense(ti.i, 1) 15 | index = block.dynamic(ti.j, n * n) 16 | index.place(s) 17 | p = ti.Vector.field(3, dtype = float, shape = (n, n)) 18 | v = ti.Vector.field(3, dtype = float, shape = (n, n)) 19 | f = ti.Vector.field(3, dtype = float, shape = (n, n)) 20 | indices = ti.field(dtype = int, shape = (n - 1) * (n - 1) * 6) 21 | vertices = ti.Vector.field(3, dtype = float, shape = n * n) 22 | colors = ti.Vector.field(3, dtype = float, shape = n * n) 23 | 24 | ball_r = 0.3 25 | ball_p = ti.Vector.field(3, dtype = float, shape = 1) 26 | ball_p[0] = [0, 0, 0] 27 | 28 | @ti.kernel 29 | def init_cloth(): 30 | #physical 31 | spring_offsets[0] = (0, 2) 32 | spring_offsets[1] = (0, 1) 33 | spring_offsets[2] = (1, 1) 34 | spring_offsets[3] = (2, 0) 35 | spring_offsets[4] = (1, 0) 36 | spring_offsets[5] = (1,-1) 37 | for i, j in ti.ndrange(n, n): 38 | for k in range(6): 39 | ni = i + spring_offsets[k][0] 40 | nj = j + spring_offsets[k][1] 41 | if 0 <= ni < n and 0<= nj < n: 42 | s[0].append(spring(i, j, ni, nj, ti.math.length(p[ni, nj] - p[i, j]))) 43 | #rendering 44 | for i, j in ti.ndrange(n - 1, n - 1): 45 | quad_id = i * (n - 1) + j 46 | indices[quad_id * 6 + 0] = i * n + j 47 | indices[quad_id * 6 + 1] = (i + 1) * n + j 48 | indices[quad_id * 6 + 2] = i * n + (j + 1) 49 | indices[quad_id * 6 + 3] = (i + 1) * n + j + 1 50 | indices[quad_id * 6 + 4] = i * n + (j + 1) 51 | indices[quad_id * 6 + 5] = (i + 1) * n + j 52 | for i, j in ti.ndrange(n, n): 53 | if (i // 4 + j // 4) % 2 == 0: 54 | colors[i * n + j] = (0.46, 0.84, 0.92) 55 | else: 56 | colors[i * n + j] = (1, 1, 1) 57 | 58 | @ti.kernel 59 | def start(): 60 | offset = ti.Vector([ti.random() - 0.5, 0, ti.random() - 0.5]) 61 | for i,j in ti.ndrange(n, n): 62 | p[i, j] = [i * quad_size - 0.5, 0.6, j * quad_size - 0.5] + offset 63 | v[i, j] = [0, 0, 0] 64 | f[i, j] = g 65 | vertices[i * n + j] = p[i, j] 66 | 67 | @ti.kernel 68 | def update(): 69 | for i,j in ti.ndrange(n, n): 70 | f[i, j] = g 71 | #v[i, j] *= 0.995 72 | for i in range(s[0].length()): 73 | x = s[0, i].a 74 | y = s[0, i].b 75 | nx = s[0, i].c 76 | ny = s[0, i].d 77 | dist_original = s[0, i].e 78 | dist_current = ti.math.length(p[nx, ny] - p[x, y]) 79 | v_relative = (p[nx, ny] - p[x, y]).normalized().dot(v[x, y]) + (p[x, y] - p[nx, ny]).normalized().dot(v[nx, ny]) 80 | force = spring_y * (dist_current / dist_original - 1) 81 | force -= d * v_relative 82 | 83 | f[x, y] += force * (p[nx, ny] - p[x, y]).normalized() 84 | f[nx, ny] += force * (p[x, y] - p[nx, ny]).normalized() 85 | for i,j in ti.ndrange(n, n): 86 | v[i, j] += dt * f[i, j] 87 | p[i, j] += dt * v[i, j] 88 | offset_to_center = p[i ,j] - ball_p[0] 89 | if ti.math.length(offset_to_center) <= ball_r: 90 | normal = offset_to_center.normalized() 91 | v[i, j] -= normal * min(v[i, j].dot(normal), 0) 92 | p[i, j] = ball_p[0] + ball_r * normal 93 | vertices[i * n + j] = p[i, j] 94 | 95 | window = ti.ui.Window("Cloth Simulation", (1024, 1024), vsync = True) 96 | canvas = window.get_canvas() 97 | canvas.set_background_color((0, 0, 0)) 98 | scene = ti.ui.Scene() 99 | camera = ti.ui.make_camera() 100 | camera.position(0, 0, 3) 101 | camera.lookat(0, 0, 0) 102 | scene.set_camera(camera) 103 | t = 0.0 104 | start() 105 | init_cloth() 106 | 107 | while window.running: 108 | if t >= 1.5 : 109 | t = 0 110 | start() 111 | for i in range(substep): 112 | t += dt 113 | update() 114 | scene.point_light(pos = (0, 1, 2), color = (1, 1, 1)) 115 | scene.mesh(vertices, indices = indices, per_vertex_color = colors, two_sided = True) 116 | scene.particles(ball_p, radius = ball_r, color = (0.3, 0.2, 0.5)) 117 | canvas.scene(scene) 118 | window.show() -------------------------------------------------------------------------------- /Lab1 Crash-balls/PythonApplication/PythonApplication.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | ti.init(arch=ti.gpu) 3 | 4 | dt = 1e-2 5 | max_num = 64 6 | num = ti.field(dtype = ti.i32, shape=()) 7 | wind = ti.field(dtype = ti.f32, shape=()) 8 | gravity = ti.field(dtype = ti.f32, shape=()) 9 | damp = ti.field(dtype = ti.f32, shape=()) 10 | update_model = ti.field(dtype = ti.i32, shape=()) 11 | p = ti.Vector.field(2, dtype = ti.f32, shape = max_num) 12 | v = ti.Vector.field(2, dtype = ti.f32, shape = max_num) 13 | f = ti.Vector.field(2, dtype = ti.f32, shape = max_num) 14 | lp = ti.Vector.field(2, dtype = ti.f32, shape = max_num) 15 | lv = ti.Vector.field(2, dtype = ti.f32, shape = max_num) 16 | lf = ti.Vector.field(2, dtype = ti.f32, shape = max_num) 17 | gui = ti.GUI("Crash Balls", (1080, 640), background_color=0xDDDDDD) 18 | gravity[None] = -9.8 19 | damp[None] = 0.15 20 | wind_label = gui.label("Wind") 21 | gravity_label = gui.label("Gravity") 22 | damp_label = gui.label("Damp") 23 | 24 | @ti.kernel 25 | def explicit_update(): 26 | for i in range(num[None]): 27 | lp[i] = p[i] 28 | lv[i] = v[i] 29 | lf[i] = f[i] 30 | f[i] = ti.Vector([wind[None], gravity[None]]) 31 | v[i] += dt * lf[i] 32 | p[i] += dt * lv[i] 33 | 34 | @ti.kernel 35 | def implicit_update(): 36 | for i in range(num[None]): 37 | lp[i] = p[i] 38 | lv[i] = v[i] 39 | lf[i] = f[i] 40 | f[i] = ti.Vector([wind[None], gravity[None]]) 41 | v[i] += dt * f[i] 42 | p[i] += dt * v[i] 43 | 44 | @ti.kernel 45 | def semi_implicit_update(): 46 | for i in range(num[None]): 47 | lp[i] = p[i] 48 | lv[i] = v[i] 49 | lf[i] = f[i] 50 | f[i] = ti.Vector([wind[None], gravity[None]]) 51 | v[i] += dt * lf[i] 52 | p[i] += dt * v[i] 53 | 54 | @ti.kernel 55 | def velocity_welley_update(): 56 | for i in range(num[None]): 57 | lp[i] = p[i] 58 | lv[i] = v[i] 59 | lf[i] = f[i] 60 | f[i] = ti.Vector([wind[None], gravity[None]]) 61 | p[i] += dt * v[i] + f[i] * dt ** 2 / 2 62 | v[i] += dt * (lf[i] + f[i]) / 2 63 | 64 | @ti.kernel 65 | def runge_kutta2(): 66 | for i in range(num[None]): 67 | lp[i] = p[i] 68 | lv[i] = v[i] 69 | lf[i] = f[i] 70 | f[i] = ti.Vector([wind[None], gravity[None]]) 71 | v[i] += dt * lf[i] 72 | p[i] += dt * lv[i] / 2 73 | f[i] = ti.Vector([wind[None], gravity[None]]) 74 | v[i] += dt * lf[i] 75 | p[i] += dt * lv[i] 76 | 77 | @ti.kernel 78 | def update(): 79 | for i in range(num[None]): 80 | for j in ti.static(range(2)): 81 | if p[i][j] < 0: 82 | if ti.math.ceil(-p[i][j]) % 2 == 1: 83 | p[i][j] = ti.math.fract(-p[i][j]) 84 | v[i][j] = - (1 - damp[None]) * v[i][j] 85 | else: 86 | p[i][j] = ti.math.fract(p[i][j]) 87 | v[i][j] = (1 - damp[None]) * v[i][j] 88 | elif p[i][j] > 1: 89 | if ti.math.floor(p[i][j]) % 2 == 1: 90 | p[i][j] = ti.math.fract(-p[i][j]) 91 | v[i][j] = - (1 - damp[None]) * v[i][j] 92 | else: 93 | p[i][j] = ti.math.fract(p[i][j]) 94 | v[i][j] = (1 - damp[None]) * v[i][j] 95 | for i in range(num[None]): 96 | for j in range(i + 1, num[None]): 97 | if ti.math.length(p[i] - p[j])< 1e-2: 98 | l = 0.0 99 | r = dt 100 | while(r - l > 1e-5): 101 | m = (l + r) / 2 102 | iPos = p[i] - m * v[i] 103 | jPos = p[j] - m * v[j] 104 | if ti.math.length(iPos - jPos) < 1e-2: 105 | l = m 106 | else: 107 | r = m 108 | p[i] -= r * v[i] 109 | p[j] -= r * v[j] 110 | iTan = (p[j] - p[i]).normalized() * (p[j] - p[i]).normalized().dot(v[i]) 111 | jTan = (p[i] - p[j]).normalized() * (p[i] - p[j]).normalized().dot(v[j]) 112 | v[i] = v[i] - iTan 113 | v[j] = v[j] - jTan 114 | p[i] += r * v[i] 115 | p[j] += r * v[j] 116 | 117 | 118 | @ti.kernel 119 | def add(xpos:ti.f32, ypos:ti.f32): 120 | if num[None] < max_num: 121 | p[num[None]] = ti.Vector([xpos, ypos]) 122 | v[num[None]] = ti.Vector([0, 0]) 123 | f[num[None]] = ti.Vector([0, 0]) 124 | lp[num[None]] = p[num[None]] 125 | lv[num[None]] = v[num[None]] 126 | lf[num[None]] = f[num[None]] 127 | num[None] += 1 128 | 129 | while gui.running: 130 | if update_model[None] == 0: 131 | explicit_update() 132 | elif update_model[None] == 1: 133 | implicit_update() 134 | elif update_model[None] == 2: 135 | semi_implicit_update() 136 | elif update_model[None] == 3: 137 | velocity_welley_update() 138 | elif update_model[None] == 4: 139 | runge_kutta2() 140 | update() 141 | for e in gui.get_events(ti.GUI.PRESS): 142 | if e.key == 'a' or e.key == ti.GUI.LEFT: 143 | wind[None] -= 0.5 144 | if e.key == 'd' or e.key == ti.GUI.RIGHT: 145 | wind[None] += 0.5 146 | if e.key == 'w': 147 | gravity[None] += 0.5 148 | if e.key == 's': 149 | gravity[None] -= 0.5 150 | if e.key == 'r': 151 | num[None] = 0 152 | if e.key == 'q': 153 | update_model[None] = (update_model[None] + 1) % 5 154 | if e.key == ti.GUI.UP: 155 | damp[None] += 0.05 156 | if e.key == ti.GUI.DOWN: 157 | damp[None] -= 0.05 158 | if e.key == ti.GUI.LMB: 159 | add(e.pos[0], e.pos[1]) 160 | if e.key == ti.GUI.ESCAPE: 161 | gui.running = False 162 | for i in range(num[None]): 163 | gui.circle(p[i],color=0x0,radius=5) 164 | wind_label.value = wind[None] 165 | gravity_label.value = gravity[None] 166 | damp_label.value = damp[None] 167 | if update_model[None] == 0: 168 | gui.text("Explicit Euler",(0,1), 16, 0x00) 169 | elif update_model[None] == 1: 170 | gui.text("Implicit Euler",(0,1), 16, 0x00) 171 | elif update_model[None] == 2: 172 | gui.text("Semi-Implicit Euler",(0,1), 16, 0x00) 173 | elif update_model[None] == 3: 174 | gui.text("Velocity Welley",(0,1), 16, 0x00) 175 | elif update_model[None] == 4: 176 | gui.text("Runge Kutta2",(0,1), 16, 0x00) 177 | gui.show() -------------------------------------------------------------------------------- /Lab8 Stable-fluid/PythonApplication/PythonApplication.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import taichi as ti 3 | ti.init(arch=ti.gpu) 4 | 5 | res = 512 6 | paused = False 7 | dt = 0.03 8 | p_jacobi_iters = 500 9 | f_strength = 10000.0 10 | curl_strength = 0 11 | dye_decay = 1 - 1 / 60 12 | force_radius = res / 2.0 13 | 14 | class Pair: 15 | def __init__(self, cur, nxt): 16 | self.cur = cur 17 | self.nxt = nxt 18 | 19 | def swap(self): 20 | self.cur, self.nxt = self.nxt, self.cur 21 | 22 | _velocities = ti.Vector.field(2, float, shape=(res, res)) 23 | _new_velocities = ti.Vector.field(2, float, shape=(res, res)) 24 | velocity_divs = ti.field(float, shape=(res, res)) 25 | velocity_curls = ti.field(float, shape=(res, res)) 26 | _pressures = ti.field(float, shape=(res, res)) 27 | _new_pressures = ti.field(float, shape=(res, res)) 28 | _dye_buffer = ti.Vector.field(3, float, shape=(res, res)) 29 | _new_dye_buffer = ti.Vector.field(3, float, shape=(res, res)) 30 | velocities_pair = Pair(_velocities, _new_velocities) 31 | pressures_pair = Pair(_pressures, _new_pressures) 32 | dyes_pair = Pair(_dye_buffer, _new_dye_buffer) 33 | 34 | class GenMouseData: 35 | def __init__(self): 36 | self.prev_mouse = None 37 | self.prev_color = None 38 | 39 | def __call__(self, gui): 40 | mouse_data = np.zeros(8, dtype=np.float32) 41 | if gui.is_pressed(ti.GUI.LMB): 42 | mxy = np.array(gui.get_cursor_pos(), dtype=np.float32) * res 43 | if self.prev_mouse is None: 44 | self.prev_mouse = mxy 45 | self.prev_color = (np.random.rand(3) * 0.7) + 0.3 46 | else: 47 | mdir = (mxy - self.prev_mouse) 48 | mdir /= np.linalg.norm(mdir) + 1e-5 49 | mouse_data[0], mouse_data[1] = mdir[0], mdir[1] 50 | mouse_data[2], mouse_data[3] = mxy[0], mxy[1] 51 | mouse_data[4:7] = self.prev_color 52 | self.prev_mouse = mxy 53 | else: 54 | self.prev_mouse = None 55 | self.prev_color = None 56 | return mouse_data 57 | 58 | @ti.func 59 | def lerp(vl, vr, frac): 60 | return vl + frac * (vr - vl) 61 | 62 | @ti.func 63 | def sample(qf, u, v): 64 | I = ti.Vector([int(u), int(v)]) 65 | I = ti.max(0, ti.min(res - 1, I)) 66 | return qf[I] 67 | 68 | @ti.func 69 | def bilerp(vf, p): 70 | u, v = p 71 | s, t = u - 0.5, v - 0.5 72 | iu, iv = ti.floor(s), ti.floor(t) 73 | fu, fv = s - iu, t - iv 74 | a = sample(vf, iu, iv) 75 | b = sample(vf, iu + 1, iv) 76 | c = sample(vf, iu, iv + 1) 77 | d = sample(vf, iu + 1, iv + 1) 78 | return lerp(lerp(a, b, fu), lerp(c, d, fu), fv) 79 | 80 | @ti.func 81 | def backtrace(vf, p, dt_): 82 | v1 = bilerp(vf, p) 83 | p1 = p - 0.5 * dt_ * v1 84 | v2 = bilerp(vf, p1) 85 | p2 = p - 0.75 * dt_ * v2 86 | v3 = bilerp(vf, p2) 87 | p -= dt_ * ((2 / 9) * v1 + (1 / 3) * v2 + (4 / 9) * v3) 88 | return p 89 | 90 | @ti.kernel 91 | def advect(vf: ti.template(), qf: ti.template(), new_qf: ti.template()): 92 | for i, j in vf: 93 | p = ti.Vector([i, j]) + 0.5 94 | p = backtrace(vf, p, dt) 95 | new_qf[i, j] = bilerp(qf, p) * dye_decay 96 | 97 | @ti.kernel 98 | def apply_impulse(vf: ti.template(), dyef: ti.template(), imp_data: ti.types.ndarray()): 99 | g_dir = -ti.Vector([0, 9.8]) * 300 100 | for i, j in vf: 101 | omx, omy = imp_data[2], imp_data[3] 102 | mdir = ti.Vector([imp_data[0], imp_data[1]]) 103 | dx, dy = (i + 0.5 - omx), (j + 0.5 - omy) 104 | d2 = dx * dx + dy * dy 105 | factor = ti.exp(-d2 / force_radius) 106 | 107 | a = dyef[i, j].norm() 108 | vf[i, j] += (mdir * f_strength * factor + g_dir * a / (1 + a)) * dt 109 | 110 | if mdir.norm() > 0.5: 111 | dyef[i, j] += ti.exp(-d2 * (4 / (res / 15) ** 2)) * ti.Vector([imp_data[4], imp_data[5], imp_data[6]]) 112 | 113 | @ti.kernel 114 | def apply_velocity(vf: ti.template()): 115 | for i, j in vf: 116 | vl = sample(vf, i - 1, j) 117 | vr = sample(vf, i + 1, j) 118 | vb = sample(vf, i, j - 1) 119 | vt = sample(vf, i, j + 1) 120 | vc = sample(vf, i, j) 121 | if i == 0: 122 | vl.x = -vc.x 123 | if i == res - 1: 124 | vr.x = -vc.x 125 | if j == 0: 126 | vb.y = -vc.y 127 | if j == res - 1: 128 | vt.y = -vc.y 129 | velocity_divs[i, j] = (vr.x - vl.x + vt.y - vb.y) * 0.5 130 | velocity_curls[i, j] = (vr.y - vl.y - vt.x + vb.x) * 0.5 131 | 132 | @ti.kernel 133 | def enhance_vorticity(vf: ti.template(), cf: ti.template()): 134 | for i, j in vf: 135 | cl = sample(cf, i - 1, j) 136 | cr = sample(cf, i + 1, j) 137 | cb = sample(cf, i, j - 1) 138 | ct = sample(cf, i, j + 1) 139 | cc = sample(cf, i, j) 140 | force = ti.Vector([abs(ct) - abs(cb), abs(cl) - abs(cr)]).normalized(1e-3) 141 | force *= curl_strength * cc 142 | vf[i, j] = ti.min(ti.max(vf[i, j] + force * dt, -1e3), 1e3) 143 | 144 | @ti.kernel 145 | def pressure_jacobi(pf: ti.template(), new_pf: ti.template()): 146 | for i, j in pf: 147 | pl = sample(pf, i - 1, j) 148 | pr = sample(pf, i + 1, j) 149 | pb = sample(pf, i, j - 1) 150 | pt = sample(pf, i, j + 1) 151 | div = velocity_divs[i, j] 152 | new_pf[i, j] = (pl + pr + pb + pt - div) * 0.25 153 | 154 | def solve_pressure_jacobi(): 155 | for _ in range(p_jacobi_iters): 156 | pressure_jacobi(pressures_pair.cur, pressures_pair.nxt) 157 | pressures_pair.swap() 158 | 159 | @ti.kernel 160 | def subtract_gradient(vf: ti.template(), pf: ti.template()): 161 | for i, j in vf: 162 | pl = sample(pf, i - 1, j) 163 | pr = sample(pf, i + 1, j) 164 | pb = sample(pf, i, j - 1) 165 | pt = sample(pf, i, j + 1) 166 | vf[i, j] -= 0.5 * ti.Vector([pr - pl, pt - pb]) 167 | 168 | def update(mouse_data): 169 | #Step 1:Advection 170 | advect(velocities_pair.cur, velocities_pair.cur, velocities_pair.nxt) 171 | advect(velocities_pair.cur, dyes_pair.cur, dyes_pair.nxt) 172 | velocities_pair.swap() 173 | dyes_pair.swap() 174 | #Step 2:Applying forces 175 | apply_impulse(velocities_pair.cur, dyes_pair.cur, mouse_data) 176 | apply_velocity(velocities_pair.cur) 177 | enhance_vorticity(velocities_pair.cur, velocity_curls) 178 | #Step 3:Projection 179 | solve_pressure_jacobi() 180 | subtract_gradient(velocities_pair.cur, pressures_pair.cur) 181 | 182 | gui = ti.GUI("Stable Fluid", (res, res)) 183 | md_gen = GenMouseData() 184 | 185 | while gui.running: 186 | if gui.get_event(ti.GUI.PRESS): 187 | e = gui.event 188 | if e.key == ti.GUI.ESCAPE: 189 | break 190 | elif e.key == "r": 191 | dyes_pair.cur.fill(0) 192 | elif e.key == "p": 193 | paused = not paused 194 | 195 | if not paused: 196 | mouse_data = md_gen(gui) 197 | update(mouse_data) 198 | gui.set_image(dyes_pair.cur) 199 | gui.show() -------------------------------------------------------------------------------- /Lab7 Path-tracing/PythonApplication/head.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import taichi as ti 3 | 4 | PI = 3.14159265 5 | 6 | @ti.func 7 | def rand3(): 8 | return ti.Vector([ti.random(), ti.random(), ti.random()]) 9 | 10 | @ti.func 11 | def random_in_unit_sphere(): 12 | p = 2.0 * rand3() - ti.Vector([1, 1, 1]) 13 | while p.norm() >= 1.0: 14 | p = 2.0 * rand3() - ti.Vector([1, 1, 1]) 15 | return p 16 | 17 | @ti.func 18 | def random_unit_vector(): 19 | return random_in_unit_sphere().normalized() 20 | 21 | @ti.func 22 | def to_light_source(hit_point, light_source): 23 | return light_source - hit_point 24 | 25 | @ti.func 26 | def reflect(v, normal): 27 | return v - 2 * v.dot(normal) * normal 28 | 29 | @ti.func 30 | def refract(uv, n, etai_over_etat): 31 | cos_theta = min(n.dot(-uv), 1.0) 32 | r_out_perp = etai_over_etat * (uv + cos_theta * n) 33 | r_out_parallel = -ti.sqrt(abs(1.0 - r_out_perp.dot(r_out_perp))) * n 34 | return r_out_perp + r_out_parallel 35 | 36 | @ti.func 37 | def reflectance(cosine, ref_idx): 38 | # Use Schlick's approximation for reflectance. 39 | r0 = (1 - ref_idx) / (1 + ref_idx) 40 | r0 = r0 * r0 41 | return r0 + (1 - r0) * pow((1 - cosine), 5) 42 | 43 | @ti.data_oriented 44 | class Ray: 45 | def __init__(self, origin, direction): 46 | self.origin = origin 47 | self.direction = direction 48 | def at(self, t): 49 | return self.origin + t * self.direction 50 | 51 | @ti.data_oriented 52 | class Sphere: 53 | def __init__(self, center, radius, material, color): 54 | self.center = center 55 | self.radius = radius 56 | self.material = material 57 | self.color = color 58 | 59 | @ti.func 60 | def hit(self, ray, t_min=0.001, t_max=10e8): 61 | oc = ray.origin - self.center 62 | a = ray.direction.dot(ray.direction) 63 | b = 2.0 * oc.dot(ray.direction) 64 | c = oc.dot(oc) - self.radius * self.radius 65 | discriminant = b * b - 4 * a * c 66 | is_hit = False 67 | front_face = False 68 | root = 0.0 69 | hit_point = ti.Vector([0.0, 0.0, 0.0]) 70 | hit_point_normal = ti.Vector([0.0, 0.0, 0.0]) 71 | if discriminant > 0: 72 | sqrtd = ti.sqrt(discriminant) 73 | root = (-b - sqrtd) / (2 * a) 74 | if root < t_min or root > t_max: 75 | root = (-b + sqrtd) / (2 * a) 76 | if root >= t_min and root <= t_max: 77 | is_hit = True 78 | else: 79 | is_hit = True 80 | if is_hit: 81 | hit_point = ray.at(root) 82 | hit_point_normal = (hit_point - self.center) / self.radius 83 | # Check which side does the ray hit, we set the hit point normals always point outward from the surface 84 | if ray.direction.dot(hit_point_normal) < 0: 85 | front_face = True 86 | else: 87 | hit_point_normal = -hit_point_normal 88 | return is_hit, root, hit_point, hit_point_normal, front_face, self.material, self.color 89 | 90 | @ti.data_oriented 91 | class Hittable_list: 92 | def __init__(self): 93 | self.objects = [] 94 | def add(self, obj): 95 | self.objects.append(obj) 96 | def clear(self): 97 | self.objects = [] 98 | 99 | @ti.func 100 | def hit(self, ray, t_min=0.001, t_max=10e8): 101 | closest_t = t_max 102 | is_hit = False 103 | front_face = False 104 | hit_point = ti.Vector([0.0, 0.0, 0.0]) 105 | hit_point_normal = ti.Vector([0.0, 0.0, 0.0]) 106 | color = ti.Vector([0.0, 0.0, 0.0]) 107 | material = 1 108 | for index in ti.static(range(len(self.objects))): 109 | is_hit_tmp, root_tmp, hit_point_tmp, hit_point_normal_tmp, front_face_tmp, material_tmp, color_tmp = self.objects[index].hit(ray, t_min, closest_t) 110 | if is_hit_tmp: 111 | closest_t = root_tmp 112 | is_hit = is_hit_tmp 113 | hit_point = hit_point_tmp 114 | hit_point_normal = hit_point_normal_tmp 115 | front_face = front_face_tmp 116 | material = material_tmp 117 | color = color_tmp 118 | return is_hit, hit_point, hit_point_normal, front_face, material, color 119 | 120 | @ti.func 121 | def hit_shadow(self, ray, t_min=0.001, t_max=10e8): 122 | is_hit_source = False 123 | is_hit_source_temp = False 124 | hitted_dielectric_num = 0 125 | is_hitted_non_dielectric = False 126 | # Compute the t_max to light source 127 | is_hit_tmp, root_light_source, hit_point_tmp, hit_point_normal_tmp, front_face_tmp, material_tmp, color_tmp = \ 128 | self.objects[0].hit(ray, t_min) 129 | for index in ti.static(range(len(self.objects))): 130 | is_hit_tmp, root_tmp, hit_point_tmp, hit_point_normal_tmp, front_face_tmp, material_tmp, color_tmp = self.objects[index].hit(ray, t_min, root_light_source) 131 | if is_hit_tmp: 132 | if material_tmp != 3 and material_tmp != 0: 133 | is_hitted_non_dielectric = True 134 | if material_tmp == 3: 135 | hitted_dielectric_num += 1 136 | if material_tmp == 0: 137 | is_hit_source_temp = True 138 | if is_hit_source_temp and (not is_hitted_non_dielectric) and hitted_dielectric_num == 0: 139 | is_hit_source = True 140 | return is_hit_source, hitted_dielectric_num, is_hitted_non_dielectric 141 | 142 | 143 | @ti.data_oriented 144 | class Camera: 145 | def __init__(self, fov=60, aspect_ratio=1.0): 146 | # Camera parameters 147 | self.lookfrom = ti.Vector.field(3, dtype=ti.f32, shape=()) 148 | self.lookat = ti.Vector.field(3, dtype=ti.f32, shape=()) 149 | self.vup = ti.Vector.field(3, dtype=ti.f32, shape=()) 150 | self.fov = fov 151 | self.aspect_ratio = aspect_ratio 152 | 153 | self.cam_lower_left_corner = ti.Vector.field(3, dtype=ti.f32, shape=()) 154 | self.cam_horizontal = ti.Vector.field(3, dtype=ti.f32, shape=()) 155 | self.cam_vertical = ti.Vector.field(3, dtype=ti.f32, shape=()) 156 | self.cam_origin = ti.Vector.field(3, dtype=ti.f32, shape=()) 157 | self.reset() 158 | 159 | @ti.kernel 160 | def reset(self): 161 | self.lookfrom[None] = [0.0, 1.0, -5.0] 162 | self.lookat[None] = [0.0, 1.0, -1.0] 163 | self.vup[None] = [0.0, 1.0, 0.0] 164 | theta = self.fov * (PI / 180.0) 165 | half_height = ti.tan(theta / 2.0) 166 | half_width = self.aspect_ratio * half_height 167 | self.cam_origin[None] = self.lookfrom[None] 168 | w = (self.lookfrom[None] - self.lookat[None]).normalized() 169 | u = (self.vup[None].cross(w)).normalized() 170 | v = w.cross(u) 171 | self.cam_lower_left_corner[None] = ti.Vector([-half_width, -half_height, -1.0]) 172 | self.cam_lower_left_corner[None] = self.cam_origin[None] - half_width * u - half_height * v - w 173 | self.cam_horizontal[None] = 2 * half_width * u 174 | self.cam_vertical[None] = 2 * half_height * v 175 | 176 | @ti.func 177 | def get_ray(self, u, v): 178 | return Ray(self.cam_origin[None], self.cam_lower_left_corner[None] + u * self.cam_horizontal[None] + v * self.cam_vertical[None] - self.cam_origin[None]) -------------------------------------------------------------------------------- /Lab5 Water-simulation/PythonApplication/PythonApplication.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numpy as np 3 | import taichi as ti 4 | 5 | ti.init(ti.gpu) 6 | 7 | screen_res = (800, 800) 8 | screen_to_world_ratio = 20.0 9 | boundary = (screen_res[0]/screen_to_world_ratio, screen_res[1]/screen_to_world_ratio, screen_res[0]/screen_to_world_ratio) 10 | cell_size = 2.51 11 | cell_recpr = 1.0 / cell_size 12 | 13 | def round_up(f, s): 14 | return (math.floor(f * cell_recpr / s) + 1) * s 15 | 16 | grid_size = (round_up(boundary[0], 1), round_up(boundary[1], 1), round_up(boundary[2], 1)) 17 | 18 | dim = 3 19 | bg_color = 0x112f41 20 | particle_color = 0x068587 21 | boundary_color = 0xebaca2 22 | num_particles_x = 10 23 | num_particles = 10000 24 | max_num_particles_per_cell = 1000 25 | max_num_neighbors = 1000 26 | time_delta = 1.0 / 20.0 27 | epsilon = 1e-5 28 | particle_radius = 3.0 29 | particle_radius_in_world = particle_radius / screen_to_world_ratio 30 | 31 | h = 1.1 32 | mass = 1.0 33 | rho0 = 1.0 34 | lambda_epsilon = 100.0 35 | pbf_num_iters = 5 36 | corr_deltaQ_coeff = 0.3 37 | corrK = 0.001 38 | neighbor_radius = h * 1.05 39 | 40 | poly6_factor = 315.0 / 64.0 / math.pi 41 | spiky_grad_factor = -45.0 / math.pi 42 | 43 | old_positions = ti.Vector.field(dim, float) 44 | positions = ti.Vector.field(dim, float) 45 | velocities = ti.Vector.field(dim, float) 46 | grid_num_particles = ti.field(int) 47 | particle_num_neighbors = ti.field(int) 48 | particle_neighbors = ti.field(int) 49 | lambdas = ti.field(float) 50 | position_deltas = ti.Vector.field(dim, float) 51 | 52 | ti.root.dense(ti.i, num_particles).place(old_positions, positions, velocities) 53 | grid_snode = ti.root.dense(ti.ijk, grid_size) 54 | grid_snode.place(grid_num_particles) 55 | 56 | grid2particles = ti.field(int, (grid_size + (max_num_particles_per_cell,))) 57 | nb_node = ti.root.dense(ti.i, num_particles) 58 | nb_node.place(particle_num_neighbors) 59 | nb_node.dense(ti.j, max_num_neighbors).place(particle_neighbors) 60 | ti.root.dense(ti.i, num_particles).place(lambdas, position_deltas) 61 | 62 | @ti.kernel 63 | def init(): 64 | init_pos = ti.Vector([10.0,10.0,10.0]) 65 | cube_size = 20 66 | spacing = 1 67 | num_per_row = (int) (cube_size // spacing) + 1 68 | num_per_floor = num_per_row * num_per_row 69 | for i in range(num_particles): 70 | floor = i // (num_per_floor) 71 | row = (i % num_per_floor) // num_per_row 72 | col = (i % num_per_floor) % num_per_row 73 | positions[i] = ti.Vector([col*spacing, floor*spacing, row*spacing]) + init_pos 74 | 75 | @ti.func 76 | def poly6_value(s, h): 77 | result = 0.0 78 | if 0 < s and s < h: 79 | x = (h * h - s * s) / (h * h * h) 80 | result = poly6_factor * x * x * x 81 | return result 82 | 83 | @ti.func 84 | def spiky_gradient(r, h): 85 | result = ti.Vector([0.0, 0.0, 0.0]) 86 | r_len = r.norm() 87 | if 0 < r_len and r_len < h: 88 | x = (h - r_len) / (h * h * h) 89 | g_factor = spiky_grad_factor * x * x 90 | result = r * g_factor / r_len 91 | return result 92 | 93 | @ti.func 94 | def compute_scorr(pos_ji): 95 | x = poly6_value(pos_ji.norm(), h) / poly6_value(corr_deltaQ_coeff * h, h) 96 | x = x * x 97 | x = x * x 98 | return (-corrK) * x 99 | 100 | 101 | @ti.func 102 | def get_cell(pos): 103 | return int(pos * cell_recpr) 104 | 105 | @ti.func 106 | def is_in_grid(c): 107 | return 0 <= c[0] and c[0] < grid_size[0] and 0 <= c[1] and c[ 108 | 1] < grid_size[1] 109 | 110 | @ti.func 111 | def confine_position_to_boundary(p): 112 | bmin = particle_radius_in_world 113 | bmax = ti.Vector([boundary[0], boundary[1], boundary[2]]) - particle_radius_in_world 114 | for i in ti.static(range(dim)): 115 | if p[i] <= bmin: 116 | p[i] = bmin + epsilon * ti.random() 117 | elif bmax[i] <= p[i]: 118 | p[i] = bmax[i] - epsilon * ti.random() 119 | return p 120 | 121 | @ti.kernel 122 | def prestep(): 123 | for i in positions: 124 | old_positions[i] = positions[i] 125 | for i in positions: 126 | g = ti.Vector([0.0, -10.0, 0.0]) 127 | pos, vel = positions[i], velocities[i] 128 | vel += g * time_delta 129 | pos += vel * time_delta 130 | positions[i] = confine_position_to_boundary(pos) 131 | 132 | for i in ti.grouped(grid_num_particles): 133 | grid_num_particles[i] = 0 134 | for i in ti.grouped(particle_neighbors): 135 | particle_neighbors[i] = -1 136 | 137 | for p_i in positions: 138 | cell = get_cell(positions[p_i]) 139 | offs = ti.atomic_add(grid_num_particles[cell], 1) 140 | grid2particles[cell, offs] = p_i 141 | 142 | for p_i in positions: 143 | pos_i = positions[p_i] 144 | cell = get_cell(pos_i) 145 | nb_i = 0 146 | for offs in ti.static(ti.grouped(ti.ndrange((-1, 2), (-1, 2),(-1, 2)))): 147 | cell_to_check = cell + offs 148 | if is_in_grid(cell_to_check): 149 | for j in range(grid_num_particles[cell_to_check]): 150 | p_j = grid2particles[cell_to_check, j] 151 | if nb_i < max_num_neighbors and p_j != p_i and (pos_i - positions[p_j]).norm() < neighbor_radius: 152 | particle_neighbors[p_i, nb_i] = p_j 153 | nb_i += 1 154 | particle_num_neighbors[p_i] = nb_i 155 | 156 | 157 | @ti.kernel 158 | def substep(): 159 | for p_i in positions: 160 | pos_i = positions[p_i] 161 | grad_i = ti.Vector([0.0, 0.0, 0.0]) 162 | sum_gradient_sqr = 0.0 163 | density_constraint = 0.0 164 | 165 | for j in range(particle_num_neighbors[p_i]): 166 | p_j = particle_neighbors[p_i, j] 167 | if p_j < 0: 168 | break 169 | pos_ji = pos_i - positions[p_j] 170 | grad_j = spiky_gradient(pos_ji, h) 171 | grad_i += grad_j 172 | sum_gradient_sqr += grad_j.dot(grad_j) 173 | density_constraint += poly6_value(pos_ji.norm(), h) 174 | 175 | density_constraint = (mass * density_constraint / rho0) - 1.0 176 | sum_gradient_sqr += grad_i.dot(grad_i) 177 | lambdas[p_i] = (-density_constraint) / (sum_gradient_sqr + lambda_epsilon) 178 | 179 | for p_i in positions: 180 | pos_i = positions[p_i] 181 | lambda_i = lambdas[p_i] 182 | pos_delta_i = ti.Vector([0.0, 0.0, 0.0]) 183 | 184 | for j in range(particle_num_neighbors[p_i]): 185 | p_j = particle_neighbors[p_i, j] 186 | if p_j < 0: 187 | break 188 | lambda_j = lambdas[p_j] 189 | pos_ji = pos_i - positions[p_j] 190 | scorr_ij = compute_scorr(pos_ji) 191 | pos_delta_i += (lambda_i + lambda_j + scorr_ij) * spiky_gradient(pos_ji, h) 192 | 193 | pos_delta_i /= rho0 194 | position_deltas[p_i] = pos_delta_i 195 | 196 | for i in positions: 197 | positions[i] += position_deltas[i] 198 | 199 | @ti.kernel 200 | def endstep(): 201 | for i in positions: 202 | pos = positions[i] 203 | positions[i] = confine_position_to_boundary(pos) 204 | 205 | for i in positions: 206 | velocities[i] = (positions[i] - old_positions[i]) / time_delta 207 | 208 | def update(): 209 | prestep() 210 | for cnt in range(pbf_num_iters): 211 | substep() 212 | endstep() 213 | 214 | def T(a): 215 | if dim == 2: 216 | return a 217 | phi, theta = np.radians(28), np.radians(32) 218 | a = a - 0.5 219 | x, y, z = a[:, 0], a[:, 1], a[:, 2] 220 | c, s = np.cos(phi), np.sin(phi) 221 | C, S = np.cos(theta), np.sin(theta) 222 | x, z = x * c + z * s, z * c - x * s 223 | u, v = x, y * C + z * S 224 | return np.array([u, v]).swapaxes(0, 1) + 25 225 | 226 | init() 227 | gui = ti.GUI("Water-simulation", (648, 648), background_color = 0xffffff) 228 | while gui.running and not gui.get_event(gui.ESCAPE): 229 | update() 230 | pos = positions.to_numpy() 231 | gui.circles(T(pos)/100.0, radius=3, color=0x66ccff) 232 | gui.show() 233 | -------------------------------------------------------------------------------- /Lab4 Dominoes/PythonApplication/PythonApplication.py: -------------------------------------------------------------------------------- 1 | import taichi as ti 2 | from taichi.math import * 3 | ti.init(ti.gpu) 4 | 5 | dt = 1e-2 6 | vertices = ti.Vector.field(3, dtype = float, shape = 8) 7 | indices = ti.field(ti.i32, shape = 13 * 36) 8 | 9 | vertices[0] = (-0.05,-0.1,0.1);vertices[1] = (-0.05,-0.1,-0.1);vertices[2] = (0.05,-0.1,-0.1);vertices[3] = (0.05,-0.1,0.1) 10 | vertices[4] = (-0.05,0.1,0.1);vertices[5] = (-0.05,0.1,-0.1);vertices[6] = (0.05,0.1,-0.1);vertices[7] = (0.05,0.1,0.1) 11 | 12 | indices[0] = 0;indices[1] = 1;indices[2] = 2;indices[3] = 0;indices[4] = 2;indices[5] = 3;indices[6] = 0;indices[7] = 1;indices[8] = 4; 13 | indices[9] = 1;indices[10] = 4;indices[11] = 5;indices[12] = 1;indices[13] = 2;indices[14] = 5;indices[15] = 2;indices[16] = 5;indices[17] = 6 14 | indices[18] = 2;indices[19] = 3;indices[20] = 6;indices[21] = 3;indices[22] = 6;indices[23] = 7;indices[24] = 0;indices[25] = 3;indices[26] = 4 15 | indices[27] = 3;indices[28] = 4;indices[29] = 7;indices[30] = 4;indices[31] = 5;indices[32] = 7;indices[33] = 5;indices[34] = 6;indices[35] = 7 16 | 17 | p = ti.Vector.field(3, dtype = float, shape = 8 * 13) 18 | p0 = ti.Vector.field(3, dtype = float, shape = 8) 19 | p1 = ti.Vector.field(3, dtype = float, shape = 8) 20 | p2 = ti.Vector.field(3, dtype = float, shape = 8) 21 | p3 = ti.Vector.field(3, dtype = float, shape = 8) 22 | p4 = ti.Vector.field(3, dtype = float, shape = 8) 23 | p5 = ti.Vector.field(3, dtype = float, shape = 8) 24 | p6 = ti.Vector.field(3, dtype = float, shape = 8) 25 | p7 = ti.Vector.field(3, dtype = float, shape = 8) 26 | p8 = ti.Vector.field(3, dtype = float, shape = 8) 27 | p9 = ti.Vector.field(3, dtype = float, shape = 8) 28 | p10 = ti.Vector.field(3, dtype = float, shape = 8) 29 | p11 = ti.Vector.field(3, dtype = float, shape = 8) 30 | p12 = ti.Vector.field(3, dtype = float, shape = 8) 31 | w = ti.field(ti.f32, shape = 13) 32 | theta = ti.field(ti.f32, shape = 13) 33 | 34 | w[0] = 1e-3 35 | 36 | @ti.kernel 37 | def init(): 38 | for i in range(36, 13 * 36): 39 | indices[i] = indices[i % 36] + i // 36 * 8 40 | 41 | for j in range(8): 42 | p[j] = p0[j] = vertices[j] + ti.Vector((-0.2, 0, - 0.2 - 0.1 * sqrt(3))) 43 | p[j + 8] = p1[j] = vertices[j] + ti.Vector((0, 0, - 0.2 - 0.1 * sqrt(3))) 44 | p[j + 16] = p2[j] = vertices[j] + ti.Vector((0.2, 0, - 0.2 - 0.1 * sqrt(3))) 45 | p[j + 24] = p3[j] = ti.Matrix([[cos(pi/3),0,-sin(pi/3)],[0,1,0],[sin(pi/3),0,cos(pi/3)]]) @ vertices[j] + ti.Vector((0.2 + 0.1 * sqrt(3), 0, - 0.1 - 0.1 * sqrt(3))) 46 | p[j + 32] = p4[j] = ti.Matrix([[cos(2*pi/3),0,-sin(2*pi/3)],[0,1,0],[sin(2*pi/3),0,cos(2*pi/3)]]) @ vertices[j] + ti.Vector((0.2 + 0.1 * sqrt(3), 0, - 0.1)) 47 | p[j + 40] = p5[j] = ti.Matrix([[cos(pi),0,-sin(pi)],[0,1,0],[sin(pi),0,cos(pi)]]) @ vertices[j] + ti.Vector((0.2, 0, 0)) 48 | p[j + 48] = p6[j] = ti.Matrix([[cos(pi),0,-sin(pi)],[0,1,0],[sin(pi),0,cos(pi)]]) @ vertices[j] 49 | p[j + 56] = p7[j] = ti.Matrix([[cos(pi),0,-sin(pi)],[0,1,0],[sin(pi),0,cos(pi)]]) @ vertices[j] + ti.Vector((-0.2, 0, 0)) 50 | p[j + 64] = p8[j] = ti.Matrix([[cos(2*pi/3),0,-sin(2*pi/3)],[0,1,0],[sin(2*pi/3),0,cos(2*pi/3)]]) @ vertices[j] + ti.Vector((- 0.2 - 0.1 * sqrt(3), 0, 0.1)) 51 | p[j + 72] = p9[j] = ti.Matrix([[cos(pi/3),0,-sin(pi/3)],[0,1,0],[sin(pi/3),0,cos(pi/3)]]) @ vertices[j] + ti.Vector((- 0.2 - 0.1 * sqrt(3), 0, 0.1 + 0.1 * sqrt(3))) 52 | p[j + 80] = p10[j] = vertices[j] + ti.Vector((- 0.2, 0, 0.2 + 0.1 * sqrt(3))) 53 | p[j + 88] = p11[j] = vertices[j] + ti.Vector((0, 0, 0.2 + 0.1 * sqrt(3))) 54 | p[j + 96] = p12[j] = vertices[j] + ti.Vector((0.2, 0, 0.2 + 0.1 * sqrt(3))) 55 | 56 | @ti.func 57 | def rotate(x:vec3, o:vec3, y:vec3, theta:ti.f32) -> vec3: 58 | left = (x - o).normalized() 59 | up = -(x - o).cross(y - o).normalized() 60 | return o + (x - o).norm() * sin(theta * dt) * up + (x - o).norm() * cos(theta * dt) * left 61 | 62 | @ti.kernel 63 | def update(): 64 | p0[0] = rotate(p0[0],p0[3],p0[2],w[0]);p0[1] = p0[0] + p0[2] - p0[3];p0[4] = rotate(p0[4],p0[3],p0[2],w[0]) 65 | p0[5] = p0[4] + p0[2] - p0[3];p0[7] = rotate(p0[7],p0[3],p0[2],w[0]);p0[6] = p0[7] + p0[2] - p0[3] 66 | 67 | p1[0] = rotate(p1[0],p1[3],p1[2],w[1]);p1[1] = p1[0] + p1[2] - p1[3];p1[4] = rotate(p1[4],p1[3],p1[2],w[1]) 68 | p1[5] = p1[4] + p1[2] - p1[3];p1[7] = rotate(p1[7],p1[3],p1[2],w[1]);p1[6] = p1[7] + p1[2] - p1[3] 69 | 70 | p2[0] = rotate(p2[0],p2[3],p2[2],w[2]);p2[1] = p2[0] + p2[2] - p2[3];p2[4] = rotate(p2[4],p2[3],p2[2],w[2]) 71 | p2[5] = p2[4] + p2[2] - p2[3];p2[7] = rotate(p2[7],p2[3],p2[2],w[2]);p2[6] = p2[7] + p2[2] - p2[3] 72 | 73 | p3[0] = rotate(p3[0],p3[3],p3[2],w[3]);p3[1] = p3[0] + p3[2] - p3[3];p3[4] = rotate(p3[4],p3[3],p3[2],w[3]) 74 | p3[5] = p3[4] + p3[2] - p3[3];p3[7] = rotate(p3[7],p3[3],p3[2],w[3]);p3[6] = p3[7] + p3[2] - p3[3] 75 | 76 | p4[0] = rotate(p4[0],p4[3],p4[2],w[4]);p4[1] = p4[0] + p4[2] - p4[3];p4[4] = rotate(p4[4],p4[3],p4[2],w[4]) 77 | p4[5] = p4[4] + p4[2] - p4[3];p4[7] = rotate(p4[7],p4[3],p4[2],w[4]);p4[6] = p4[7] + p4[2] - p4[3] 78 | 79 | p5[0] = rotate(p5[0],p5[3],p5[2],w[5]);p5[1] = p5[0] + p5[2] - p5[3];p5[4] = rotate(p5[4],p5[3],p5[2],w[5]) 80 | p5[5] = p5[4] + p5[2] - p5[3];p5[7] = rotate(p5[7],p5[3],p5[2],w[5]);p5[6] = p5[7] + p5[2] - p5[3] 81 | 82 | p6[0] = rotate(p6[0],p6[3],p6[2],w[6]);p6[1] = p6[0] + p6[2] - p6[3];p6[4] = rotate(p6[4],p6[3],p6[2],w[6]) 83 | p6[5] = p6[4] + p6[2] - p6[3];p6[7] = rotate(p6[7],p6[3],p6[2],w[6]);p6[6] = p6[7] + p6[2] - p6[3] 84 | 85 | p7[0] = rotate(p7[0],p7[3],p7[2],w[7]);p7[1] = p7[0] + p7[2] - p7[3];p7[4] = rotate(p7[4],p7[3],p7[2],w[7]) 86 | p7[5] = p7[4] + p7[2] - p7[3];p7[7] = rotate(p7[7],p7[3],p7[2],w[7]);p7[6] = p7[7] + p7[2] - p7[3] 87 | 88 | p8[0] = rotate(p8[0],p8[3],p8[2],w[8]);p8[1] = p8[0] + p8[2] - p8[3];p8[4] = rotate(p8[4],p8[3],p8[2],w[8]) 89 | p8[5] = p8[4] + p8[2] - p8[3];p8[7] = rotate(p8[7],p8[3],p8[2],w[8]);p8[6] = p8[7] + p8[2] - p8[3] 90 | 91 | p9[0] = rotate(p9[0],p9[3],p9[2],w[9]);p9[1] = p9[0] + p9[2] - p9[3];p9[4] = rotate(p9[4],p9[3],p9[2],w[9]) 92 | p9[5] = p9[4] + p9[2] - p9[3];p9[7] = rotate(p9[7],p9[3],p9[2],w[9]);p9[6] = p9[7] + p9[2] - p9[3] 93 | 94 | p10[0] = rotate(p10[0],p10[3],p10[2],w[10]);p10[1] = p10[0] + p10[2] - p10[3];p10[4] = rotate(p10[4],p10[3],p10[2],w[10]) 95 | p10[5] = p10[4] + p10[2] - p10[3];p10[7] = rotate(p10[7],p10[3],p10[2],w[10]);p10[6] = p10[7] + p10[2] - p10[3] 96 | 97 | p11[0] = rotate(p11[0],p11[3],p11[2],w[11]);p11[1] = p11[0] + p11[2] - p11[3];p11[4] = rotate(p11[4],p11[3],p11[2],w[11]) 98 | p11[5] = p11[4] + p11[2] - p11[3];p11[7] = rotate(p11[7],p11[3],p11[2],w[11]);p11[6] = p11[7] + p11[2] - p11[3] 99 | 100 | p12[0] = rotate(p12[0],p12[3],p12[2],w[12]);p12[1] = p12[0] + p12[2] - p12[3];p12[4] = rotate(p12[4],p12[3],p12[2],w[12]) 101 | p12[5] = p12[4] + p12[2] - p12[3];p12[7] = rotate(p12[7],p12[3],p12[2],w[12]);p12[6] = p12[7] + p12[2] - p12[3] 102 | 103 | w[0] = w[0] + (p0[3] - p0[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 104 | w[1] = w[1] + (p1[3] - p1[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 105 | w[2] = w[2] + (p2[3] - p2[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 106 | w[3] = w[3] + (p3[3] - p3[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 107 | w[4] = w[4] + (p4[3] - p4[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 108 | w[5] = w[5] + (p5[3] - p5[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 109 | w[6] = w[6] + (p6[3] - p6[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 110 | w[7] = w[7] + (p7[3] - p7[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 111 | w[8] = w[8] + (p8[3] - p8[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 112 | w[9] = w[9] + (p9[3] - p9[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 113 | w[10] = w[10] + (p10[3] - p10[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 114 | w[11] = w[11] + (p11[3] - p11[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 115 | w[12] = w[12] + (p12[3] - p12[7]).normalized().cross(ti.Vector((0, -1, 0))).norm() 116 | 117 | if (p1[5] - p1[0]).cross(p1[1] - p1[0]).dot(rotate(p0[7],p0[3],p0[2],w[0]) - p1[0]) < 0 or (p1[5] - p1[0]).cross(p1[1] - p1[0]).dot(p0[3] - p1[0]) < 0: 118 | w[1] = w[1] + w[0] * (p0[1] - p0[0]).normalized().dot((p1[1] - p1[0]).normalized()) 119 | w[0] = 0 120 | 121 | if (p2[5] - p2[0]).cross(p2[1] - p2[0]).dot(rotate(p1[7],p1[3],p1[2],w[1]) - p2[0]) < 0 or (p2[5] - p2[0]).cross(p2[1] - p2[0]).dot(p1[3] - p2[0]) < 0: 122 | w[2] = w[2] + w[1] * (p1[1] - p1[0]).normalized().dot((p2[1] - p2[0]).normalized()) 123 | w[1] = 0 124 | 125 | if (p3[5] - p3[0]).cross(p3[1] - p3[0]).dot(rotate(p2[7],p2[3],p2[2],w[2]) - p3[0]) < 0 or (p3[5] - p3[0]).cross(p2[1] - p2[0]).dot(p1[3] - p2[0]) < 0: 126 | w[3] = w[3] + w[2] * (p2[1] - p2[0]).normalized().dot((p3[1] - p3[0]).normalized()) 127 | w[2] = 0 128 | 129 | if (p4[5] - p4[0]).cross(p4[1] - p4[0]).dot(rotate(p3[7],p3[3],p3[2],w[3]) - p4[0]) < 0 or (p4[5] - p4[0]).cross(p4[1] - p4[0]).dot(p3[3] - p4[0]) < 0: 130 | w[4] = w[4] + w[3] * (p3[1] - p3[0]).normalized().dot((p4[1] - p4[0]).normalized()) 131 | w[3] = 0 132 | 133 | if (p5[5] - p5[0]).cross(p5[1] - p5[0]).dot(rotate(p4[7],p4[3],p4[2],w[4]) - p5[0]) < 0 or (p5[5] - p5[0]).cross(p5[1] - p5[0]).dot(p4[3] - p5[0]) < 0: 134 | w[5] = w[5] + w[4] * (p4[1] - p4[0]).normalized().dot((p5[1] - p5[0]).normalized()) 135 | w[4] = 0 136 | 137 | if (p6[5] - p6[0]).cross(p6[1] - p6[0]).dot(rotate(p5[7],p5[3],p5[2],w[5]) - p6[0]) < 0 or (p6[5] - p6[0]).cross(p6[1] - p6[0]).dot(p5[3] - p6[0]) < 0: 138 | w[6] = w[6] + w[5] * (p5[1] - p5[0]).normalized().dot((p6[1] - p6[0]).normalized()) 139 | w[5] = 0 140 | 141 | if (p7[5] - p7[0]).cross(p7[1] - p7[0]).dot(rotate(p6[7],p6[3],p6[2],w[6]) - p7[0]) < 0 or (p7[5] - p7[0]).cross(p7[1] - p7[0]).dot(p6[3] - p7[0]) < 0: 142 | w[7] = w[7] + w[6] * (p6[1] - p6[0]).normalized().dot((p7[1] - p7[0]).normalized()) 143 | w[6] = 0 144 | 145 | if (p8[5] - p8[0]).cross(p8[1] - p8[0]).dot(rotate(p7[7],p7[3],p7[2],w[7]) + p7[2] - p7[3] - p8[0]) < 0 or (p8[5] - p8[0]).cross(p8[1] - p8[0]).dot(p7[2] - p8[0]) < 0: 146 | w[8] = w[8] + w[7] * (p7[1] - p7[0]).normalized().dot((p8[1] - p8[0]).normalized()) 147 | w[7] = 0 148 | 149 | if (p9[5] - p9[0]).cross(p9[1] - p9[0]).dot(rotate(p8[7],p8[3],p8[2],w[8]) + p8[2] - p8[3] - p9[0]) < 0 or (p9[5] - p9[0]).cross(p9[1] - p9[0]).dot(p8[2] - p9[0]) < 0: 150 | w[9] = w[9] + w[8] * (p8[1] - p8[0]).normalized().dot((p9[1] - p9[0]).normalized()) 151 | w[8] = 0 152 | 153 | if (p10[5] - p10[0]).cross(p10[1] - p10[0]).dot(rotate(p9[7],p9[3],p9[2],w[9]) + p9[2] - p9[3] - p10[0]) < 0 or (p10[5] - p10[0]).cross(p10[1] - p10[0]).dot(p9[2] - p10[0]) < 0: 154 | w[10] = w[10] + w[9] * (p9[1] - p9[0]).normalized().dot((p10[1] - p10[0]).normalized()) 155 | w[9] = 0 156 | 157 | if (p11[5] - p11[0]).cross(p11[1] - p11[0]).dot(rotate(p10[7],p10[3],p10[2],w[10]) - p11[0]) < 0 or (p11[5] - p11[0]).cross(p11[1] - p11[0]).dot(p10[3] - p11[0]) < 0: 158 | w[11] = w[11] + w[10] * (p10[1] - p10[0]).normalized().dot((p11[1] - p11[0]).normalized()) 159 | w[10] = 0 160 | 161 | if (p12[5] - p12[0]).cross(p12[1] - p12[0]).dot(rotate(p11[7],p11[3],p11[2],w[11]) - p12[0]) < 0 or (p12[5] - p12[0]).cross(p12[1] - p12[0]).dot(p11[3] - p12[0]) < 0: 162 | w[12] = w[12] + w[11] * (p11[1] - p11[0]).normalized().dot((p12[1] - p12[0]).normalized()) 163 | w[11] = 0 164 | 165 | if rotate(p12[7],p12[3],p12[2],w[12]).y < 0: 166 | w[12] = 0 167 | 168 | for i in range(8): 169 | p[i] = p0[i] 170 | p[8 + i] = p1[i] 171 | p[16 + i] = p2[i] 172 | p[24 + i] = p3[i] 173 | p[32 + i] = p4[i] 174 | p[40 + i] = p5[i] 175 | p[48 + i] = p6[i] 176 | p[56 + i] = p7[i] 177 | p[64 + i] = p8[i] 178 | p[72 + i] = p9[i] 179 | p[80 + i] = p10[i] 180 | p[88 + i] = p11[i] 181 | p[96 + i] = p12[i] 182 | 183 | window = ti.ui.Window("Dominoes", (648, 648), vsync = True) 184 | canvas = window.get_canvas() 185 | canvas.set_background_color((0, 0, 0)) 186 | scene = ti.ui.Scene() 187 | camera = ti.ui.Camera() 188 | camera.position(0, 3, 3) 189 | camera.lookat(0, 0, 0) 190 | scene.set_camera(camera) 191 | init() 192 | while window.running: 193 | scene.ambient_light((0.1, 0.1, 0.1)) 194 | scene.point_light(pos = (0, 3, -3), color = (1, 1, 1)) 195 | 196 | update() 197 | #Combine Mesh 198 | scene.mesh(p, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 199 | #scene.mesh(p0, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 200 | #scene.mesh(p1, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 201 | #scene.mesh(p2, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 202 | #scene.mesh(p3, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 203 | #scene.mesh(p4, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 204 | #scene.mesh(p5, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 205 | #scene.mesh(p6, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 206 | #scene.mesh(p7, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 207 | #scene.mesh(p8, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 208 | #scene.mesh(p9, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 209 | #scene.mesh(p10, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 210 | #scene.mesh(p11, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 211 | #scene.mesh(p12, indices = indices, color = (1, 0.89, 0.8), two_sided = True) 212 | canvas.scene(scene) 213 | window.show() --------------------------------------------------------------------------------