Need help with lil script

Hello guys!
As I prepare my game, I’ve been once again tackling a problem I’ve encountered from the beginning.
Use one mesh for the entire terrain. This has been done one a planar mesh, but it’s much difficult to me to make it work on a spherical mesh.
My theory is the following:

  1. Get the vertices position in the sphere and save them somewhere.
  2. Use the positions multiplied by the object orientation, the get the vertices global position and then apply a noise function to get an altitude.(The sphere will orient it’s denser part towards the camera).
    3.Set the vertex position added by the vector pointing from the center of the object to that vertex multiplied by the altitude.

Result: Every time the sphere rotates, a new set of values is acquired.
I really don’t see where the problem is, I believed my maths were correct, but it shows I’m wrong!
Script:


import bge, mathutils
from mathutils import*


def map(ob):
    ob= ob.owner
    mesh= ob.meshes[0]
    ob["map"]=[]
    for a in range(mesh.getVertexArrayLength(0)):
        b=()
        vert= mesh.getVertex(0,a)
        vp= vert.getXYZ()
        b= (vert, vp); ob["map"].append(b)
    ob["on"]= True    
        
def up(ob):
   
    ob=ob.owner
    for v in ob["map"]:
        vert=v[0]; vp= v[1]
        pos= vp*ob.orientation
        h= mathutils.noise.hybrid_multi_fractal(pos, 0.21, 1, 3, 0.5, 0.75, 3)
        p= vp+(ob.getVectTo(vp)[1]*(h*10))
        n= Vector((0.1,0.1,0.1))+(ob.getVectTo(vp)[1])*(h*5)
        vert.setXYZ((p))
        vert.setNormal((n))

blend

Thank you for your time!

Of course you’re going to get new values. You multiply vp by the object’s orientation to get pos which you use as in argument in the noise function. Thus rotating the object changes the noise you get on each vertex.

Yes, the idea is to get a global position for the vertices. This means that for any vertex at a specific global position, the value should be the same! Means that if I rotate the sphere, the appearance of the heightmap should be the same, as if a global texture map is used as displacement map!

Hi,

i guess you have to transform the vertices in global coordinate,
but in this case can be almost avoidable .(maybe, i not understand well what do mathutils.noise)

try to put the mathutil.noise on this ,to replace the simple random.random .
it actually change just the magnitude.


import bge


import random
from mathutils import Vector




bge.logic.setLogicTicRate(1000)
def map(cont):
    ob = cont.owner
    mesh = ob.meshes[0]
    ob["map"] = {}
    for vN in range(mesh.getVertexArrayLength(0)):
        vertId = mesh.getVertex(0, vN)
        vertPos = tuple(vertId.XYZ)
        #print(vertPos)
        if not vertPos in ob["map"] :
            ob["map"][vertPos] = [vertId]
        else :
            ob["map"][vertPos].append(vertId)
    ob["on"] = True    
    print(ob["map"])
        
        
def up(cont):
    ob = cont.owner
    for vp in ob["map"]:
        vp2 = Vector(vp)
        vp2.magnitude *= 1+random.random()*0.05
        for vertId in ob["map"][vp]:
            vertId.setXYZ(vp2)
        

Actually, I just need their global position, the vert.setXYZ(), sets the vertices locally, so I need to get the values globally and apply then locally! The noise function will give me a “nice” procedural heighmap.
I think you don’t understand the whole thing…
Explanation in portuguese:
Com o noise de mathutils, adquiro um valor por cada posição, quero que toda vertice que estiver naquela posição adquira aquele valor. Mas eu acho que o erro vem da atribuição do valor nas vertices localmente.

Trnaslation:
Wthi the noise function, I acquire a spcific value for each position in space. I need to get the same position for the same position. The error ma come from the local assignement of the values to the vertices.

Edit: MarcoIT, your script generates a different value per vertex everytime! Not what I want!

I think I got the entire setup wrong!

to transform the vertex local in global make this:

vertGlobal = ob.worldTransform * vertLocal

so, change value, then , re-transform it in local space with :

vertLocal = ob.worldTransform.inverted() * vertGlobal

the first function (map(cont)) should speed up a bit the script

“Edit: MarcoIT, your script generates a different value per vertex everytime! Not what I want!”

but is more dynamic in this way :evilgrin: , i not know how make it :wink:

Found the problem.

You aren’t converting vp to world coordinates properly. Multiplying vp by the orientation matrix rotates vp, but in the opposite direction you want. What you should do is make vp a Vector and use the Vector.rotate() method. This should solve your problem.

You should also note that you haven’t made your script translation invariant, so moving the object will alter the results as well. To fix this, you need to include the object’s world position in vp.

Sorry, I’m kind of lost here! I tried getting a vector form ob to vp then use rotate(ob.orientation), I get a None value. Could you elaborate it a bit more?

Yes the object’s translation should bring new values, it’s expected and desired!

umh, i got now what do mathutil.noise (not really … how is possible ?_?)

this seem that work :slight_smile: : (lack the the normal)


import bge, mathutils
from mathutils import*
bge.logic.setLogicTicRate(1000)


import random


def map(cont):
    ob = cont.owner
    mesh = ob.meshes[0]
    ob["map"] = {}
    for vN in range(mesh.getVertexArrayLength(0)):
        vertId = mesh.getVertex(0, vN)
        vertPos = tuple(vertId.XYZ)
        #print(vertPos)
        if not vertPos in ob["map"] :
            ob["map"][vertPos] = [vertId]
        else :
            ob["map"][vertPos].append(vertId)
    ob["on"] = True    
    print(ob["map"])
        
        
def up(cont):
    ob = cont.owner
    for vp in ob["map"]:
        vp2 = Vector(vp)
        h = mathutils.noise.hybrid_multi_fractal(vp2, 0.21, 1, 3, 0.5, 0.75, 3)
        vp2.magnitude *= 1.0+h*0.1 
        for vertId in ob["map"][vp]:
            vertId.setXYZ(vp2)

The Vector.rotate() method doesn’t return anything, it just rotates the vector in place. I believe MarcoIT’s method will work fine as well (just use pos = ob.worldTransformation * vp).

Just off subject I’m trying to put a song across all of my menu screens in blender game but i don’t know how can you help?

Thank you guys for your efforts, but the result is still the same as mine. This video shows how I want the displacement:

Got it!
here’s the code:


# Global procedural displacement script


import bge, mathutils
from mathutils import*


#Mapping the half sphere's vertices. We need to save those initial positions to calculate the height
# value on the current vertex position.( displacement will disturb the position


def map(ob):
    ob= ob.owner
    mesh= ob.meshes[0]
    ob["map"]={}
    
    # looping through all vertices in the object. It's better if the object has few...
    for a in range(mesh.getVertexArrayLength(0)):
        
        vert= mesh.getVertex(0,a)                           # Getting the vertex
        vp= vert.getXYZ()                                   # Getting vertex local position
        vp=(round(vp[0],2),round(vp[1],2),round(vp[2],2))   # Reduce the vertex position by 2 decimals, for easy saving
        
        if not vp in ob["map"].keys():
            ob["map"][vp]=[vert]                            # Add vertex to dict
        else:
            b= ob["map"][vp]; b.append(vert)                # Add vertex to existing vertex list
            
    ob["on"]= True                                          #Telling that the object is ready for displacement


# Update will calculate the height values per vertex group position globally and apply them to those vertices locally.       
def up(ob):
    #mathutils.noise.hybrid_multi_fractal(position, H, lacunarity, octaves, offset, gain, noise_basis=noise.types.STDPERLIN)
    ob=ob.owner
    
    for vp in ob["map"].keys():
        
        pos= (ob.worldTransform*Vector(vp))                         # Getting the vertex global position
        
        h= mathutils.noise.multi_fractal(pos, 10.01, 120.0, 3, 1)   # Calculating detail heigh values
        h1= mathutils.noise.turbulence(pos,12, 0, 1, 1.5, 0.5)      # Calculating general elevation
        h2=(h1*4+h*8)                                               # Summing up the heights
        
        p= (ob.getVectTo(vp)[1]*(25570+h2))                         # Setting the vertex local position. 25570 is the sphere's radius
        
        n= Vector((0.1,0.1,0.1))+(ob.getVectTo(vp)[1])*(h+h1)       # Calculating the normal( still have to tune the values)
        
        for vert in ob["map"][vp]:
            vert.setXYZ((p))                                        # Applying values to the vertices
            vert.setNormal((n))                                     # Applying Normals
            
    ob.reinstancePhysicsMesh()                                      # Setting the physics mesh
           

Well done torakunsama. I couldn’t actually determine what behaviour you were looking for, but I do have some pointers
If you could take a look at this Python proposal; http://www.python.org/dev/peps/pep-0008/
Python is, at the end of the day, interpreted code, and most of the advice in PEP8 won’t make it run any faster (or differently for that matter). Yet, most of the time in using programs the programmer does not care as much about his program once it is completed. Until they have to patch it, or change it a year later. In such a case as this, it becomes hard to remember what you were thinking at the time of writing. This is where PEP8 comes in. It means that other programmers can understand what you were doing, and your future self from 2055 can too! I think it would be of great help to you and to others if you consider the style guide. You don’t have to follow all of it if you don’t wish to, it merely just provides the underlying convention rules!

Best of luck as ever, Angus.

Thank you Angus! I’ve been trying to get this thing to work for so long, that I forgot to respect a few conventions before asking for help…
This script can benefit other users as well, it’s still at a primitive state, but, who knows?