PDA

View Full Version : rayCasting implementation.


BiGMaCHiNe
12-01-2011, 12:35 AM
Hey all, Im attempting to wrap my head around the math/concepts of raycasting, raytracing etc.
Ive started to implement a basic version of this.

I realise the peformance decreases im going to get as far as using python etc may be detrimental, but this is more an exercise in math/conceptualization/newbie programming than retrieving a result that is useable in a production context. By the same token, once I get something that at least works as expected, id ofcourse want to optimize it as much as possible.

At the moment for some reason Maya crashes occasionally ( not everytime ) when the script is run,
it also as of yet, has never returned a hit. Im testing it with one object in the viewport, a sphere that takes up approx. 50% of the screen real estate.

Any pointers would be amazing! cheers!

import math
import pymel.core as pm
import maya.cmds as cmds
import maya.OpenMaya as om
import maya.OpenMayaUI as omUI

debug = False

class Camera():
def __init__(self):

#find viewport/Camera Info
self.ActiveView = omUI.M3dView.active3dView()
self.CameraPath = om.MDagPath()
self.ActiveView.getCamera(self.CameraPath)
self.Camera = om.MFnCamera(self.CameraPath)
self.CameraName = (self.Camera.fullPathName()).split('|')[-1]

self.FocalLength = self.Camera.focalLength()
self.eyePoint = self.Camera.eyePoint(om.MSpace.kWorld)
self.upDirection = self.Camera.upDirection(om.MSpace.kWorld)
self.COIPoint = self.Camera.centerOfInterestPoint(om.MSpace.kWorld)

self.hFOV = math.degrees(self.Camera.horizontalFieldOfView())
self.vFOV = math.degrees(self.Camera.verticalFieldOfView())

renderWidth = cmds.getAttr("defaultResolution.width")
renderHeight = cmds.getAttr("defaultResolution.height")

self.Resolution = (renderWidth, renderHeight)

#setUp pointers to catch attributes
xPtrInit = om.MScriptUtil()
yPtrInit = om.MScriptUtil()
widthPtrInit = om.MScriptUtil()
heightPtrInit = om.MScriptUtil()

xPtr = xPtrInit.asUintPtr()
yPtr = yPtrInit.asUintPtr()
widthPtr = widthPtrInit.asUintPtr()
heightPtr = heightPtrInit.asUintPtr()

self.ActiveView.viewport(xPtr, yPtr, widthPtr, heightPtr)

viewX = xPtrInit.getUint( xPtr )
viewY = yPtrInit.getUint( yPtr )
viewWidth = widthPtrInit.getUint( widthPtr )
viewHeight = heightPtrInit.getUint( heightPtr )

self.viewScreen = (viewWidth, viewHeight, viewX, viewY)

centerPort = (self.viewScreen[0]*0.5, self.viewScreen[1]*0.5)

np = om.MPoint()
fp = om.MPoint()
#find center of the viewport ( in coords ) for testing - needed?
self.ActiveView.viewToWorld(int(centerPort[0]), int(centerPort[1]),np, fp)

self.NP_Center = ( np.x, np.y, np.z )
self.FP_Center = ( fp.x, fp.y, fp.z )

self.aspectRatio = float(renderHeight) / float(renderWidth)

self.pixHeight = self.Resolution[0] / self.viewScreen[0]
self.pixWidth = self.Resolution[1] / self.viewScreen[1]
self.Rays = {}
self.QuadList = self.Create_Bins()
self.CreateRays()

def Create_Bins(self):
#to divide into render partitions
binSize = 64

print 'binSize: %i' % binSize

lastX = 0
lastY= 0
QuadList = []

for x in range(0,self.Resolution[0], binSize):
for y in range(0, self.Resolution[1], binSize):
QuadList.append([lastX, lastY, x, y])
lastX = x
lastY = y

QuadList.append([lastX, lastY, self.Resolution[0], self.Resolution[1]])

if(debug):
for q in QuadList:
print 'x0: %i, y0: %i, x1: %i, y1: %i' %(q[0],q[1],q[2],q[3])

print len(QuadList), ' bins'
return QuadList

def CreateRays(self):
#Create a ray for each pixel
for q in self.QuadList:
np = om.MPoint()
fp = om.MPoint()
for x in xrange(q[0], q[2]):
for y in xrange(q[1],q[3]):
self.ActiveView.viewToWorld(int(x), int(y), np, fp)

Vector = fp - np
#normalize the vector for ray orientation
om.MVector.normalize(Vector)

Ray = self.Camera_Rays(np, Vector, fp.z)

class Camera_Rays():
def __init__(self, origin, direction, zMax):
self.origin = origin
self.direction = direction
self.Pos = origin
self.hitTesting()

def hitTesting(self):
#check closest point, and test if it falls on the same vector line
for z in xrange(abs(int(fp.z - np.z))):
self.Pos += self.direction

closestPoint = om.MPoint()

mutil = om.MScriptUtil()
intPtr = mutil.asIntPtr()

testMesh.MFnMesh.getClosestPoint(self.Pos,closestPoint,om.MSpace.kWorld,intPtr)

testVector = self.origin - closestPoint
om.MVector.normalize(testVector)

if testVector == self.direction:
print 'hit'


class Mesh():
def __init__(self):

selObj = om.MSelectionList()
om.MGlobal.getActiveSelectionList(selObj)
meshDag = om.MDagPath()
selObj.getDagPath(0, meshDag)
self.MFnMesh = om.MFnMesh(meshDag)

myCamera = Camera()
testMesh = Mesh()

NaughtyNathan
12-01-2011, 10:12 AM
Hello again BiGMaCHiNe, what exactly is this script supposed to do? I have to confess I've got no idea just by looking at the code, and you said it doesn't work, so I didn't bother running it! ;) :D
But based on your description, are you trying to hit a mesh with a ray? There is an MFnMesh method: closestIntersection (and a couple of similar, related methods) that will find the rayCast intersection point for a given mesh from a given vector/point. Is this basically what you want?
I've got a working version of this using python and it works pretty good.

:nathaN

BiGMaCHiNe
12-01-2011, 12:49 PM
Hi naughty :) yeah essentially. I am using the camera class to get the required information about the camera and sort out the near and far planes, and respective coordinates. I think my main issue has been figuring out the correlation between viewport coordinates and image pixels ( for any given render ) I'm shooting out a ray at what I hope is the correct vector ( subtracting far and near points from each other and normalizing the result). Im then moving the ray through the scene by incrementing the normalized vector onto the original rays starting point ( which I have inferred was the near plane coords, tho some books seem to write it as the cameras eye point ). Whilst its incrementing Ive been running the closest point on mesh with a sphere ( for testing ). I've then been taking that returned point on the mesh and testing if subtracting it with the respective near point to c if it returns the same ( normalized ) vector that the ray is projecting along ( which ATM hasn't been successful ). I could be way off on all of this ofcourse, but diff books I've got seem to implement slightly diff methods in varying amounts of detail. Im mostly doing this to better understand the algorithms used in the rendering process and the python API at the same time. Thanks again for being so helpful!

CGTalk Moderation
12-01-2011, 12:49 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.