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

Interesting,

However, matrix multiplication isn’t a huge bottleneck right now except for when changing the view on a large mesh.

I have two faster versions of the script available now. One is a bug fix to the above which reduces the number of faces processed.

The second is a new method that projects the mouse onto the mesh instead of the faces to the window, which is a huge drop in the number of matrix multiplications.

However, since I was caching everything anyway it isn’t as big a speed up as I expected.

I can’t post them right now though, someone else is doing an edit on the wiki…

The matrix speed up will help for when changing views, but I’m not going to invest time in it right now. (Of course others are more than welcome to do so >grin>).

LetterRip

hi LetterRip, following this thread with interest.

So you know, I’ve just download and built the latest from CVS with the newly commited patch. When running the script posted to the Wiki, the following error shows up:

“Version mismatch: script was written for Blender 235. It may fail with yours: 234.”

and then blender hangs. Tried to edit the script but I don’t see anything.

Hope it helps. Thanks and good luck.

It hangs?

you can change the 235 to 234

so it was you that was keeping me from updating the script <grin>

I’ve been checking it for the past half hour so I can post the newest version…

It probably wasn’t hung, I just don’t have visual feedback right now when the script starts.

LetterRip

Most recent version, you can ignore the warning. the 235 is to indicate it needs to be the cvs version.

Also it doesn’t give visual feedback when it starts, so you might not realize it has started. Wait a few seconds then start RMB on the object.

LetterRip


#!BPY

"""
Name: 'Sculpt Mesh...'
Blender: 235
Group: 'Mesh'
Tip: 'Sculpts mesh pushing and pulling'
"""

# $Id:sculpt_mesh.py,v .22 2004/10/20 03:53:31 Tom Musgrove Exp $
#
#===============================================#
# Sculpt Mesh v 0.22 by Tom Musgrove (LetterRip)#
#		       and Michael Schardt	#
# if you have any questions about this script   #
# email LetterRip at gmail dot com              #
#                                               #
#===============================================#

# -------------------------------------------------------------------------- 
#  Sculpt Mesh v 0.21 by Tom Musgrove (LetterRip) and Michael Scardt
# -------------------------------------------------------------------------- 
# ***** BEGIN GPL LICENSE BLOCK ***** 
# 
# This program is free software; you can redistribute it and/or 
# modify it under the terms of the GNU General Public License 
# as published by the Free Software Foundation; either version 2 
# of the License, or (at your option) any later version. 
# 
# This program is distributed in the hope that it will be useful, 
# but WITHOUT ANY WARRANTY; without even the implied warranty of 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
# GNU General Public License for more details. 
# 
# You should have received a copy of the GNU General Public License 
# along with this program; if not, write to the Free Software Foundation, 
# Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. 
# 
# ***** END GPL LICENCE BLOCK ***** 
# -------------------------------------------------------------------------- 


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

# commented out because psyco causes a segfault if you rotate the mesh for
# some reason...
# Import Psyco if available, psyco can often give substantial speed ups
#try:
#	import psyco
#	psyco.log()
#	psyco.profile()
#	psyco.full()
#except ImportError:
#	pass

displaceMode = 1 # 0 is off, 1 is displaceOut, -1 is displaceIn, 2 is Smooth
# smooth isn't implemented yet
displacementHeight = 1.0 #
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)



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
#the above are the corners of the 3d view window, and the scaling factors
mouseX = mouseY = 0
obj_mat_times_persp_mat = Matrix()
myMesh = NMesh.New("temp")
selectedVerts = []
dictOfAlphaMasks = {}
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
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
			if facedotVecDict[face] &gt; 0:
				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
			else:
				pass #we aren't interested in faces with a negative normal value
			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 alphaMask
# 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 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 &gt; 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
						#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
					except KeyError:
						thisDisplacement = 0.0
						vertex.sel = 0
						selection[vertex.index] = False
					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
							
							#right now we don'l have smooth implemented
			if(faceDirtyCount &gt; 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 &lt; radiusMinimum:
		selectionRadius = radiusMinimum
	if selectionRadius &gt; 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 &lt;= 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 &lt;= myVal &lt;=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 &gt; screen_x &gt; win_min_x) and (win_max_y &gt; screen_y &gt; 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 &gt; mouseX &gt; win_min_x) and (win_max_y &gt; mouseY &gt; 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 [Draw.RIGHTMOUSE]: #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 &gt;= 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


Also realize it is TODAYS CVS, the commit was only a few hours ago, so the builds at the builds forum don’t have the function you need.

LetterRip

Yah, no, still getting hangs. Don’t know what that is. Also, if I change the “Blender 235” at the menu listing there’s no change regarding the error. Is that the only place to change? A search doesn’t reveal 235, 2.35, or version, in the script. Anyway, the CVS built with Cygwin if that means anything. Full version Python is installed and working. Cygwin Python is up to date and defaults to whatever the CVS is using so should be 2.33 but BF is a mystery sometimes.

I was having some trouble with the wiki too, web stopping pemisions belong to someone else though. <girin>

[edit]
just downloaded the new post here in the thread. No hangs :slight_smile:
and yah, CVS was checked out after reading the commit logs so patch should be in place.

Now I can’t get it to do anything so I’m going to go back and look for instructions. Thanks for the tool. Black and Decker.

Here are a bit more directions

  1. Create an object
  2. Subdivide to the level your computer can handle
    For my computer about 20,000 faces is OK with an Athlon 2500

If you are zoomed in you can have a (much) larger number of faces - For instance a typical poser model is 60,000 faces and I can do some work on them when I’m highly zoomed in.

  1. Have a scripts window open
  2. get the object as large as possible in your screen - this program does subdivision based on screen coordinates, thus the more of the screen you can use the better.
  3. Run the script SculptMesh … ’ from your scripts menu.
  4. Move your mouse to the 3D viewwindow and wait a few seconds the bigger the mesh and slower your computer the longer you should wait. What is happening is that Blender is precomputing everything so that it can just look up calculations instead of performing them each time.

Now press RMB and drag on the surface of your object. You should start seeing faces move around - ooooo ahhhhh… Occassionally there is some initial problems getting the mesh to start displacing, just try the RMB and drag a couple of different times.

If you press RMB + ALTKEY (or CNTRLKEY) you can change some parameters (such as the displacement amount, the displacement radius, etc.)

If it isn’t fast enough for you, you can edit the script and reduce the maximum radius. This will decrease the size of the ‘bins’ and thus Blender will have fewer faces to compute each time.

Also, you can zoom in and this will also reduce the size of the bins.

Hope this helps,

LetterRip

Great script. I love it.
There were some problem with RMB. It grabbed the mesh instead of displacing it. This seems to be fixed in the last version.
And Blender crashes when rendering, even with a cube which is subd’ed only once… a subdivided cube without displacing renders just fine…
Keep up that great work.

D.

PS: Could you provide a download for a textfile? Konqueror has some problems with copy’n’paste scriptcode…

The crash when render is a known problem, Ianwill is investigatiing.

I’ll post a link to a text file later today,

Tom M.
LetterRip

Still having problems, but I did get the script to play. In your instructions you mention a Script Window. Now that there actually is a Scripts Window the Text window is a different beast :-? ? Script won’t run from the Script window but the menu is there. Still has to run from a text window to get any life. This may have had something to do with my original miscue (not your instructions, the text window).

This next bit is going to be a little vague. When the script is running, I click on the mesh and it simply pops up several vertices to a single height and then just stops. Then clicking just does nothing. Except when in a certain place, I’m really not sure, the script will keep moving the same vertices in the certain place but nowhere else. So exit the script, rotate the view a bit, run the script and the same place is active but that’s it. But only sometimes will there be a sweet spot. Mostly just the initial single jump to a fixed height, if anything all. And even though there isn’t any vertice activity the popup menu is still available. My feeling is the sweet spot seemed to be in a highly tangent area from the veiw . . .

Mesh size, location and rotation have been zeroed.
Using the script posted above. $Id:sculpt_mesh.y,v .22 2004/10/20 03:53:31 Tom Musgrove
My machine is a 2.4ghz Pentium IV with 1.5G ram
I actually re-built the Windows binary again thinking I may’ve been early to the CVS.
Built with Cygwin and Make.

I’d try patching but the only source I keep around is the latest check-out and I am already too close to the abyss. Needing light and shadow now. Hope it helps.

Marty,

right now the displacement amount is not neccessarily going to be reasonable for your mesh. You can edit it by hand in the text editor window. I’ll have it automagicly adjust to your mesh size in a day or so,.

Yes the scripts window and text editor window are different. For the scripts window go to Mesh -> sculpt_mesh

This is prerelease - and is mostly to get the code out for developers to have a look at, it isn’t really intended for artists (yet) except power users. It will be nice and easy to use before the actual release, and will have much better functionality(check back in about three or four days). Up to this point I’ve been working on speed and making sure the core functionality and infrastructure was available.

Now I’m working on making things ‘automagic’ and accessible.

LetterRip

Yes, of course. Thought you might like to have a humble beta tester’s p.o.v. [grin]

Still a little confused and I don’t want to sound all machismo and stuff that is not what I’m saying, Mesh/Scripts is accessible from edit mode only and so the script only runs in object mode and when I click in edit mode after running the script I only get a single vertice in motion? Apologies. I shouldn’t probably even say anything. :frowning: I’m also seeing the demo video do a good deal more than I can seem to. Almost looks like proportional editing except the object doesn’t appear to be in edit mode.

Looking forward to seeing a final version!! Please take your time too. Someday when I have a more powerfull machine maybe we’ll have the ability to sculpt and then paint a displacement map onto a character mesh directly in blender. A worthy goal. :smiley:

It is now quite fast, especially on zoomed in meshes.

There is some processing that has to take place when you first press the RMB, so there will be some lag. Also there is sort of visual feedback that you have entered the mode (generally your mesh material will look different when you are sculpting with RMB.)

Also, I recommend pressing the ESC key if you want to rotate, pan, etc.

while you can do it while in the script it is probably a lot faster to just enter and exit the script (unless you are working on a small mesh).

I’ve been working with meshes of 400,000 faces, and can work on mesh of 60,000-120,000 faces being only slightly zoomed in (the more zoom the faster you go…).

Now that the most critical of the speed issues are largely solved, I’ll start expanding the functionality.

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

At the top of the page is the currently planned functionality (stuff that will be implemented shortly, some even before the next release…)

There is a display bug I’m having where sometimes the mesh dissappears entirely when you press the RMB, and sometimes part of the mesh dissappears. This is related to the new code for speeding things up. Not sure what the cause is yet…

LetterRip

Fixed a stupid math error and now no more disappearing mesh,

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

LetterRip

Here is the link I promised, sorry it had slipped my mind, now you can just save instead of copy and paste.

http://wiki.blender.org/pub/Blenderdev/SculpMesh/sculpt_mesh_fast.py.txt

let me know if there are any issues.

LetterRip

I use a smooth-sub-devided cube. Every time when I press RMB, the sub-devided mesh becomes to the orginal cube with 6 vertices.

Ok,

I’m creating a temp object to work on, apparently the properties of the original object aren’t copying over correctly I’ll look into that.

LetterRip

yet another advanced TEDDY
http://www.vrmesh.com/images/Extrusion.gif

VRMesh is a new style of sketch-based free-form 3D polygonal modeling software, which is based on our new groundbreaking techniques ?Smart Form and Digital Clay. It is a powerful, flexible and comprehensive tool for the general modeling work, and especially suitable for the earlier (conceptual) design communication in the 3d industrial design and development process.

Feature highlights in VRMesh:
Smart Form
Digital Clay
Profile Edit
Fillet, Knife, Extrusion, Boolean…

Oyster,

the script can only displace actual vertices. I would suggest subdividing by selecting all vertices (AKEY) the using the subdivide (WKEY) in editmode. I’d recommend subdividing till you have at least about 400 faces - typically I work on 6000-20000 faces.

The subdivision you are currently using is only for display purposes thus only the 8 vertices of the original cube are actually editable.

Of course that doesn’t fix your problem - thus far I can’t seem to find a way to copy the property regarding visual subdivision over.

LetterRip

Apologies in advance for my ignorance in this area :slight_smile: I’ve tried to run the script, but I can’t get it to work. I’m not actually all that sure what to do, I went to the text window, selected my mesh and opened the text file. I pressed alt+p but got some error.
Do you know what I’m doing wrong? I am literally a complete newbie to scripts, all I’ve actually done is install python and set the python path in blender so I could get the wavefront obj export to work.