Closed AntonioVinciguerra closed 1 year ago
Hello Antonio
I hope you won't consider this cheeky, as I initially looked into using PlotOptix for my electromagnetics modelling, using their hooks to access optix through python. However, you may find LyceanEM (https://lyceanem-python.readthedocs.io/en/latest/) suits your needs, as it has been explicitly designed to support electromagnetics scattering. I would caution you that true plane waves are only an abstraction however. All scattering, optical and microwave are superpositions of expanding spherical wavefronts.
You may be able to do it with Plot Optix but I would not recommend it. I suggested LyceanEM because it is an electromagnetic ray tracer, designed for your specific needs.
I can't advise you on how to do it in PlotOptix, only on LyceanEM or the actual physics. I actually hold a PhD in antenna array design and electromagnetics.
Hi guys!
A lot depends on what level you'd like to get you hands dirty. I was already working with a group doing antenna simulations and added some features to facilitate this kind of applications (though the main purpose and fun with PlotOptiX is image generation).
So, with PlotOptiX at low level you:
This means most of the EM formulas and simulation logic is in your hands. Now, not being familiar with LyceanEM :) - you may find it better suited to work on a higher level of simulation design.
Interesting things! Accidentaly I've done my PhD in Radioelectronics Institute as well :) but moved to particle physics after that..
Hi guys!
A lot depends on what level you'd like to get you hands dirty. I was already working with a group doing antenna simulations and added some features to facilitate this kind of applications (though the main purpose and fun with PlotOptiX is image generation).
So, with PlotOptiX at low level you:
- send rays in any pattern: you define source, destination or direction, max lenght, etc.
- from this you get hit positions, primitive id's, flight distances
- you define behaviour at the hit point, eg direction of the next segment of the ray; some scattering distributions are implemented as shaders so you can run run multi-segment simulation easier.
This means most of the EM formulas and simulation logic is in your hands. Now, not being familiar with LyceanEM :) - you may find it better suited to work on a higher level of simulation design.
Interesting things! Accidentaly I've done my PhD in Radioelectronics Institute as well :) but moved to particle physics after that..
Please, where can i find simple examples of this stuff ? I'm having a lot of troubles , thank you in advance
I need to realize a simple simulation ; for example, shoot a number of parallel rays(in order to simulate a plane wave) towards a mesh with triangular faces and then I would like to obtain in output the index of the faces that were hit, the coordinates of the pixels that were hit and the distance between the hit point and the camera plane.. I really thank you if you can help me.
There is a sample notebook doing this, I'll point you to it after my morning meetings.
Here is the notebook calculating distances from ray origin to hit position, where rays are distributed over a plane and all rays are parallel.
This notebook shows what info is available for ray hits (face id's, distances, ...).
Both notebooks use callback function to display results. This callback is executed when gpu finished calculations for the frame. If you prefer more simple code, please, remember callback with at least threading Event is needed to signal the end of calculations, otherwise buffer are empty with zeros - this is usual gotcha. :)
Sure, write when you need help. :)
Hi Robert, sorry to bother you again. In a previous message, you told me that with plotoptix it is possible to cast rays by specifying origin, direction, destination and max length. Could you send me some code examples? Thank you in advance and best regards.
Inviato da iPhone
Il giorno 11 ott 2022, alle ore 12:16, Robert Sulej @.***> ha scritto:
Sure, write when you need help. :)
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.
Hi Antonio,
Please, find included below simple code that starts parallel rays from a vertical plane towards Z axis. It contains the synchronization, so figures are shown after calculations finished and data is ready in the buffers. Code expects .obj file in data folder, so you can run it eg from plotoptix\examples\1_basics folder. All x, y, z dimensions and image sizes are different so you should figure out what dimension is which direction etc.
The code is basically simplified notebook that I linked in the earlier comment. You can also see here for other modes of shooting rays.
import matplotlib.pyplot as plt
import numpy as np
from plotoptix import NpOptiX
from plotoptix.materials import m_flat
import threading
class params:
done = threading.Event()
def wait_for_gpu(rt: NpOptiX) -> None:
print("gpu done")
params.done.set()
def main():
nu = 50
nv = 70
rt = NpOptiX(on_launch_finished=wait_for_gpu, width=nu, height=nv)
rt.set_param(min_accumulation_step=1, max_accumulation_frames=1)
rt.setup_material("flat", m_flat)
rt.load_mesh_obj(r"data\utah-teapot.obj", mat="flat")
u = np.linspace(-30, 30, nu)
v = np.linspace(20, -20, nv)
V, U = np.meshgrid(v, u)
W = np.full((nu, nv), -50)
src_tex = np.stack((U, V, W, np.zeros((nu, nv)))).T
rt.set_texture_2d("src", src_tex)
cx = np.zeros((nu, nv))
cy = np.zeros((nu, nv))
cz = np.ones((nu, nv))
r = np.full((nu, nv), 200)
dir_tex = np.stack((cx, cy, cz, r)).T
rt.set_texture_2d("dir", dir_tex)
rt.setup_camera("custom_cam", cam_type="CustomProjXYZtoDir", textures=["src", "dir"])
rt.start()
print("working...")
if params.done.wait(10):
f = rt._geo_id[:,:,1].reshape(rt._height, rt._width)
f1 = np.amax(f[f < 0xFFFFFFFF]) # skip id of empty regions
f0 = np.amin(f)
d = rt._hit_pos[:,:,3].reshape(rt._height, rt._width)
d1 = np.amax(d[f < 0xFFFFFFFF]) # skip distance to empty regions
d0 = np.amin(d[f < 0xFFFFFFFF])
plt.figure(1)
img = plt.imshow(f, vmin=f0, vmax=f1, cmap=plt.get_cmap("flag"))
plt.tight_layout()
plt.show()
plt.figure(2)
img = plt.imshow(d, vmin=d0, vmax=d1, cmap=plt.get_cmap("gray"))
plt.tight_layout()
plt.show()
else:
print("timeout")
rt.close()
if __name__ == '__main__':
main()
Hello, I wanted to ask something. I have created a mesh and I would like to shoot rays with the customprojXYZtoDir camera by setting the mesh vertices as the origin and the direction from the mesh vertices to the camera plane as the direction. in other words, I would like to shoot rays backwards from the mesh vertices to the camera plane. is this possible with plotoptix ? Thank you in advance and best regards.
Inviato da iPhone
Il giorno 27 ott 2022, alle ore 17:43, Antonio Vinciguerra @.***> ha scritto:
Thank you very much!
Inviato da Posta per Windows
Da: Robert Sulej Inviato: giovedì 27 ottobre 2022 13:08 A: rnd-team-dev/plotoptix Cc: AntonioVinciguerra; Author Oggetto: Re: [rnd-team-dev/plotoptix] Plane-Wave with PlotOptiX (Issue #32)
Hi Antonio,
Please, find included below simple code that starts parallel rays from a vertical plane towards Z axis. It contains the synchronization, so figures are shown after calculations finished and data is ready in the buffers. Code expects .obj file in data folder, so you can run it eg from plotoptix\examples\1_basics folder. All x, y, z dimensions and image sizes are different so you should figure out what dimension is which direction etc.
The code is basically simplified notebook that I linked in the earlier comment. You can also see here for other modes of shooting rays.
import matplotlib.pyplot as plt import numpy as np
from plotoptix import NpOptiX from plotoptix.materials import m_flat
import threading
class params: done = threading.Event()
def wait_for_gpu(rt: NpOptiX) -> None: print("gpu done") params.done.set()
def main(): nu = 50 nv = 70
rt = NpOptiX(on_launch_finished=wait_for_gpu, width=nu, height=nv) rt.set_param(min_accumulation_step=1, max_accumulation_frames=1) rt.setup_material("flat", m_flat) rt.load_mesh_obj(r"data\utah-teapot.obj", mat="flat") u = np.linspace(-30, 30, nu) v = np.linspace(20, -20, nv) V, U = np.meshgrid(v, u) W = np.full((nu, nv), -50) src_tex = np.stack((U, V, W, np.zeros((nu, nv)))).T rt.set_texture_2d("src", src_tex) cx = np.zeros((nu, nv)) cy = np.zeros((nu, nv)) cz = np.ones((nu, nv)) r = np.full((nu, nv), 200) dir_tex = np.stack((cx, cy, cz, r)).T rt.set_texture_2d("dir", dir_tex) rt.setup_camera("custom_cam", cam_type="CustomProjXYZtoDir", textures=["src", "dir"]) rt.start() print("working...") if params.done.wait(10): f = rt._geo_id[:,:,1].reshape(rt._height, rt._width) f1 = np.amax(f[f < 0xFFFFFFFF]) # skip id of empty regions f0 = np.amin(f) d = rt._hit_pos[:,:,3].reshape(rt._height, rt._width) d1 = np.amax(d[f < 0xFFFFFFFF]) # skip distance to empty regions d0 = np.amin(d[f < 0xFFFFFFFF]) plt.figure(1) img = plt.imshow(f, vmin=f0, vmax=f1, cmap=plt.get_cmap("flag")) plt.tight_layout() plt.show() plt.figure(2) img = plt.imshow(d, vmin=d0, vmax=d1, cmap=plt.get_cmap("gray")) plt.tight_layout() plt.show() else: print("timeout") rt.close()
if name == 'main': main() — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.
Sure, no problem - just put your vertex coordinates in pixels of the src_tex
texture in the above code. The order of vertices stored in pixels does not matter (it will run faster if they are spatially organized, but don't care about that in the beginning). The dir_tex
is like before - all pixels set to the same direction to shoot parallel rays - you only need to decide which direction it should be.
Then put an object that will act as the flat surface where you expect to catch rays. It can be eg a simple mesh.
Note that you may need to check if you are shooting outside the mesh volume, probably you are not interested in rays that start inward and are stopped somewhere on the mesh itself (anyway, this information will be available in the face id biffer).
Hi,
Note the sizes of image that is ray-traced: rt = NpOptiX(on_launch_finished=wait_for_gpu, width=nu, height=nv)
.
Camera textures in the custom modes are resized (with interpolation) to match width and height of the ray tracing output if they are not of the same size. If sizes are equal, then no interpolation is done and pixels in the output correspond exactly to pixels in the camera textures (mentioned here in docs).
The flow of calculations is optimized to work with large number of rays. If you want to test output on a few rays, set a low size of the ray-tracing output, eg rt = NpOptiX(on_launch_finished=wait_for_gpu, width=16, height=16)
, make the same 16x16 size of the camera textures and set your 3 points in the first 3 pixels.
If the ray did not hit any object, then it is tagged with 0xFFFFFFFF
in rt._geo_id[:,:,1]
.
If you read buffers too early they will be all zeros, but for this you already have the synchronization, on_launch_finished=wait_for_gpu
.
Closing the thread. Feel free to reopen or send me an email in case of questions.
Hi Antonio,
Please, find included below simple code that starts parallel rays from a vertical plane towards Z axis. It contains the synchronization, so figures are shown after calculations finished and data is ready in the buffers. Code expects .obj file in data folder, so you can run it eg from plotoptix\examples\1_basics folder. All x, y, z dimensions and image sizes are different so you should figure out what dimension is which direction etc.
The code is basically simplified notebook that I linked in the earlier comment. You can also see here for other modes of shooting rays.
import matplotlib.pyplot as plt import numpy as np from plotoptix import NpOptiX from plotoptix.materials import m_flat import threading class params: done = threading.Event() def wait_for_gpu(rt: NpOptiX) -> None: print("gpu done") params.done.set() def main(): nu = 50 nv = 70 rt = NpOptiX(on_launch_finished=wait_for_gpu, width=nu, height=nv) rt.set_param(min_accumulation_step=1, max_accumulation_frames=1) rt.setup_material("flat", m_flat) rt.load_mesh_obj(r"data\utah-teapot.obj", mat="flat") u = np.linspace(-30, 30, nu) v = np.linspace(20, -20, nv) V, U = np.meshgrid(v, u) W = np.full((nu, nv), -50) src_tex = np.stack((U, V, W, np.zeros((nu, nv)))).T rt.set_texture_2d("src", src_tex) cx = np.zeros((nu, nv)) cy = np.zeros((nu, nv)) cz = np.ones((nu, nv)) r = np.full((nu, nv), 200) dir_tex = np.stack((cx, cy, cz, r)).T rt.set_texture_2d("dir", dir_tex) rt.setup_camera("custom_cam", cam_type="CustomProjXYZtoDir", textures=["src", "dir"]) rt.start() print("working...") if params.done.wait(10): f = rt._geo_id[:,:,1].reshape(rt._height, rt._width) f1 = np.amax(f[f < 0xFFFFFFFF]) # skip id of empty regions f0 = np.amin(f) d = rt._hit_pos[:,:,3].reshape(rt._height, rt._width) d1 = np.amax(d[f < 0xFFFFFFFF]) # skip distance to empty regions d0 = np.amin(d[f < 0xFFFFFFFF]) plt.figure(1) img = plt.imshow(f, vmin=f0, vmax=f1, cmap=plt.get_cmap("flag")) plt.tight_layout() plt.show() plt.figure(2) img = plt.imshow(d, vmin=d0, vmax=d1, cmap=plt.get_cmap("gray")) plt.tight_layout() plt.show() else: print("timeout") rt.close() if __name__ == '__main__': main()
I think it would be more perfect if you could directly provide the ray casting interface
That depends on the aim. Pure interface to underlaying OptiX would be a diiferent project, with a different performance, and you would need to write pieces in CUDA C.
Hello, I am trying to simulate an electromagnetic scattering situation using PlotOptiX. In particular, I would like to make the source produce plane waves instead of optical rays. Is this possible?