Created
May 11, 2022 01:08
-
-
Save RH2/5197d7000685a1f0686f747a00d20139 to your computer and use it in GitHub Desktop.
blenderraycastsample.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import bpy | |
from mathutils import Vector, Quaternion | |
import numpy as np | |
import bmesh | |
import glob | |
import os | |
os.system('clear') | |
def lerp( t, a, b): | |
return a + t * (b - a) | |
def project(camera, coords): | |
# objects to consider | |
obj = bpy.data.objects['geometry'] | |
# background = bpy.data.objects['plane'] | |
targets = [obj] | |
# camera object which defines ray source | |
cam = camera | |
print(cam.name) | |
# save current view mode | |
mode = bpy.context.area.type | |
# set view mode to 3D to have all needed variables available | |
bpy.context.area.type = "VIEW_3D" | |
# get vectors which define view frustum of camera | |
frame = cam.data.view_frame(scene=bpy.context.scene) | |
topRight = frame[0] | |
bottomRight = frame[1] | |
bottomLeft = frame[2] | |
topLeft = frame[3] | |
# number of pixels in X/Y direction | |
resolutionX = int(bpy.context.scene.render.resolution_x * (bpy.context.scene.render.resolution_percentage / 100)) | |
resolutionY = int(bpy.context.scene.render.resolution_y * (bpy.context.scene.render.resolution_percentage / 100)) | |
# setup vectors to match pixels | |
# xRange = np.linspace(topLeft[0], topRight[0], 4) | |
# yRange = np.linspace(topLeft[1], bottomLeft[1], 4) | |
# print("xRange",xRange,"yRange",yRange) | |
print("coords",coords) | |
#for each x and y, interpolate between left,right, bottom,top | |
xRange = [] | |
yRange = [] | |
for x,y in coords: | |
#print("x is:",x,"y is:", y) | |
xRange.append(lerp(x,topLeft[0],topRight[0])) | |
yRange.append(lerp(y,topLeft[1],bottomLeft[1])) | |
print(xRange,yRange) | |
xRange = np.array(xRange) | |
yRange = np.array(yRange) | |
#ycoords = np.interp(np.array(ys),topLeft[1],bottomLeft[1]) | |
# for x,y in zip(xcoords,ycoords): | |
# x = np.interp(x,topLeft[0],topRight[0]) | |
# y = np.interp(y,topLeft[1],bottomLeft[1]) | |
# array to store hit information | |
values = np.empty((xRange.size, yRange.size), dtype=object) | |
# indices for array mapping | |
indexX = 0 | |
indexY = 0 | |
# filling array with None | |
for x in xRange: | |
for y in yRange: | |
values[indexX,indexY] = None | |
indexY += 1 | |
indexX += 1 | |
indexY = 0 | |
hits = [] | |
# iterate over all targets | |
for target in targets: | |
# calculate origin | |
matrixWorld = target.matrix_world | |
matrixWorldInverted = matrixWorld.inverted() | |
origin = matrixWorldInverted @ cam.matrix_world.translation | |
for x,y in coords: | |
x = (lerp(x,topLeft[0],topRight[0])) | |
y = (lerp(y,topLeft[1],bottomLeft[1])) | |
pixelVector = Vector((x, y, topLeft[2])) | |
pixelVector.rotate(cam.matrix_world.to_quaternion()) | |
destination = matrixWorldInverted @ (pixelVector + cam.matrix_world.translation) | |
direction = (destination - origin).normalized() | |
hit, location, norm, face = target.ray_cast(origin, direction) | |
if hit: | |
#values[indexX,indexY] = (matrixWorld @ location) | |
hits.append(matrixWorld @ location) | |
# create new mesh | |
# source: https://devtalk.blender.org/t/alternative-in-2-80-to-create-meshes-from-python-using-the-tessfaces-api/7445/3 | |
mesh = bpy.data.meshes.new(name='created mesh') | |
bm = bmesh.new() | |
for hit in hits: | |
# no hit at this position | |
if hit is None: | |
continue | |
# add new vertex | |
bm.verts.new((hit[0], hit[1], hit[2])) | |
# # iterate over all possible hits | |
# for index, location in np.ndenumerate(values): | |
# # no hit at this position | |
# if location is None: | |
# continue | |
# # add new vertex | |
# bm.verts.new((location[0], location[1], location[2])) | |
# make the bmesh the object's mesh | |
bm.to_mesh(mesh) | |
bm.free() # always do this when finished | |
# We're done setting up the mesh values, update mesh object and | |
# let Blender do some checks on it | |
mesh.update() | |
mesh.validate() | |
# Create Object whose Object Data is our new mesh | |
obj = bpy.data.objects.new('created object', mesh) | |
# Add *Object* to the scene, not the mesh | |
scene = bpy.context.scene | |
scene.collection.objects.link(obj) | |
# Select the new object and make it active | |
bpy.ops.object.select_all(action='DESELECT') | |
obj.select_set(True) | |
bpy.context.view_layer.objects.active = obj | |
# reset view mode | |
bpy.context.area.type = mode | |
print("Done.") | |
path = r"A:\Controllerscan\coke\mov1\det_clean" | |
wildcard = r"*.txt" | |
completePath = os.path.join(path, wildcard) | |
print(completePath) | |
for det in glob.iglob(completePath): | |
f = open(det, "r") | |
head,tail = os.path.split(det) | |
cameraname = tail.replace(".txt",".png") | |
cam = bpy.data.objects[cameraname] | |
print(cam) | |
coords = [] | |
content = f.read() | |
for line in content.split("\n"): | |
if line != "": | |
vars = line.split(",") | |
u = float(vars[2]) | |
v = float(vars[3]) | |
coords.append([u,v]) | |
#print(vars) | |
#point = geo.createPoint() | |
#point.setAttribValue("id", int(vars[0])) | |
#point.setAttribValue("corner", int(vars[1])) | |
#point.setPosition( (float(vars[2]), (1.0-float(vars[3])) , 0.0) ) | |
if len(coords) > 0: | |
project(cam, coords) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment