taichi
taichi copied to clipboard
cornell_box.py example doesn't work on macOS with Metal backend
Describe the bug
Hi, I'm trying to run the latest taichi
release (upd: and the latest nightly build - [Taichi] version 1.8.0, llvm 15.0.7, commit 52b24f3e, osx, python 3.11.7
, outcome is the same) on macOS, but unfortunately, the Cornell Box sample fails to start. Other samples (in particular, sdf_renderer.py
) seem to work.
To Reproduce
- Run
ti gallery
- Click on the Cornell Box icon
- Observe the error
Log/Screenshots
> ti gallery
[Taichi] version 1.7.0, llvm 15.0.7, commit 2fd24490, osx, python 3.11.7
*******************************************
** Taichi Programming Language **
*******************************************
Docs: https://docs.taichi-lang.org/
GitHub: https://github.com/taichi-dev/taichi/
Forum: https://forum.taichi.graphics/
Demo source code:
1 # pylint: disable=W0622,W0621,W0401
2 import taichi as ti
3 from taichi.math import *
4
5 ti.init(arch=ti.gpu, default_ip=ti.i32, default_fp=ti.f32)
6
7 image_resolution = (512, 512)
8 image_buffer = ti.Vector.field(4, float, image_resolution)
9 image_pixels = ti.Vector.field(3, float, image_resolution)
10
11 Ray = ti.types.struct(origin=vec3, direction=vec3, color=vec3)
12 Material = ti.types.struct(albedo=vec3, emission=vec3)
13 Transform = ti.types.struct(position=vec3, rotation=vec3, scale=vec3, matrix=mat3)
14 SDFObject = ti.types.struct(distance=float, transform=Transform, material=Material)
15
16 objects = SDFObject.field(shape=8)
17 objects[0] = SDFObject(
18 transform=Transform(vec3(0, 0, -1), vec3(0, 0, 0), vec3(1, 1, 0.2)),
19 material=Material(vec3(1, 1, 1) * 0.4, vec3(1)),
20 )
21 objects[1] = SDFObject(
22 transform=Transform(vec3(0, 1, 0), vec3(90, 0, 0), vec3(1, 1, 0.2)),
23 material=Material(vec3(1, 1, 1) * 0.4, vec3(1)),
24 )
25 objects[2] = SDFObject(
26 transform=Transform(vec3(0, -1, 0), vec3(90, 0, 0), vec3(1, 1, 0.2)),
27 material=Material(vec3(1, 1, 1) * 0.4, vec3(1)),
28 )
29 objects[3] = SDFObject(
30 transform=Transform(vec3(-1, 0, 0), vec3(0, 90, 0), vec3(1, 1, 0.2)),
31 material=Material(vec3(1, 0, 0) * 0.5, vec3(1)),
32 )
33 objects[4] = SDFObject(
34 transform=Transform(vec3(1, 0, 0), vec3(0, 90, 0), vec3(1, 1, 0.2)),
35 material=Material(vec3(0, 1, 0) * 0.5, vec3(1)),
36 )
37 objects[5] = SDFObject(
38 transform=Transform(vec3(-0.275, -0.3, -0.2), vec3(0, 112, 0), vec3(0.25, 0.5, 0.25)),
39 material=Material(vec3(1, 1, 1) * 0.4, vec3(1)),
40 )
41 objects[6] = SDFObject(
42 transform=Transform(vec3(0.275, -0.55, 0.2), vec3(0, -197, 0), vec3(0.25, 0.25, 0.25)),
43 material=Material(vec3(1, 1, 1) * 0.4, vec3(1)),
44 )
45 objects[7] = SDFObject(
46 transform=Transform(vec3(0, 0.809, 0), vec3(90, 0, 0), vec3(0.2, 0.2, 0.01)),
47 material=Material(vec3(1, 1, 1) * 1, vec3(100)),
48 )
49
50
51 @ti.real_func
52 def rotate(a: vec3) -> mat3:
53 s, c = sin(a), cos(a)
54 return (
55 mat3(c.z, s.z, 0, -s.z, c.z, 0, 0, 0, 1)
56 @ mat3(c.y, 0, -s.y, 0, 1, 0, s.y, 0, c.y)
57 @ mat3(1, 0, 0, 0, c.x, s.x, 0, -s.x, c.x)
58 )
59
60
61 @ti.real_func
62 def signed_distance(obj: SDFObject, pos: vec3) -> float:
63 p = obj.transform.matrix @ (pos - obj.transform.position)
64 q = abs(p) - obj.transform.scale
65 return length(max(q, 0)) + min(max(q.x, max(q.y, q.z)), 0)
66
67
68 @ti.real_func
69 def nearest_object(p: vec3) -> (int, float):
70 index, min_dis = 0, 1e32
71 for i in ti.static(range(8)):
72 dis = signed_distance(objects[i], p)
73 if dis < min_dis:
74 min_dis, index = dis, i
75 return index, min_dis
76
77
78 @ti.real_func
79 def calc_normal(obj: SDFObject, p: vec3) -> vec3:
80 e = vec2(1, -1) * 0.5773 * 0.005
81 return normalize(
82 e.xyy * signed_distance(obj, p + e.xyy)
83 + e.yyx * signed_distance(obj, p + e.yyx)
84 + e.yxy * signed_distance(obj, p + e.yxy)
85 + e.xxx * signed_distance(obj, p + e.xxx)
86 )
87
88
89 @ti.real_func
90 def raycast(ray: Ray) -> (SDFObject, vec3, bool):
91 w, s, d, cerr = 1.6, 0.0, 0.0, 1e32
92 index, t, position, hit = 0, 0.005, vec3(0), False
93 for _ in range(64):
94 position = ray.origin + ray.direction * t
95 index, distance = nearest_object(position)
96
97 ld, d = d, distance
98 if ld + d < s:
99 s -= w * s
100 t += s
101 w *= 0.5
102 w += 0.5
103 continue
104 err = d / t
105 if err < cerr:
106 cerr = err
107
108 s = w * d
109 t += s
110 hit = err < 0.001
111 if t > 5.0 or hit:
112 break
113 return objects[index], position, hit
114
115
116 @ti.real_func
117 def hemispheric_sampling(normal: vec3) -> vec3:
118 z = 2.0 * ti.random() - 1.0
119 a = ti.random() * 2.0 * pi
120 xy = sqrt(1.0 - z * z) * vec2(sin(a), cos(a))
121 return normalize(normal + vec3(xy, z))
122
123
124 @ti.real_func
125 def raytrace(ray: Ray) -> Ray:
126 for _ in range(3):
127 object, position, hit = raycast(ray)
128 if not hit:
129 ray.color = vec3(0)
130 break
131
132 normal = calc_normal(object, position)
133 ray.direction = hemispheric_sampling(normal)
134 ray.color *= object.material.albedo
135 ray.origin = position
136
137 intensity = dot(ray.color, vec3(0.299, 0.587, 0.114))
138 ray.color *= object.material.emission
139 visible = dot(ray.color, vec3(0.299, 0.587, 0.114))
140 if intensity < visible or visible < 0.000001:
141 break
142 return ray
143
144
145 @ti.kernel
146 def build_scene():
147 for i in objects:
148 rotation = radians(objects[i].transform.rotation)
149 objects[i].transform.matrix = rotate(rotation)
150
151
152 @ti.kernel
153 def render(camera_position: vec3, camera_lookat: vec3, camera_up: vec3):
154 for i, j in image_pixels:
155 z = normalize(camera_position - camera_lookat)
156 x = normalize(cross(camera_up, z))
157 y = cross(z, x)
158
159 half_width = half_height = tan(radians(35) * 0.5)
160 lower_left_corner = camera_position - half_width * x - half_height * y - z
161 horizontal = 2.0 * half_width * x
162 vertical = 2.0 * half_height * y
163
164 uv = (vec2(i, j) + vec2(ti.random(), ti.random())) / vec2(image_resolution)
165 po = lower_left_corner + uv.x * horizontal + uv.y * vertical
166 rd = normalize(po - camera_position)
167
168 ray = raytrace(Ray(camera_position, rd, vec3(1)))
169 buffer = image_buffer[i, j]
170 buffer += vec4(ray.color, 1.0)
171 image_buffer[i, j] = buffer
172
173 color = buffer.rgb / buffer.a
174 color = pow(color, vec3(1.0 / 2.2))
175 color = (
176 mat3(
177 0.597190,
178 0.35458,
179 0.04823,
180 0.07600,
181 0.90834,
182 0.01566,
183 0.02840,
184 0.13383,
185 0.83777,
186 )
187 @ color
188 )
189 color = (color * (color + 0.024578) - 0.0000905) / (color * (0.983729 * color + 0.4329510) + 0.238081)
190 color = (
191 mat3(
192 1.60475,
193 -0.531,
194 -0.0736,
195 -0.102,
196 1.10813,
197 -0.00605,
198 -0.00327,
199 -0.07276,
200 1.07602,
201 )
202 @ color
203 )
204 image_pixels[i, j] = clamp(color, 0, 1)
205
206
207 def main():
208 window = ti.ui.Window("Cornell Box", image_resolution)
209 canvas = window.get_canvas()
210 build_scene()
211 while window.running:
212 render(vec3(0, 0, 3.5), vec3(0, 0, -1), vec3(0, 1, 0))
213 canvas.set_image(image_pixels)
214 window.show()
215
216
217 if __name__ == "__main__":
218 main()
219
[Taichi] version 1.7.0, llvm 15.0.7, commit 2fd24490, osx, python 3.11.7
[Taichi] Starting on arch=metal
[E 02/24/24 13:10:29.644 2395910] [spirv_ir_builder.cpp:query_value@1316] Value "tmp26" does not yet exist.
Traceback (most recent call last):
File "/opt/homebrew/lib/python3.11/site-packages/taichi/examples/real_func/rendering/cornell_box.py", line 218, in <module>
main()
File "/opt/homebrew/lib/python3.11/site-packages/taichi/examples/real_func/rendering/cornell_box.py", line 210, in main
build_scene()
File "/opt/homebrew/lib/python3.11/site-packages/taichi/lang/kernel_impl.py", line 1103, in wrapped
return primal(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/taichi/lang/kernel_impl.py", line 1035, in __call__
return self.launch_kernel(kernel_cpp, *args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/taichi/lang/kernel_impl.py", line 966, in launch_kernel
raise e from None
File "/opt/homebrew/lib/python3.11/site-packages/taichi/lang/kernel_impl.py", line 959, in launch_kernel
compiled_kernel_data = prog.compile_kernel(prog.config(), prog.get_device_caps(), t_kernel)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: [spirv_ir_builder.cpp:query_value@1316] Value "tmp26" does not yet exist.
>>> Running time: 5.81s
Additional comments
Here is the output of ti diagnose
:
> ti diagnose
[Taichi] version 1.7.0, llvm 15.0.7, commit 2fd24490, osx, python 3.11.7
*******************************************
** Taichi Programming Language **
*******************************************
Docs: https://docs.taichi-lang.org/
GitHub: https://github.com/taichi-dev/taichi/
Forum: https://forum.taichi.graphics/
Taichi system diagnose:
python: 3.11.7 (main, Dec 4 2023, 18:10:11) [Clang 15.0.0 (clang-1500.1.0.2.5)]
system: darwin
executable: /opt/homebrew/opt/[email protected]/bin/python3.11
platform: macOS-14.3.1-arm64-arm-64bit
architecture: 64bit
uname: uname_result(system='Darwin', node='macbook.local', release='23.3.0', version='Darwin Kernel Version 23.3.0: Wed Dec 20 21:30:44 PST 2023; root:xnu-10002.81.5~7/RELEASE_ARM64_T6000', machine='arm64')
/opt/homebrew/lib/python3.11/site-packages/taichi/tools/diagnose.py:20: DeprecationWarning: 'locale.getdefaultlocale' is deprecated and slated for removal in Python 3.15. Use setlocale(), getencoding() and getlocale() instead.
print(f'locale: {".".join(locale.getdefaultlocale())}')
Traceback (most recent call last):
File "/opt/homebrew/bin/ti", line 8, in <module>
sys.exit(main())
^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/taichi/_main.py", line 897, in main
return cli()
^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/taichi/_main.py", line 33, in wrapper
result = func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/taichi/_main.py", line 92, in __call__
return getattr(self, args.command)(sys.argv[2:])
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/opt/homebrew/lib/python3.11/site-packages/taichi/_main.py", line 806, in diagnose
diagnose.main()
File "/opt/homebrew/lib/python3.11/site-packages/taichi/tools/diagnose.py", line 20, in main
print(f'locale: {".".join(locale.getdefaultlocale())}')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: sequence item 0: expected str instance, NoneType found
Same issue. Same environment.