If I understood, you are looking for a representation of a single ray, without the use of render engines.
You can create geometry with python, which is raycasted. I modified the script from this laser question to create an object, which contains the laser as geometry.

Start with the first "hit" point at (0, 0, 0) and the casting direction (0, 0, 1) in the objects orientation. The following steps are
- Use the scenes
ray_cast
method to cast a ray. Get the hit position and the normal of the hit face.
- If the normal is on the side of the incoming ray, reverse it. The resulting angle between direction and normal ray will be < 90°.
- Get the difference between direction and normal ray. Rotate the direction ray twice by this difference. The direction ray is now "mirrored" along the inversed normal ray.
- Inverse the direction ray. This is the new direction ray in which direction we cast from the hit position.
import bpy
import bmesh
import mathutils
EPSILON = 0.00001
MAXIMUM_ITERATIONS = 50
OBJECT_NAME = 'light_plane'
def get_create_object(scene):
ob = scene.objects.get(OBJECT_NAME)
if ob == None:
me = bpy.data.meshes.new("me")
ob = bpy.data.objects.new(OBJECT_NAME, me)
scene.collection.objects.link(ob)
return ob
def do_raycast(scene):
object = get_create_object(scene)
points = [object.location]
_, rot, _ = object.matrix_world.decompose()
direction = mathutils.Vector((0, 0, 1))
direction.rotate(rot)
for i in range(MAXIMUM_ITERATIONS):
origin = points[-1] + direction * EPSILON
result = scene.ray_cast(scene.view_layers[0], origin=origin, direction = direction)
hit, location, normal, index, ob, matrix = result
if not hit:
break
if normal.dot(direction) < 0:
normal *= -1
rot_dif = direction.rotation_difference(normal)
direction.rotate(rot_dif)
direction.rotate(rot_dif)
direction *= -1
points.append(location)
points.append(points[-1] + direction*10)
bm = bmesh.new()
[bm.verts.new(pt) for pt in points]
bm.verts.ensure_lookup_table()
for i in range(len(bm.verts) - 1):
bm.edges.new((bm.verts[i], bm.verts[i + 1]))
bmesh.ops.transform(bm, matrix = object.matrix_world.inverted(), verts = bm.verts)
bm.to_mesh(object.data)
bm.free()
for h in bpy.app.handlers.depsgraph_update_post:
bpy.app.handlers.depsgraph_update_post.remove(h)
bpy.app.handlers.depsgraph_update_post.append(do_raycast)
In 2.9+ the Scene.ray_cast
method takes different arguments. Replace the line with this for 2.9+
graph = bpy.context.evaluated_depsgraph_get()
result = scene.ray_cast(graph, origin=origin, direction = direction)