mathutils.rand

I have a code snippet to create a mesh which I render
to make a spaceship hull texture. The idea is to write
a script to automate an old tutorial by Iforgethisname*
to use Blender/Gimp for hull textures.

But… I seem to have a problem with mathutils.Rand.
It seems to give a very bad pseudo random distribution.

What’s the deal/is this a bug?

Here’s the code which gives a satisfactory result with
the standard python random.random() function ( line 60)
but if you put line 61 back in there are non random “lines”
of detail visible…

import Blender
from Blender import NMesh,Object,Material
from Blender.NMesh import Vert,Face
from Blender.Mathutils import *

import random

def bigger(a,b):
	if min(a) > min(b) : 
		return -1
	else: 
		return 0

def ranPairs(l,w,n=1):
	return [(l*Rand(0.5,1),w*Rand(0.5,1)) for i in range(n)]

def toVert(x):
	'''x a list/Vector returns Vert'''
	return Vert(x[0],x[1],x[2])

def rectangle(l,w,x,y,z):
	offSet =Vector([x,y,2*z])
	
	#rectange centered (0,0) 
	myRect = [[l,w,0],[-l,w,0],[-l,-w,0],[l,-w,0]]
	return [toVert( .5*Vector(p)+ .5*offSet
					    ) for p in myRect]

def shades():
	xx = int(Rand(150,255)) #shades of Grey
	return [NMesh.Col(xx,xx,xx,255)]*4


tube = ((0,1,5,4),
(1,2,6,5),
(2,3,7,6),
(3,0,4,7))


mesh2 = NMesh.GetRaw()
mesh2.hasVertexColours(1)
mesh2.materials =[Material.Get("vxCols")]
mesh2.verts = []


ranRects=ranPairs(5,5,30)
ranRects.extend(ranPairs(6,2,10))
ranRects.extend(ranPairs(1,1,100))
ranRects.extend(ranPairs(.5,.5,40))
ranRects.extend(ranPairs(10,.2,10))
ranRects.sort(bigger)

z=0
for rect in ranRects:
	
	l,w = rect
	if Rand(0,1) > .5:
		l,w = w,l

	x,y = 30*random.random(),30*random.random()
	#x,y = 30*Rand(0,1),30*Rand(0,1) commented out
	z+= .009
	
	#create a bevel
	mesh2.verts.extend(rectangle(l,w,x,y,z))
	mesh2.verts.extend(rectangle(l*.9,w*.9,x,y,z+.01))

	myShade = shades()
	for vces in tube:
		ff = Face()
		ff.v = [mesh2.verts[i-8] for i in vces]
		ff.col = myShade
		ff.mat = 0
		mesh2.faces.append(ff)
	
	#create face
	ff = Face()
	ff.v = mesh2.verts[-4:]
	ff.col = shades()
	ff.mat = 0
	mesh2.faces.append(ff)

    
NMesh.PutRaw(mesh2)

	

try Noise


import Blender
from Blender import NMesh,Object,Material,Noise
from Blender.NMesh import Vert,Face
from Blender.Mathutils import *

random = Noise.random

def bigger(a,b):
   if min(a) > min(b) :
      return -1
   else:
      return 0

def ranPairs(l,w,n=1):
   return [(l*Rand(0.5,1),w*Rand(0.5,1)) for i in range(n)]

def toVert(x):
   '''x a list/Vector returns Vert'''
   return Vert(x[0],x[1],x[2])

def rectangle(l,w,x,y,z):
   offSet =Vector([x,y,2*z])

   #rectange centered (0,0)
   myRect = [[l,w,0],[-l,w,0],[-l,-w,0],[l,-w,0]]
   return [toVert( .5*Vector(p)+ .5*offSet
                   ) for p in myRect]

def shades():
   xx = int(Rand(150,255)) #shades of Grey
   return [NMesh.Col(xx,xx,xx,255)]*4


tube = ((0,1,5,4),
(1,2,6,5),
(2,3,7,6),
(3,0,4,7))


mesh2 = NMesh.GetRaw()
mesh2.hasVertexColours(1)
mesh2.materials =[Material.Get("vxCols")]
mesh2.verts = []


ranRects=ranPairs(5,5,30)
ranRects.extend(ranPairs(6,2,10))
ranRects.extend(ranPairs(1,1,100))
ranRects.extend(ranPairs(.5,.5,40))
ranRects.extend(ranPairs(10,.2,10))
ranRects.sort(bigger)

z=0
for rect in ranRects:

   l,w = rect
   if Rand(0,1) > .5:
      l,w = w,l

   x,y = 30*random(),30*random()
   #x,y = 30*Rand(0,1),30*Rand(0,1) commented out
   z+= .009

   #create a bevel
   mesh2.verts.extend(rectangle(l,w,x,y,z))
   mesh2.verts.extend(rectangle(l*.9,w*.9,x,y,z+.01))

   myShade = shades()
   for vces in tube:
      ff = Face()
      ff.v = [mesh2.verts[i-8] for i in vces]
      ff.col = myShade
      ff.mat = 0
      mesh2.faces.append(ff)

   #create face
   ff = Face()
   ff.v = mesh2.verts[-4:]
   ff.col = shades()
   ff.mat = 0
   mesh2.faces.append(ff)


NMesh.PutRaw(mesh2)

btw are you speaking of IceMan?

Mathutils.Rand() is reseeding the random number generator on each call. This is probably not a good idea.

:expressionless:

You are (both) probably right.

BTW I don’t see how to reseed the generator.
There’s nothing in the doc nor in the docstrings.

I suppose Rand() is ok for 1 or 2 throwaway “random” numbers
but I don’t really see the point of this function as it duplicates
(badly) what is done well by functions in other modules.

Noise.setRandomSeed(seed_value)

how to un-re-seed, I really don’t know

What stiv means is that internally in blender it is reseeding during each call.
From Mathutils.c:

//***************************************************************************
// Function:                                    M_Mathutils_Rand


//***************************************************************************
static PyObject *M_Mathutils_Rand(PyObject *self, PyObject *args)
{

        float high, low, range;
        double rand;
        high = 1.0;
        low = 0.0;

        if (!PyArg_ParseTuple(args, "|ff", &low, &high))
                return (EXPP_ReturnPyObjError (PyExc_TypeError,
                                                "expected optional float & float
"));

        if ( (high < low) ||(high < 0 && low > 0))
                return (EXPP_ReturnPyObjError (PyExc_TypeError,
                                                "high value should be larger than low value
"));

        //seed the generator
        BLI_srand((unsigned int) (PIL_check_seconds_timer()*0x7FFFFFFF));

        //get the random number 0 - 1
        rand = BLI_drand();

        //set it to range
        range = high - low;
        rand = rand * range;
        rand = rand + low;

        return PyFloat_FromDouble((double)rand);
}

See how it calls BLI_srand() every time Rand() is called?
Ideally it would only be called the first time Rand() is called.

The idea is that since the math module isn’t part of the cut-down python distributed with blender, if scripts use them then the user has to have a full python2.3 install. However if the script uses Blender.Mathutils instead then it will run on the small install packed with blender.

Can someone post a bug report for this to blender.org. This will get fixed.

OK I tried it with Noise.random() which comes with Blender
and I get a similar result to random.random() from the full python distribution so I’m a happy panda.

Can someone report the bug please. I only have one e-mail
and blender.org says it’s already registered so I can’t…

PS and it’s another thread :-? it’s a shame that there aren’t some
of the PIL functions in the Blender python module. Now that
Blender doesn’t have to fit on a single disquette why not?