color faces of mesh with python

how can you color the individual faces of my mesh depending on distance to e.g. a different object?
This is possible with bpy but i need to execute the script in-game.

for face in object:
__distance = get distanceTo(object2)
__if distance > 5:
____face.color(rgb)

Any ideas?

<b>from</b> <b>bge</b> <b>import</b> logic
cont = logic.getCurrentController()
object = cont.owner

<b>for</b> mesh <b>in</b> object.meshes:
   <b>for</b> m_index <b>in</b> range(len(mesh.materials)):
      <b>for</b> v_index <b>in</b> range(mesh.getVertexArrayLength(m_index)):
         vertex = mesh.getVertex(m_index, v_index)
         <i># Do something with vertex here...</i>
         <i># ... eg: color the vertex red.</i>          vertex.color = [1.0, 0.0, 0.0, 1.0]

http://www.blender.org/api/blender_python_api_2_73_5/bge.types.KX_MeshProxy.html#bge.types.KX_MeshProxy

We do have an API and forum code tags.

Wow thanks for the reference :slight_smile: I will dive into it, ill try to finish this thread by tomorrow thanks

I did some testing and this is my result:



pro:
-amazing results thanks to colors

contra:
-only in untextured shading -> no detailed objects
-colors vertices but not faces :frowning:

any ideas?

Instead of
getVertex(matid, index)¶Gets the specified vertex from the mesh object.Parameters:

get
getPolygon(index)Gets the specified polygon from the mesh.

function
http://www.blender.org/api/blender_python_api_2_73_5/bge.types.KX_MeshProxy.html#bge.types.KX_MeshProxy.getPolygon

result
http://www.blender.org/api/blender_python_api_2_73_5/bge.types.KX_PolyProxy.html#bge.types.KX_PolyProxy

Also you have to change the material settings, if you want to enable vertex colors.

ok wow thanks,
ill stick to it :slight_smile:

So I am getting polygons but their material is read-only…
Blender told me via console that the polygon matindex is not writeable :frowning:
Am I’m doing something wrong or is it time to close this thread and look for a workaround?

http://www.blender.org/api/blender_python_api_2_73_5/bge.types.KX_PolyProxy.html#bge.types.KX_PolyProxy.v1

v1vertex index of the first vertex of the polygon, use this to retrieve vertex proxy from mesh proxy.
[TABLE=“class: docutils field-list”]
[TR=“class: field-odd field”]
[TH=“class: field-name, bgcolor: #EEDDEE, align: left”]Type:[/TH]
integer
[/TR]
[/TABLE]
v2vertex index of the second vertex of the polygon, use this to retrieve vertex proxy from mesh proxy.
[TABLE=“class: docutils field-list”]
[TR=“class: field-odd field”]
[TH=“class: field-name, bgcolor: #EEDDEE, align: left”]Type:[/TH]
integer
[/TR]
[/TABLE]
v3vertex index of the third vertex of the polygon, use this to retrieve vertex proxy from mesh proxy.
[TABLE=“class: docutils field-list”]
[TR=“class: field-odd field”]
[TH=“class: field-name, bgcolor: #EEDDEE, align: left”]Type:[/TH]
integer
[/TR]
[/TABLE]
v4Vertex index of the fourth vertex of the polygon, 0 if polygon has only 3 vertex Use this to retrieve vertex proxy from mesh proxy.
[TABLE=“class: docutils field-list”]
[TR=“class: field-odd field”]
[TH=“class: field-name, bgcolor: #EEDDEE, align: left”]Type:[/TH]
integer
[/TR]
[/TABLE]

It is actually simple, would have made a example, but blender is not currently on my machines.

Get the vertex indexes, then change their color by .getVertex(mat_id, index).
vertex_1 = mesh.getVertex(0, polyproxy.V1)
So you basicallu only use the polyproxy to identify the vertex indexes of a face.

Apart from why you would want per face distance when per vertex would blend the colors better, here it is:
http://i.imgur.com/S4YOfzH.gif

from bge import logicfrom mathutils import Vector
from math import sin
cont = logic.getCurrentController()
object = cont.owner


scene = logic.getCurrentScene()
objects = scene.objects
cube = objects["Cube"]


cubePos = cube.worldPosition
spherePos = cont.owner.worldPosition


def averagePos(vertPosList):
    temp = Vector()
    for pos in vertPosList: temp += pos
    return temp / len( vertPosList )


for mesh in object.meshes:
    for p_index in range( mesh.numPolygons):
        polyProxy = mesh.getPolygon(p_index)
        polyMatID = polyProxy.material_id
        polyIndex = [polyProxy.v1,polyProxy.v2,polyProxy.v3]
        if polyProxy.v4: polyIndex.append(polyProxy.v4)  
        
        polyVerts = [ mesh.getVertex(polyMatID, v_index) for v_index in polyIndex ]     
        
        polyPositions = [ vert.getXYZ() for vert in polyVerts ]         
        
        facePos = averagePos( polyPositions )
        
        faceWorldPos = spherePos + facePos
        
        dist = ( cubePos - faceWorldPos ).length
        
        dist /= 20.
        
        color = [ sin( dist ) ** 2 , sin( dist * 2  ) **2  , sin( dist * 0.77  )  , 1 ] 
        
        print( color )
        for vertex in polyVerts:
            vertex.color = color
    
      

The example is crude, but it is something at least.

Attachments

colorFaces.blend (558 KB)

Wow thank you so much!! This is more than I ever wanted!
I think I can close the thread, the result of your amazing work is going to be presented in my game I am working on!

You wondered why per poly coloring… Its to keep the low poly esthetic
Over time green habitable polygons are going to spread on the sparse grey polys of the inhabitable planet!

If you like ill credit you

Thanks, nolzett :slight_smile:

for some reason everything works well in your blend,
in my blend the color of my object doesn’t change and stays white even though nothing is set to white…
Also the polygon positions are very weird and don’t match their actual 3d space coordinates :mad:

I attached a blend file which also is the current game I am working on

please help thx,
nolzett

Attachments

rocketier.blend (1.75 MB)

def planetPlants_stone():    
    own = logic.getCurrentController().owner # you are coloring what here??? the object is which&gt;
    scene = logic.getCurrentScene()
    
    planet = scene.objects['planet_stone'] // this should be used instead of own


You are coloring the wrong object…

Polygons are relative to their owner.
You have to calculate yourself the world position of them based on the owner pos and scale(, or transform matrix)

Also, there seems to be a problem with when triangles and quad faces are mixed…
Triangulating removed the artifacts on faces that were skipped in the coloring.

HA ! okey thanks so much:D I would have never conceived this problem.

HI again!

now I am trying to ‘read’ the vertex.color because this is a good way to e.g. only add trees on the green and not on the light green polys.
BUT it doesn’t read it correct for example a set color [.2,.7,.2,1] reads [0.200,0.680,0.200,1.000]
is there some python magic to filter this or round the results? so the color can be read like this if vertex.color == [.2,.7,.2,1]:

Hi! If you set the vertex green to 0.7 it should be equal to 0.7. Anyway, if you want to get 0.7 from 0.68, you can use round() python function: https://docs.python.org/3/library/functions.html#round

Take care about the note:

The behavior of round() for floats can be surprising: for example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: it’s a result of the fact that most decimal fractions can’t be represented exactly as a float. See Floating Point Arithmetic: Issues and Limitations for more information.

But print(round(2.68, 1)) gives you 2.7 .

You can also say:

if vertex.g &gt;= 0.68:
    # Do something

I just tried: if vertex.color == [round(value,1) for value in green]:
but it didn’t work

[round(value,1) for value in green] generates a list…

Normally, the code looks like this:

mesh = own.meshes[0]
for i in range (mesh.getVertexArrayLength(0)):
    vertex = mesh.getVertex(0, i)
    if vertex.g &gt; 0.68: # or round(vertex.g, 1) == 2.7:
        #Do something

Yup but I directly compared full RGBA lists that way it is easier to change colors on the fly! But it still doesnt work so ill be looking for some other issues

HURRAY! [solved]
finally did it :smiley: learn new things every day!

did it with a global list
then write and read data per poly off this list!