Worst Script ive ever writen! Horrible performance trying to highlight objects.

So i was trying to write a script to conect the dots on the verticies of a plane in order to highlight them, which actualy will work using this script if you first sort the vertices. But… It Runs SOOOOO Slow! Ive got a realy nice computer running linux, and it has never given me any sort of problem. (60 fps with a uv sphere with over 130000 faces)

This gave it trouble! it when all of the objects in the scene were selected, it was down to 6 fps!

Long story short this is terrable and i need a new meathod for hilghting or a way to fix the code.

Here it is:

import bpy
from bge import render , logic
from mathutils import Vector
co = logic.getCurrentController()
# Changed is a sensor that checks if the "Selected" property has changed
Changed = co.sensors["Changed"]
own = co.owner
scene = logic.getCurrentScene()
OL = logic.getCurrentScene().objects
if own["Selected"] == True:
    # function to set the vertex mesh point to the actual world position
    def GetVertPosition(vert,obj):
        vertex = Vector(vert)
        pos = Vector(obj.worldPosition)
        vertex += pos    
        return vertex
    # get the position vertxces of the owner (in a round about way)
    for item in bpy.data.objects:
        if item.name == own.name:
            if item.type == "MESH":
                vertlist = [vertex.co for vertex in item.data.vertices]
                obj = OL[item.name]
    #setting the position list to be global positions           
    for vert in vertlist:
        vertex = GetVertPosition(vert,obj)
        vertlist[vertlist.index(vert)] = vertex
    # draw the outlines by connecting the dots ##note## must first sort vertex points
    for vert in vertlist:
        try: render.drawLine(vert, vertlist[vertlist.index(vert)+1], [1,0,1])
        except IndexError: render.drawLine(vert, vertlist[0], [1,0,1])

This code has to be run every frame or the line doesent show up.

Here is what i need from you:

a. A diferent meathod for showing that a flat plane object is selected (these planes are countries in a kind of risk game)

or

b. a way to make this code run faster.

Thanks! :slight_smile:

This is normal. What you do is like you run around your car and turn move it by pushing against each of the wheels rather then starting the engine.

It sounds like you want to show the wireframe of the mesh?

Just set material to wireframe mode and shadeless and you get the effect. I assume you still want to see the original material. In that case you can addObject a copy of the mesh with wireframe material.

Alternative: use a shader.

@Kylona

  1. You’re using the BPY module in the BGE. It’s not usable in a runtime, so don’t use it.
  2. You’re looping through each object in the scene to get the currently selected one. You already have a reference to it.
  3. You’re getting a vertex list for the current object each frame. You only need to get it once, and then store it.
  4. You’re looping through the vertex list twice. Since the first loop is populating the list with the vertex list with the reference to the vertex (why do that right after writing the vertex positions to the same list?), it again only needs to be done once, after which it can be stored.

EDIT: But I would just go with Monster’s method - if you want to show something is selected, just create a duplicate mesh and make it slightly larger. Or, create a ‘cursor’ mesh that copies the mesh of the selected object / section, with increased scale (Python’s replaceMesh() function would be helpful here).

The methods Monster suggested probably are the easiest. But if you want to use bge.render.drawLine then this may be a script you could use:

from bge import render

edgeColor = [1, 1, 1]

def init(own):
    verts = getVerts(own)
    own['edges'] = getEdges(verts)

def getVerts(own):
    pos = own.worldPosition
    mesh = own.meshes[0]
    verts = []
    for i in range(4):
        vert = mesh.getVertex(0, i).XYZ + pos
        verts.append(vert)
    return verts

def getEdges(verts):
    edges = []
    for i in range(3):
        edges.append([verts[i], verts[i+1]])
    edges.append([verts[3], verts[0]])
    return edges

def highlight(cont):
    own = cont.owner
    if 'edges' not in own:
        init(own)
    edges = own['edges']
    drawLines(edges)

def drawLines(edges):
    for edge in edges:
        x, y = edge
        render.drawLine(x, y, edgeColor)

Edit: Much simpler as already suggested is using a separate object. I don’t want to give the wrong example here, so you better use the method in the second blend. Especially because it doesn’t have to run every logic tic when hovering over the plane.

Attachments

HighLighting01.blend (75.9 KB)HighLighting02.blend (76.5 KB)

When I think of Selection Highlighting, then I guess you want the Object to be OUTLINED. For that, as suggested by Monster, you might simply use a Shader: By feeding a Vector Math Node set to Dot or Cross Product with the View and Normal Coordinates you can easily get a fading “Rim” Effect (which I tend to then chas through a “Power” Math Converter of some Value over 1.0) and with a “Less Than”/“Greater Than” Math Converter you can get a sharp Outline, pretty much “Cel Shading” (it actually is) and then you can mix that celshaded Outline with a Color of your Choice.

You would either have to exchange the Mesh with a Mesh of the outlined Material in Case of Selection, or your Outline Visibility is bound to Vertex Colors or Object Colors (faster), which can be changed when the Object is selected.

Either that or you really want a Wireframe on your Object. Then also use a Shader and just blend in a second Material set to “Wireframe”.

@Monster: Does the Shader method work on multitexture. The graphics in this game are simple so i havent been using GLSL.
@SolarLune: Thanks I didn’t know BPY wouldent work. also i think ill go with the replace mesh, of a cursor object, if the shading method won’t work.

I dident exactly understand the shading method…

No shaders are by its nature GLSL only. For outline you can use the “doublicate, scale and invert mesh” method in all modes. This is pretty generic, but means quit a lot of work for the modeller.

ok so im going with the addobject method. i have a cursor object (just a cube) and i have succesfully added it to the scene, but i now need to change its mesh, when i create a proxy, how do i get it? How can i access the new object?

Edit: i found it online,

proxy = scene.addObject(proxy,own)

The newly meshed object has lost its material. How can i set a material?

I use such highlighting method in my adventure. Each selectable object gets two additional objects with a slightly modified mes. Each of the meshes is a little bit larger as the selectable object’s mesh with semi-transparent material and the normals are inverted.
One object has white material to act as isHover. The other has yellow material to act as isFocused.

The hover method is simple: whenever the mousecursor is over a selectable object a property is set at this object. The property gets reset when mouse cursor is not over object. A keyboard UI is possible too. All it needs to do is setting/resetting this property.

The selectable objects show the hiver object when the property is set and hide when reset. How they do is up to the objects. This means you can establish different methods of shiwing/hiding e.g. Switch visibility, addObject/endObject, animation, motion.

You can even build a manager object that triggers the according hover objects. So the logic is not at the selectable+hover but at hover manager+hover.

Focus is nearly the same as hover (but with a differenct property ;)). The difference is, that you can have multiple objects focused, and you tricker differently. E.g. By mouse click, keyboard or even by game logic.

Edit: Videos showing the adventure: Add-A-Thing: Sci-Fi Doors prototype look at the things under the cursor.
Library: Simple selection