sculpt mesh Tablet support, bug squash Dec 25th Merry XMAS

zbgump,

If you can’t compile yourself, I can send you a a recently compiled cvs version.

Just message me your email address.

LetterRip

with the new script I get this

===== Fri Oct 15 2004 ===== 12:54:04 US/Eastern =====
===== Fri Oct 15 2004 ===== 12:54:05 US/Eastern =====
File “dis2.py”, line 98
name = myObject.name
^
IndentationError: unindent does not match any outer indentation level

Fixed it,

there was two extra spaces prior to the two tabs on the previous line.

LetterRip

Now you need to fix the post to show the code layout so it is easy to copy and has the correct formating :stuck_out_tongue:

I want to use this but I don’t understand what I have to do. I open the text file in 2.34, select the default cube and the error comes up: Invalid sintax.

ya it is meesed up untill the author or a mod fixes the post

Cringe

Okay, it is updated.

LetterRip

can someone post a windows build for this ??? Or can the added patch change get put into CVS ???

I’ve implemented ‘binning’ - that is, I subdivide the screen into a grid, and assign each vert and face to one of the grid locations.

Then I only process those faces that the mouse shares the same grid as.

I probably have some bugs in my implemenation, and there are probably smarter and faster ways to do things. However, slower computers should see a speed up.

The ways to improve speed are

  1. reduce the radiusMaximum
  2. zoom in
  3. increase the updateFrequency (the higher it is, the more pixels that must be moved before it updates)

import Blender
from Blender import Object, NMesh, Window, Draw, Mathutils, Types
from Blender.Mathutils import *
from math import sin, cos, sqrt, pi, hypot

# Import Psyco if available, psyco can often give substantial speed ups
#try:
#	import psyco
#	psyco.log()
#	psyco.profile()
#	psyco.full()
#except ImportError:
#	pass


#
# ideas for the future are
# 1) back face culling
# 2) image based alpha maps
# basically just need to implement the image loading and selection code
# see this link for ideas on how to do it
# https://blenderartists.org/forum/viewtopic.php?t=16326&highlight=getpixel 
#
# 1) select edge loops that are perpendicular to the direction of motion
# 2) select face loops
# those would be nice for doing muscles for instance
# will implement rectanuglar formulaic alpha maps shortly
# tricolor displacement might be intersting
# ie each color represents displacement in the x, y, or z
# I'd like paintable selection
# and paintable fall off
# for symetric selection have a look at makehuman and the file
# MHsymmetry.py
# I'd also like to have an option where the alpha maps direction
# follows the direction of the mouse for implementing 'nudge'
# and pinch - perhaps use the mouse direction as a vector to affect the mesh
#
# other ideas are to make all of the changes to displacement maps
# which would then make it easy to 'drag' features around
# as well a maintaining ultra low poly models
# we could also create alpha maps from an object which would be pretty sweet
# a paint roller and tiling mode for alpha maps
# paint roller mode only affects mesh when you are moving between a specifed
# direction/angle range
# tiling mode treats the alphamap as a a tile

displaceMode = 1 # 0 is off, 1 is displaceOut, -1 is displaceIn, 2 is Smooth
# smooth isn't implemented yet

#displacementHeight should be turned into displacement ratio
#that is usally we want the height to stay proportional to the radius
#of the selection
#the level of zoom right now significantly affects the selection, because
#selection is in pixels, whereas displacement is in vert coordinates
#we can if we want, scale the displacement to pixels... thus a zoomed in
#view would displace much less than a zoomed out view.
displacementHeight = .5
selectedVerts = []
dictOfAlphaMasks = {}
win_min_x = win_min_y = win_max_x = win_max_y = win_mid_x = win_mid_y = win_size_x = win_size_y = 0
boundx_max = boundy_max = boundx_min = boundy_min = 0 #these are the bounding coordinates for the object
mouseX = mouseY = 0
obj_mat_times_persp_mat = Matrix()
#the above are the corners of the 3d view window, and the scaling factors
myMesh = NMesh.New("temp")
radiusMinimum = 5 # the smallest size of the selection radius in pixels
radiusMaximum = 20 #this gives us a grid size of 100 x 100 which isn't that big of a savings
			#the smaller the grid size the greater the savings
alpha_size_x = alpha_size_y = 2*radiusMaximum
# no user friendly gui yet
# to change the formula used, change fallofftype to
# one of None, Linear, Sin, Cos, SquareRoot, Squared, Cubic, and Quadratic
# then change the selectionRadius
# the xsize and ysize of the image are the first two numbers of the MaskID
# except in the case of the radial functions, in which case it is the radius
# also may change it to inner and outer radius or other such stuff
# the string is the id of the mask ID for formula based it is falloffType + maxRadius
falloffType = "Linear"
selection_size_x = selection_size_y = selectionRadius = 20
maskName = falloffType+repr(selectionRadius)
MaskID = (selectionRadius,selectionRadius,maskName)
boundingBox = []

myObject = Blender.Object.New('Mesh')
lastViewVector = [-100,100,-100] #right now these doesn't do much
currentViewVector = [-100,-100,-100] #but, if we allow screen rotation then they will trigger an update of the matrices

obj_mat = Matrix() #contains the matrix of the object (local? or global? I think global.)
perspMatrix = Matrix() #contains the perspective Matrix, and allows the screen coordinates to be projected to the screen

dictFaces = {}
faceNormalWorldVecDict = {}
facedotVecDict = {}
vectorDirtyDict = {}
cacheVecCoMultDict = {}
vectorDirty = False
# gets the mesh data from the selected object
# finds the selected verts
# and then selects verts based on the alpha mask
def initialize():
	global myObject, myMesh, currentViewVector, lastViewVector
	myObject = Object.GetSelected()[0]
	if myObject.getType() == 'Mesh':
		myMesh = myObject.getData()	
		name = myObject.name
	else:
		print "we either did not have a mesh or did not have an object selected"
	mouseX, mouseY = Window.GetMouseCoords()
	updateViewCoords(mouseX, mouseY)
	mouseInView3DWindow(mouseX, mouseY)
	currentViewVector = Window.GetViewVector()
	lastViewVector = currentViewVector
	initializeFaceLists()
	updateRadius(MaskID[0], 0, falloffType) #this initializes the starting alphamask

#we could actually create two lists from each, one that contains the faces with normals towards the
#camera, and the other without, and thus traverse our faces a bit faster...
#also we could use smaller grid subdivisions, which means fewer faces and verts per bin
#which means likely faster
#however, because I'm a slacker we'll try it with a one size fits all bin size and not make seperate
#lists
def initializeFaceLists():
	selection = {}
	global myMesh, dictFaces, faceNormalWorldVecDict, facedotVecDict
	global vectorDirtyDict, cacheVecCoMultDict
	dictFaces = {}
	faceNormalWorldVecDict = {}
	facedotVecDict = {}
	vectorDirtyDict = {}
	cacheVecCoMultDict = {}
	global alpha_size_x
	global alpha_size_y
	global VectorDirty
	facedotVec = 0.0
	VectorDirty = False
	viewVector = Vector(Window.GetViewVector())
	objectWorldMatrix = myObject.getMatrix('worldspace')
	perspMatrix = Blender.Window.GetPerspMatrix()
	obj_mat_times_persp_mat = objectWorldMatrix*perspMatrix
	for face in myMesh.faces:
		gfn = VecMultMat(Vector(list(face.normal[:3])+[1.0]), objectWorldMatrix)
		gfn = Vector(list(gfn[:3]))
		faceNormalWorldVecDict[face] = gfn
		facedotVecDict[face] = DotVecs(gfn, viewVector)
		for vertex in face.v:
			if vertex not in selection:
				#calculate the vertex screen coordinates...
				vectorDirtyDict[vertex.index] = vertex.co
				tempVec = vertex.co		
				hvs = VecMultMat(Vector(list(tempVec[:3])+[1.0]), obj_mat_times_persp_mat)
				hvs[0] /= hvs[3]
				hvs[1] /= hvs[3]	

				vs = [int(win_mid_x + (hvs[0] * win_size_x)),
					int(win_mid_y + (hvs[1] * win_size_y))]					
				cacheVecCoMultDict[vertex.index] = vs
			else:
				vs = cacheVecCoMultDict[vertex.index]
			##### now ...

			vert_grid_x = vs[0]/alpha_size_x
			vert_grid_y = vs[1]/alpha_size_y
			tempList = []
			try:
				tempList = dictFaces[(vert_grid_x, vert_grid_y)]
				tempList.append(face)
			except KeyError:
				tempList.append(face)
			dictFaces[(vert_grid_x, vert_grid_y)] = tempList
			selection[vertex] = True
	####and now we remove the duplicate faces
	for key in dictFaces.keys():
		listAppended = dictFaces[key]
		nd={}
		for f in listAppended:
			nd[f]=None
		dictFaces[key] = nd.keys()

# takes a vert and based on its screen location relative to the mouse
# is displaced according to an alphaMaskDict
# radius and falloff are done via computing the mask once
# the alphaMaskDict is specified by a MaskID
# mask ID is a tuple
# with four values,
# Xoffset, Yoffset, "maskName"
# for radius functions, maskName is "FallOffTypeRadius"
# ie for a linear of radius 8, it would be Linear8
# and the tuple would be (8,8,"Linear8")
# for imagebased, it is usually the image name
def DisplaceSelection(MaskID, mouseX, mouseY, displaceMode=0, displacementHeight= 0.0):
	global myMesh, dictOfAlphaMasks, alpha_size_x, alpha_size_y, dictFaces, faceNormalWorldVecDict
	global facedotVecDict, cacheVecCoMultDict, vectorDirtyDict

	selection = {}
	if MaskID not in dictOfAlphaMasks:
		# should handle image masks as well, but for now, we will handle only the radius masks
		updateRadius(MaskID[0], 0, falloffType)
	alphaMaskDict = dictOfAlphaMasks[MaskID]
	maskOffset = []
	maskOffset.append(MaskID[0])
	maskOffset.append(MaskID[1])
	displaceMH = displacementHeight*displaceMode
	mouse_and_maskX = maskOffset[0] - mouseX
	mouse_and_maskY = maskOffset[1] - mouseY
	viewVector = Vector(Window.GetViewVector())
	objectWorldMatrix = myObject.getMatrix('worldspace')
	perspMatrix = Blender.Window.GetPerspMatrix()
	obj_mat_times_persp_mat = objectWorldMatrix*perspMatrix
	emptyVector = Vector()
	#### here we find which grids the alphamask is in, and return a list of faces
	try:
		list1 = dictFaces[((mouseX + maskOffset[0])/alpha_size_x, (mouseY - maskOffset[1])/alpha_size_y)]
	except KeyError:
		list1 = []
	try:
		list2 = dictFaces[((mouseX + maskOffset[0])/alpha_size_x, (mouseY + maskOffset[1])/alpha_size_y)]
	except KeyError:
		list2 = []
	try:
		list3 = dictFaces[((mouseX - maskOffset[0])/alpha_size_x, (mouseY - maskOffset[1])/alpha_size_y)]
	except KeyError:
		list3 = []
	try:
		list4 = dictFaces[((mouseX - maskOffset[0])/alpha_size_x, (mouseY + maskOffset[1])/alpha_size_y)]
	except KeyError:
		list4 = []
	listAppended = list1+list2+list3+list4
	####and now we remove the duplicate faces
	nd={}
	for f in listAppended:
		nd[f]=None
	listAppended = nd.keys() 
	for face in myMesh.faces:
		if (face in listAppended):
			if faceNormalWorldVecDict[face] == emptyVector:
				gfn = VecMultMat(Vector(list(face.normal[:3])+[1.0]), objectWorldMatrix)
				gfn = Vector(list(gfn[:3]))
				faceNormalWorldVecDict[face] = gfn
				facedotVecDict[face] = DotVecs(gfn, viewVector)
			elif vectorDirty:
				gfn = faceNormalWorldVecDict[face]
				facedotVecDict[face] = DotVecs(gfn, viewVector)
			facedotVec = facedotVecDict[face]
			if facedotVec > 0: # simple backface-culling
				faceDirtyCount = 0
				for vertex in face.v:
					if (vertex.index not in selection):
						# we need to calculate the distance of the vert from the mouse
						# thus we need either the screen x and y of the vert
						# or the UV x,y of the mouse and of the vert
						# the offset is the distance from the mouse location, to the lower left corner
						# of the mask
						try:
							tempCo = vectorDirtyDict[vertex.index]
						except KeyError:
							tempCo = None
						if tempCo == vertex.co:
							vs = cacheVecCoMultDict[vertex.index]
						else:
							vectorDirtyDict[vertex.index] = vertex.co
							tempVec = vertex.co
							hvs = VecMultMat(Vector(list(tempVec[:3])+[1.0]), obj_mat_times_persp_mat)
							hvs[0] /= hvs[3]
							hvs[1] /= hvs[3]	

							vs = [int(win_mid_x + (hvs[0] * win_size_x)),
							int(win_mid_y + (hvs[1] * win_size_y))]					
							cacheVecCoMultDict[vertex.index] = vs
									
						deltaX = vs[0] + mouse_and_maskX
						deltaY = vs[1] + mouse_and_maskY
						try:
							thisDisplacement = alphaMaskDict[(deltaX, deltaY)]
							vertex.sel = 1
						except KeyError:
							thisDisplacement = 0.0
							vertex.sel = 0
						if vertex.sel == 1:
							#if we are just updating the selection
							if displaceMode == 0:
								pass
							#if we are displacing the vertex out
							#or if we are displacing the vertex in					
							elif (displaceMode == 1) or (displaceMode == -1):
								tempDisplace = thisDisplacement*displaceMH
								vertex.co[0] += vertex.no[0]*tempDisplace
								vertex.co[1] += vertex.no[1]*tempDisplace
								vertex.co[2] += vertex.no[2]*tempDisplace
								#since the vertex changed,
								#we need to update the faces normal
								#information based on the new vertex location
								faceDirtyCount += 1
								###we need to find the new screen location of the moved verts
	### and if they are in a new grid locations we need to add the face to the new grids face list
	# we should probably pop the face off of its original face lists if we expect verts to change
	# quadrants frequently otherwise our facelists will soon have faces that shouldn't be in it...
	# of course we may rebuild our face list often enough that this might not be a significant issue
	# perhaps we should rebuild a single face list based on its length

	#we might also consider subdividing a grid if it has more than a certain number of faces
							#this is to let the loop know that we've already handled this vertex
							#so it doesn't do calculations on it twice
							selection[vertex.index]=True
							#right now we don'l have smooth implemented
				if(faceDirtyCount > 0):
					faceNormalWorldVecDict[face] = emptyVector
					 


					

#displaces verts towards the vert average normal
def SmoothSelection():
#we need to first calculate the average normal for the selected verts
#probably we should exlude outliers to give better results
#then find the difference between average normal and the current verts normal
	print "we smoothed the selection"	
	pass

# takes an image and its size (or just an image and gets the size from the image?
# use code ideas from this link to implement
# https://blenderartists.org/forum/viewtopic.php?t=16326&highlight=getpixel
# instead of doing positive and negative numbers
# i define all locations from the lower left corner
def alphaMaskDictFromAlphaMap(xsize, ysize, alphamap):
	global dictOfAlphaMasks
	alphaMaskDict = {}
	for x in range(0, xsize):
		for y in range (0, ysize):
			alphacoords = (x,y)
			thisDisplacement = alphamap.alphacoords
			alphaMaskDict[alphacoords] = thisDisplacement
	MaskID = (int(xsize/2),int(ysize/2), alphamap.name)
	dictOfAlphaMasks[MaskID] = alphaMaskDict
#
#
def updateRadius(selectionRadius, deltaRadius, falloffType):
	global MaskID, dictOfAlphaMasks
	print "update radius"
	selectionRadius += deltaRadius
	if selectionRadius < radiusMinimum:
		selectionRadius = radiusMinimum
	if selectionRadius > radiusMaximum:
		selctionRadius = radiusMaximum
	maskName = falloffType+repr(selectionRadius)
	MaskID = (selectionRadius, selectionRadius, maskName)
	if MaskID not in dictOfAlphaMasks:
		dictOfAlphaMasks[MaskID] = alphaMaskDictFromRadius(selectionRadius, falloffType)
	selection_size_x = selection_size_y = selectionRadius
	return selectionRadius

def updateDisplacement(displacementHeight, deltaHeight):
	displacementHeight = displacementHeight + deltaHeight
	return displacementHeight
#
# not needed but would be nice
def drawSelectionCircle(selectionRadius):
	#print "Drawing the selection circle"
	pass

# creates an alphamask from the radius supplied
# this gives two benefits - the first is that we can use any alphamask
# instead of using just radius based functions with falloff
# the second is that this gives us a lookup table and we don't have to
# calculate the radius function a bazillion times
def alphaMaskDictFromRadius(radius = 8, falloffType = "None"):
	#note that instead of negative numbers, I'm using an offset of
	#of the radius, and use all positive numbers
	thisRadius2 = 0
	radius2 = radius*radius
	alphaMaskDict = {}
	for x in range(0, radius):
		for y in range(0, radius):
			thisRadius2 = x^2+y^2
			if thisRadius2 <= radius2:
				thisRadius = sqrt(thisRadius2)
				thisDisplacement = radiusFunction(thisRadius, radius, falloffType)
				alphaMaskDict[( x+radius,-y+radius)]=thisDisplacement
				alphaMaskDict[(-x+radius, y+radius)]=thisDisplacement
				alphaMaskDict[(-x+radius,-y+radius)]=thisDisplacement
				alphaMaskDict[( x+radius, y+radius)]=thisDisplacement
	return alphaMaskDict

# falloffTypes are None, Linear, Sin, Cos, SquareRoot, Squared, Cubic, and Quadratic
# these are adapted from 'Taper and Twist'
# by flippyneck
def radiusFunction(thisRadius, maxRadius, falloffType="None"):
	if falloffType == "None":
		return 1.0
	if falloffType == "Cubic":
		return interpolateCubic(0,maxRadius, thisRadius)
	elif falloffType == "Quadratic":
		return interpolateQuadratic(0,maxRadius, thisRadius)
	elif falloffType == "Linear":
		return interpolateLinear(0, maxRadius, thisRadius)
	elif falloffType == "Sin":
		return interpolateSin(0, maxRadius, thisRadius)
	elif falloffType == "Cos":
		return interpolateCos(0,maxRadius, thisRadius)
	elif falloffType == "SquareRoot":
		return interpolateRoot(0,maxRadius, thisRadius)
	elif falloffType == "Squared":
		return interpolateLinear(0,maxRadius, thisRadius)
	
def interpolateLinear(min, max, myVal):
	''' returns 0.0 <= myVal <=1.0 '''
	return myVal/float((max-min))
		
def interpolateSin(min, max, myVal):
	n=interpolateLinear(min, max, myVal)
	return sin(n)

def interpolateCos(min, max, myVal):
	n=interpolateLinear(min, max, myVal)
	return cos(n) 

def interpolateSquared(min, max, myVal):
	n=interpolateLinear(min, max, myVal)
	return n**2

def interpolateRoot(min, max, myVal):
	n=interpolateLinear(min, max, myVal)
	return sqrt(n)

def interpolateCubic(min, max, myVal):
	n=interpolateLinear(min, max, myVal)
	return n**3

def interpolateQuadratic(min, max, myVal):
	n=interpolateLinear(min, max, myVal)
	return n**4

# ********************************************************************************

# init screen coordinates
# these should be updated if the screen is resized, etc.
def updateViewCoords(screen_x, screen_y):
	global win3d, win_mid_x, win_mid_y, win_max_x, win_max_y, win_min_x, win_min_y
	global win_size_x, win_size_y, acceptable_min_x, acceptable_min_y, acceptable_max_x, acceptable_max_y
	global selection_size_x, selection_size_y
	for win3d in Blender.Window.GetScreenInfo(Blender.Window.Types.VIEW3D):
		win_min_x, win_min_y, win_max_x, win_max_y = win3d.get('vertices')
		win_mid_x  = (win_max_x + win_min_x) * 0.5
		win_mid_y  = (win_max_y + win_min_y) * 0.5
		win_size_x = (win_max_x - win_min_x) * 0.5
		win_size_y = (win_max_y - win_min_y) * 0.5

		acceptable_min_x = screen_x - selection_size_x
		acceptable_min_y = screen_y - selection_size_y
		acceptable_max_x = screen_x + selection_size_x
		acceptable_max_y = screen_y + selection_size_y
		if (win_max_x > screen_x > win_min_x) and (win_max_y > screen_y > win_min_y):
			return True
		else:
			return False

def mouseInView3DWindow(mouseX, mouseY):
# we calculate the screens midpoints and the scaling factor for the screen
# and then check if the mouse is in the view3d area
# we should really only do the calculations the first time
# thus it should prbably
	global win3d, win_mid_x, win_mid_y, win_max_x, win_max_y, win_min_x, win_min_y
	global win_size_x, win_size_y, acceptable_min_x, acceptable_min_y, acceptable_max_x, acceptable_max_y
	global selection_size_x, selection_size_y
	for win3d in Blender.Window.GetScreenInfo(Blender.Window.Types.VIEW3D):
		win_min_x, win_min_y, win_max_x, win_max_y = win3d.get('vertices')
		if (win_max_x > mouseX > win_min_x) and (win_max_y > mouseY > win_min_y):
			return True
		else:
			return False



	
# Here is the main loop
mouseStartX, mouseStartY = Window.GetMouseCoords()
mouseX = mouseY = 0
radiusIncrement = 5
updateFrequency = 0 # number of pixels to move before updating the vert selection
selectedVerts = []
updateBounds = True

initialize()
done = 0
while not done:
	evt, val = Window.QRead()
	if evt in [4]: #Draw.RIGHTMOUSE is 3 which is wrong...	
		# first we need to check if the mouse is inside the view3d boundbox
		currentViewVector = Window.GetViewVector()
		if currentViewVector != lastViewVector:
			lastViewVector = currentViewVector
			#vectorDirty = True
			#instead we will initialize the face lists...
			#this should probably be done elsewhere so that there isn't a huge lag on the firt RMB
			#press...
			initializeFaceLists()
		while Window.GetMouseButtons() == 4:
			if Window.GetKeyQualifiers() == 0:
				mouseX, mouseY = Window.GetMouseCoords()
				if mouseInView3DWindow(mouseX, mouseY):
					# determine if the mouse has moved far enough for an update
					mouseDistX = mouseStartX - mouseX
					mouseDistY = mouseStartY - mouseY
					mouseDistanceMoved = hypot(mouseDistX, mouseDistY)
					if mouseDistanceMoved > updateFrequency: 
						mouseStartX, mouseStartY = mouseX, mouseY
						old_mode = Window.EditMode()
						Window.EditMode(0)
						DisplaceSelection(MaskID, mouseX, mouseY, displaceMode, displacementHeight)
						myMesh.update()
						Window.EditMode(old_mode)					
						Blender.Window.Redraw(Window.Types.VIEW3D)
			elif Window.GetKeyQualifiers() != 0:
				if displaceMode == +1: displacement_string = "out"
				elif displaceMode == -1: displacement_string = "in"
				menu_result = Draw.PupMenu("Interactive Paint%t|%l|Selection Size: "+str(selectionRadius)+"%x1|Displacement: "+displacement_string+"%x2|%l|Quit%x3")
				if (menu_result == 1):
					selection_size = Draw.PupIntInput("Selection Size:", selectionRadius, 1, 100)
					deltaRadius = selection_size - selectionRadius
					selectionRadius = updateRadius(selectionRadius, deltaRadius, falloffType)
				if (menu_result == 2):
					displaceMode *= -1
				if (menu_result == 3):
					done = True
				Draw.Redraw (Window.QTest())


					
				#drawSelectionCircle(selectionRadius)

#	elif evt in [Draw.SKEY]:
#		if val:
#			displaceMode = 2 #smooth mode
#		else:
#			displaceMode = 0
	elif not val or evt in [Draw.MOUSEX, Draw.MOUSEY]: continue #helps speed
	elif evt in [Draw.ESCKEY, Draw.QKEY]: done = True	
	elif evt in [Draw.LEFTARROWKEY] and val: 	#shrink radius
		selectionRadius = updateRadius(selectionRadius, -radiusIncrement, falloffType)
	elif evt in [Draw.RIGHTARROWKEY] and val: 		#grow radius
		selectionRadius = updateRadius(selectionRadius, radiusIncrement, falloffType)
	elif evt in [Draw.UPARROWKEY] and val:				#grow displacementHeight
		displacementHeight = updateDisplacement(displacementHeight, 0.1)
	elif evt in [Draw.DOWNARROWKEY] and val:			#shrink displacementHeight
		displacementHeight = updateDisplacement(displacementHeight, -0.1)
	else:	#otherwise pass the event back and let Blender handle it
		id = Window.GetScreenInfo(Window.Types.VIEW3D)[0].get('id')
		Window.QAdd(id, evt, val)
		Window.QHandle(id)
		Blender.Redraw(-1) #don't forget to redraw
		pass

I opened with the latest BF blender build and run the python script but it came up with an error about “GetPerspMatrix”

My patch that has GetPerspMatrix hasn’t been applied yet to CVS, hopefully it will be approved at this meeting.

Tom M.
LetterRip

please will you release a compiled version

this is looking very nice… looking forward to a compilation also :slight_smile:

Hey all, according to the meeting notes my patch will soon be committed to CVS so you’ll be able to use it with the testing builds shortly.

I also have a new version of the script, just drop it in your script folder,

http://projects.blender.org/pipermail/bf-scripts-dev/2004-October/000015.html

Now you can do object rotation and other stuff without leaving the script.

Tom M.
LetterRip

even so is there no way to post a build ? As I have seen patches never get put in even if they said they would, or it just starts to take more time than first thought …

this is the worlds most trivial patch and allows a cool new toy, so I’m sure it is going in. I don’t have any place to host a build, sorrry.

Tom M.
LetterRip

on OSX, it is kinda slow.

Bug: Right click to paint will not work unless I rotate the view a tiny bit eash time I lift the button. The alt click to change the mode and presure is gone. Where can I change it to use the left click button ? As it screws up my wacom tablet buttons, and left click is standard among all clay 3d molding apps, Wings, Zbrush…

but it is very much welcome in blender and hope that you can make it even better :smiley:

Here is the latest version

http://wiki.blender.org/bin/preview.pl/Blenderdev/SculpMesh

The code for GetPerspMatrix has been commited to CVS so you should be able to use pure CVS builds now to use the script.

Bug: Right click to paint will not work unless I rotate the view a tiny bit eash time I lift the button.

Fixed, was waiting for a CVS fix.

The alt click to change the mode and presure is gone.

Nope it is still present, not certain why it wasn’t working for you though.

Where can I change it to use the left click button ?

I think there is still something that needs to be fixed in CVS yet before it can be done easily. I’ll let you know shortly.

LetterRip

This is a useful discussion showing the speed gains possible for matrix multiplications in python:

http://www.scipy.org/documentation/weave/weaveperformance.html

As you can see some are quite impressive.