rnd-team-dev / plotoptix

Data visualisation and ray tracing in Python based on OptiX 7.7 framework.
https://rnd.team/plotoptix
Other
496 stars 26 forks source link

Plane-Wave with PlotOptiX #32

Closed AntonioVinciguerra closed 1 year ago

AntonioVinciguerra commented 1 year ago

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?

LyceanEM commented 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.

AntonioVinciguerra commented 1 year ago
First of all, thank you very much for answering me; I'll take a look at the link you sent me. However, since I am writing a thesis on electromagnetic ray tracing (bachelor's degree), I have to use plotoptix which performs it automatically. In particular, I have to simulate a very simple situation, for example a single plane wave that affects a mesh created by me (I already know how to create a mesh, set lights, camera etc.). So, I ask you again if it is possible to do such a thing using PlotOptiX. I thank you again and greet you. Inviato da Posta per Windows Da: TimInviato: giovedì 6 ottobre 2022 21:35A: rnd-team-dev/plotoptixCc: AntonioVinciguerra; AuthorOggetto: Re: [rnd-team-dev/plotoptix] Plane-Wave with PlotOptiX (Issue #32) Hello AntonioI hope you won't consider this cheeky, as I initially looked into using PlotOptix for my electromagnetics modelling, using their hooks to access optic through python. However, you may find LyceanEM (https://lyceanem-python.readthedocs.io/en/latest/) suits your needs, as it has been explicitly 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.—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: ***@***.***> 
LyceanEM commented 1 year ago

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.

AntonioVinciguerra commented 1 year ago
OK Tim, I'll talk to my professor about it. In any case, as I would still like to try today to make a simple example of a plane wave hitting a triangle, I just ask you one last thing because I don't want to bother you any further. How would I go about creating a plane wave?  There is nothing in the documentation about how to modify optical rays, it is only possible to change the intensity, colour, position, shape (spherical or rectangular) and radius of the light source.Thank you. Translated with www.DeepL.com/Translator (free version) Inviato da Posta per Windows Da: TimInviato: giovedì 6 ottobre 2022 22:11A: rnd-team-dev/plotoptixCc: AntonioVinciguerra; AuthorOggetto: Re: [rnd-team-dev/plotoptix] Plane-Wave with PlotOptiX (Issue #32) 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.—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: ***@***.***> 
LyceanEM commented 1 year ago

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.

robertsulej commented 1 year ago

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..

AntonioVinciguerra commented 1 year ago

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

AntonioVinciguerra commented 1 year ago

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.

robertsulej commented 1 year ago

There is a sample notebook doing this, I'll point you to it after my morning meetings.

robertsulej commented 1 year ago

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. :)

AntonioVinciguerra commented 1 year ago
Thank you again for your reply. In case I have to use what you recommended, can I ask you for some advice? Inviato da Posta per Windows Da: TimInviato: giovedì 6 ottobre 2022 22:51A: rnd-team-dev/plotoptixCc: AntonioVinciguerra; AuthorOggetto: Re: [rnd-team-dev/plotoptix] Plane-Wave with PlotOptiX (Issue #32) 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.—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: ***@***.***> 
robertsulej commented 1 year ago

Sure, write when you need help. :)

AntonioVinciguerra commented 1 year ago

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.

robertsulej commented 1 year ago

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()
AntonioVinciguerra commented 1 year ago
Thank you very much! Inviato da Posta per Windows Da: Robert SulejInviato: giovedì 27 ottobre 2022 13:08A: rnd-team-dev/plotoptixCc: AntonioVinciguerra; AuthorOggetto: 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 pltimport numpy as np from plotoptix import NpOptiXfrom 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.Message ID: ***@***.***> 
AntonioVinciguerra commented 1 year ago

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.

robertsulej commented 1 year ago

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).

AntonioVinciguerra commented 1 year ago
I already know how to create meshes and spatially order the vertices (e.g. I have created icosahedra, tetrahedra, cubes, etc. ). Since I have to do a simulation in which I shoot parallel rays towards a mesh and make them reflect but I’m having a lot of difficulties, for the moment, in trying to understand how the program works, what I’m trying to do is to shoot 3 parallel rays that start from the vertices of a triangle (e.g. with mesh vertices [0,0,0], [1,-2,0], [-1,-2,0] ) and that propagate backwards towards the camera plane. Looking at the previous code you sent, I have created two textures with “set_texture_2d”: the texture that contains the origins (I have created 3 origins by adding 0 to the 3 vertices), and the texture that contains the equal directions (with shape [0,0,1,-1] I think -1 indicates that the rays have an infinite range); then, I set the camera CustomProjXYZtoDir with the textures previously created. What I’d like to obtain are the distances at which these 3 rays hit some object in the scene by using “NpOptiX._hit_pos”. Since there are no intersections because the are no objects, what I expect to obtain are 3 arrays of shape [X, Y, Z, D] with very high (infinite) values; instead, what I get is an array of shape (388,707) with all 0s. Honestly, I don’t understand at all what these 0s means.Inviato da Posta per Windows Da: Robert SulejInviato: martedì 1 novembre 2022 17:23A: rnd-team-dev/plotoptixCc: AntonioVinciguerra; AuthorOggetto: Re: [rnd-team-dev/plotoptix] Plane-Wave with PlotOptiX (Issue #32) 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).—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: ***@***.***> 
robertsulej commented 1 year ago

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.

robertsulej commented 1 year ago

Closing the thread. Feel free to reopen or send me an email in case of questions.

mshmoon commented 1 year ago

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

robertsulej commented 1 year ago

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.