Creating mesh's in code

carlo

04-11-2005 09:55:01

Ok, I've been bashing my head against this for a while, trying to understsand how I can create a mesh manually in pyogre. I was following one of the c++ code snippets on the wiki (Generating a mesh), but once I get to:

*snip*RenderSystem* rs = Root::getSingleton().getRenderSystem();
RGBA colours[nVertices];
RGBA *pColour = colours;
// Use render system to convert colour value since colour packing varies
rs->convertColourValue(ColourValue(1.0,0.0,0.0), pColour++); //0 colour


things fall apart. Obviously I need to pass a uint32 pointer to the function, but my python knowledge is not that far advanced.

Hopefully someone else out there has been creating mesh's in python manually and can offer some assistance.

Thanks.

carlo.

Clay

04-11-2005 19:24:58

Sorry, this is still on the todo list. Creating/manipulating meshes in python is one of the most complicated things we have to do, and we haven't fully gotten around to it yet.

carlo

04-11-2005 19:47:33

Doh.

I found a py script in the SVN called grassdemo.py, and another on the forums with a flag generated from python code.

Are these two scripts supposed to work? Mine always crash out when thye need to use ogre.VertexBuffer() (which I cant find in the pyogre lib). I just downloaded the latest files for ogre and pyogre and compiled them both, but it didnt seem to do anything.

Given that I need to be able to create geometry from code, what do you think about the idea of creating a convenience function in c++ which takes my geometry, and returns a mesh (or Line3D:SimpleRenderable) which can be slotted into the scene graph...

cya
carlo.

Clay

05-11-2005 21:18:45

They are not supposed to work. They were written for the Boost.Python version of pyogre, and I have not gotten that wrapped in the new pyogre. This is my top priority right now, and I'm working on it right now.

Our sandbox/ directory is our testing directory. Anything you find in there probably does not work. If it did work we would clean it up and move it to the demos directory.

futnuh

08-11-2005 12:25:15

Sorry, this is still on the todo list. Creating/manipulating meshes in python is one of the most complicated things we have to do, and we haven't fully gotten around to it yet.

Ability to programmatically define/manipulate geometry from python (Numeric arrays?) would be extremely helpful to our pyOgre needs. We might be able to fund this development if it meant that the work got done sooner rather than later ;-)

Clay

08-11-2005 12:38:19

I've been working on CEGUI attributes for the release this saturday. If this is a real priority I'll start working on this. The primary holdup here is I've never done this stuff in C++ Ogre, so I'm going to first have to learn how to do it there then figure out what needs to be done to make this work in PyOgre.

You mentioned numeric, which I was considering. I have taken a look at Numarray and that might be what I use to do this with. Do you have any preference as to which library? I see there is also numpy which also has a recent release date, but I'm not sure which is the "perfered" library.

Donations are welcome (I don't think I have it properly set up yet in BerliOS yet), but I'll do this no matter if you donate or not. All proceeds from PyOgre go towards buying a mac mini so we can finally get a Mac OS X port going.

futnuh

08-11-2005 13:01:42

You mentioned numeric, which I was considering. I have taken a look at Numarray and that might be what I use to do this with. Do you have any preference as to which library? I see there is also numpy which also has a recent release date, but I'm not sure which is the "perfered" library.

Sorry, I really meant "some python array library". I should have said SciPy or NumArray. Numeric, no longer in development, should probably be avoided (though we still use it extensively as part of our in-house VR scenegraph software). I've used Numarray a little bit recently while teaching a python course. And it does have the nicer web page ;-)



All proceeds from PyOgre go towards buying a mac mini so we can finally get a Mac OS X port going.


Ah, this is another aspect of PyOgre high on our wishlist. Let me talk to the money people at work. What country are you located in?

Clay

08-11-2005 13:04:41

I'm in the USA.

So if you don't mind me asking, what are you guys using pyogre for? =)

futnuh

08-11-2005 13:30:30

So if you don't mind me asking, what are you guys using pyogre for? =)

I recently parachuted in from the OpenSceneGraph community. I haven't quite committed to Ogre/pyOgre yet but am becoming more and more sure with each passing day.

Our group does scientific visualization including a lot of custom VR applications. We work for free for (our) university researchers but also do contract work for Australian museums. Python is our glue of choice. We have an in-house python system based on the now-defunct Cosmo scenegraph library but this desperately needs to be retired. I've been using OpenSceneGraph for a couple of projects but this has been pure C++. Faced with a new VR project on an extremely short deadline, I can't see using OpenSceneGraph this time round ... so here I am looking at Ogre/PyOgre.

The specific project is a miniature recreation of an 18th-century active diorama created by the London-based painter and set designer Philipp de Loutherbourg. http://www.acmi.net.au/AIC/LOUTHERBOURG_BIO.html (See the Eidophusikon section part way down.)

Our mockup will show a real de Loutherbourg "spectacle" from the front, and from the rear a passive stereo "behind the scenes" display. We've got a couple of cultural historians, a lighting designer, a sound engineer, an architect and a visualization programmer (me) volunteering on the project. The miniature stage and projection system will be finished tomorrow so it is time to focus on content (real and virtual) ...

Clay

08-11-2005 15:23:17

Wow, nice. =)

My current todo list:

Major Items
  1. Learn to create meshes manually in C++.[/*:m]
  2. Wrap manual mesh creation.[/*:m]
  3. Create a Dagon branch.[/*:m][/list:u]

    Minor Items (done when they need to be done)
    1. Prepare for next release.[/*:m]
    2. Continue to fix bugs.[/*:m][/list:u]

griminventions

08-11-2005 21:16:06

@futnuh: Oh my god you have a cool job. :)

@Clay: I'll do anything I can to help get a Mac port running. Ask if you need some testing etc.

Clay

08-11-2005 21:31:53

NumArray is not looking good. Their namespace is polluted, and it's not C++ friendly.

From a numarray header:
typedef struct {
PyObject_HEAD
PyObject *operator; /* ufunc name */
PyObject *identity; /* identity value, e.g. 0 for + or 1 for * */
int n_inputs, n_outputs;
_ufunc_function call;
_ufunc_cache cache;
} PyUfuncObject;


Specifically:
PyObject *operator;
That's going to break any C++ compiler. After fixing that, it still breaks OgreHardwareVertexBuffer.h, and I can only assume it's because of some typedef or #define which conflicts with something in Ogre.

I don't think I'm going to wrap this with anything other than the basic python lists for now. I'm open to patches changing this later.

mingus

10-11-2005 22:02:03

I've just started learning PyOgre and come across the same problem... I'd like to be able to algorithmically create and transform mesh vertex data from python.

From the quick look I've had at a C++ example for creating a cube, I agree that it looks quite complex to wrap the Ogre API up into SWIG - handling the creation of the different buffer types (dynamic, write-only, etc) and declaring the vertex info interleaving with the VertexDeclaration class. Only once that's all working do you get the chance to pump data in and out with the readData and writeData methods. So I guess that's the first step?

I get the feeling that once the initial low-level API is exposed, it will be possible for people to implement their own "pythonic" interfaces on top of that if they're more interested in code productivity than performance, eg:

iterate through vertices:

for vertex in vertexBuffer :
print vertex.normal
vertex.diffuse = (0.1,0.2,0.3)


slice vertex buffers across elements:

normals = vertexBuffer.normals
for each normal in normals:
normal = normalize( myTransformFn( normal ) )


or that sort of thing...

I think the trick with getting a good pythonic API would be to get the read/write semantics of the different buffer types working conveniently and efficiently...?

Clay

10-11-2005 23:24:10

This is with the new pyogre. The grass (StaticGeometry) uses hardware buffers.


I still need to work out a few things, and a LOT of testing needs to be done, but it's working.

for vertex in vertexBuffer :
print vertex.normal
vertex.diffuse = (0.1,0.2,0.3)

I like that syntax. I'll see what we can do.

This would be much harder:
normals = vertexBuffer.normals
for each normal in normals:
normal = normalize( myTransformFn( normal ) )


Perhaps this would be better:
normalList = vertexBuffer.normals
normalList[0] = (1, 2, 3)
someTuple = normalList[7]

The problem with an iterator over the normals is when you say "normal = ..." you are assigning the normal variable to be a different reference and not the data itself.

I'll look into it.

fog

11-11-2005 11:08:04

This is with the new pyogre. The grass (StaticGeometry) uses hardware buffers.
Great work Clay. :D

This would be much harder:
normals = vertexBuffer.normals
for each normal in normals:
normal = normalize( myTransformFn( normal ) )


This would definitely be non-pythonic (and excessively hard to do.)

Ludo

14-11-2005 22:24:20

Wow, nice. =)

My current todo list:

Major Items
  1. Learn to create meshes manually in C++.[/*:m]
  2. Wrap manual mesh creation.[/*:m]
  3. Create a Dagon branch.[/*:m][/list:u]

    Minor Items (done when they need to be done)
    1. Prepare for next release.[/*:m]
    2. Continue to fix bugs.[/*:m][/list:u]


@clay
Would you be so kind and upload a PyCEGUI Windows-Installer?
I need some more advanced GUI for my mech simulation project but I am too lazy to build the PyCEGUI from source.

BTW great work, with python and pyogre I am faster in hacking some quick tests with OGRE and ODE. I'm convinced that I'll use pyogre for the next months or maybe years ;). IMHO python and pyogre are the best choice for home made games.

Last of all some (not ogre related) physics question. Do anybody know an other Physics-Engine-Binding for python than ODE? A Novodex binding would be great.

Clay

15-11-2005 00:13:12

I was waiting on fog to mark Ogre and CEGUI as stable. I'll go ahead and release an almagated installer (containing both CEGUI and Ogre) sometime tomorrow.

The linux "Release" (tarball with sources) will have to wait until next time I guess.

Clay

15-11-2005 11:12:44

@clay
Would you be so kind and upload a PyCEGUI Windows-Installer?
I need some more advanced GUI for my mech simulation project but I am too lazy to build the PyCEGUI from source.

I just released a new PyOGRE (1.0.5-1) which includes PyCEGUI. Future releases will have seperate installers for PyOgre and PyCEGUI.

BTW great work, with python and pyogre I am faster in hacking some quick tests with OGRE and ODE. I'm convinced that I'll use pyogre for the next months or maybe years ;). IMHO python and pyogre are the best choice for home made games.
Thanks. =)

Last of all some (not ogre related) physics question. Do anybody know an other Physics-Engine-Binding for python than ODE? A Novodex binding would be great.
I don't know of any other physics engine for python other than ODE. Out of curiosity, why not ODE? Having never used it before I don't know any pros/cons for it.

futnuh

15-11-2005 12:08:25

NumArray is not looking good ...
PyObject *operator;
That's going to break any C++ compiler.


Can you explain this in more detail? Why couldn't one "extern C" the NumArray stuff?

Ludo

15-11-2005 12:43:31

Thank you Clay, I'll try the new version this evening when I'm at home.

Related to ODE:
I am looking for an other Physics-Binding because ODE slows down when you use a lot of Bodies/Geoms which collide (stacking).
Also adjusting the CFM/ERM values in combination with a dynamic (fps dependent) ODE-Worldstep can be pain.
ODE isn't realtime and it's not that stable on slower cpu's. Sometimes the whole world "explodes" if some internal parameters run out of the expected range.
And last but not least, I tried to create a gyroscope to stabilize my mech, but the result don't looks realistic.
Maybe I am to stupid to use ODE the right way, but in this case I need an easier physics-binding.

Clay

15-11-2005 17:13:45

NumArray is not looking good ...
PyObject *operator;
That's going to break any C++ compiler.


Can you explain this in more detail? Why couldn't one "extern C" the NumArray stuff?

Had the NumArray maintainers done this it should work fine, but in the "nummacro.h" file maintainers clearly didn't do so. I'm unwilling to maintain my own "fixed" copy of NumArray to compile against. If they ever fix their library then I would be willing to look at it again.

---

Ludo:
Interesting... Thanks for letting me know. =)

Clay

15-11-2005 19:10:52

Sorry, I don't think I was thinking straight earlier.

Can you explain this in more detail? Why couldn't one "extern C" the NumArray stuff?
Actually there is another big problem with wrapping this using NumArray. A vertex declaration has many different "types" of values inside the declaration.

For example, if you have a vertex declaration consisting of POSITION, NORMAL, DIFFUSE, and TEXCOORDS...and lets say you are passing in 2 integers for the TEXCOORDS as well. This means for each Vertex you need to set the POSITION and NORMAL variables with 3 floats, but the DIFFUSE would require a uint32, and the TEXCOORDS would require 2 ints, in the code this would look something like this:

vertices.setFloat(0, 0, 1, 2, 3) # position
vertices.setFloat(0, 1, 0, 0, 1) # normal
vertices.setColour(0, 2, ogre.ColourValue()) # diffuse, actually unsigned int32
vertices.setInt(0, 3, 27, 32) # TEXCOORDS

Or some such.

The big problem comes from the fact that NumArray does not know how to deal with multiple types inside the same buffer. When you create a NumArray buffer you specify what type of buffer to create from these types:
Bool, Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float32, Float64, Complex32, Complex64

If I use NumArray, all vertex declarations created with this are all-or-nothing. I can't say "every 3-5th element out of 10 is a Uint32, everything else is Float32."

I'm open to suggestions on this, but I'm not sure it can be resolved so that using NumArray makes sense. I'm also open to checking out other libraries, but I'm not sure what else can be done on the matter.

Any ideas/thoughts?

mingus

21-11-2005 23:59:35

I'm open to suggestions on this, but I'm not sure it can be resolved so that using NumArray makes sense.

Even if the NumArray arrays can't be used directly as a target for vertex buffers, it might be useful to have some utility functions to quickly copy data backwards and forwards between the two. This would allow people using NumArray in the scientific community a relatively easy and powerful way to view their datasets.

I'm also open to checking out other libraries, but I'm not sure what else can be done on the matter.

Is it not enough to expose the buffer just as a chunk of memory? This could easily be parsed and manipulated in a Python wrapper, or a custom C module if speed is crucial. Perhaps Psyco is clever enough to provide a decent speed boost when applying a transformation to a whole buffer of vertex data?

Clay

22-11-2005 00:10:04

This is possible, but how would the data be exposed? A python list with each byte of the buffer as an entry? (Meaning a float would span 4 entries in the list, an unsigned short as two entries, etc?) Or did you mean something different?

Or even possibly wrapping a NumArray buffer with a single type?

mingus

22-11-2005 00:41:45

This is possible, but how would the data be exposed? A python list with each byte of the buffer as an entry?
I've never used them so don't know the pros and cons, but buffer objects look like they might be designed to do the job:
http://docs.python.org/api/bufferObjects.html

From the docs:
Using their ability to reference a block of memory, it is possible to expose any data to the Python programmer quite easily. The memory could be a large, constant array in a C extension, it could be a raw block of memory for manipulation before passing to an operating system library, or it could be used to pass around structured data in its native, in-memory format.

Clay

22-11-2005 00:55:54

Wow I never even knew about this....I'll look into it.

Thanks.

Clay

22-11-2005 04:37:21

Ok, I've wrapped this as HardwareBuffer.bufferLockRead and HardwareBuffer.bufferLockReadWrite (which also works for the subclasses, such as vertex/index buffers).

This function locks the hardware buffer, so you must call unlock after using either of these functions. I'm not sure of the implications of reading/writing to the buffer after you unlock them. If you create the hardware buffer with a ShadowBuffer then it might be safe to read from it, but I wouldn't bet on it. You should never never never write to the buffer after you unlock it, even if you created it with a shadow buffer.

A little caveat emptor. There's not really a way for me to ensure that these things happen, so I suggest you delete the Buffer object before unlocking the HardwareBuffer object, and if you don't unlock the HardwareBuffer object you will run into problems too. Use this at your own risk, though these problems could happen in C++ as well.

I'll commit this tomorrow sometime, since it seems BerliOS is down.

Clay

23-11-2005 16:24:45

Ok, comitted as of this morning.

fschulze

11-12-2005 16:18:57

Hello!

I'm new to PyOgre, but have a suggestion for the array interfacing. You should definitely look into this: http://numeric.scipy.org/array_interface.html It's an interface for arrays which is independant of the implementation. It will work with Numeric, numarray and scipy.base.

I just started looking into PyOgre, but it already looks really impressive. I'm looking forward to using it.

Regards,
Florian Schulze

Clay

12-12-2005 15:14:26

Yeah I looked this over too. It falls into the same problem as Numeric, numarray, and scipy.base has. That API cannot handle the case where multiple types inside an array are required. For a vertex declaration, it's possible that every 1st 2nd 3rd elements in a vertex declaration are floats, the 4th, 5th, and 6th elements are short ints and they repeat after that.

So your array would look something like this:
[13251.1343, 6542.1, 0.0, 1, 13, 200, 1.1, 2.2, 3.3, 2, 24, 500]

The interface doesn't really support that because each index can be different sizes (4bytes for floats, 2 for short ints, for example), and the closest thing they allow you to define this as is:
'V' -- Other (void * -- each item is a fixed-size chunk of memory)

Which does not accurately describe what's in the void pointer. (Each chunk is not a fixed-size.)

Thanks for the suggestion, but it's not usable with vertex declarations.

fschulze

12-12-2005 20:43:18

It should work like this:

__array_typestr__ == '|V18'
__array_descr__ == [('float1','<f4'), ('float2','<f4'), ('float3','<f4'), ('short1','<i2'), ('short2','<i2'), ('short3','<i2')]

If not, then you should contact the scipy.base developers, because they want to create an interface which is able to cover such situations. If everyone is doing his own thing, then we get more and more incompatibilities. I'm using news://gmane.comp.python.numeric.general to access the mailinglist.

Regards,
Florian Schulze

Clay

13-12-2005 03:30:20

Ah ok, I must have read it wrong. Alright, I'll go pester them for a bit. =)

esteban

03-01-2006 02:10:33

I did a little helper class to fudge with hardware vertex buffers in a pythonic way. It depends on only ogre and struct, which is a standard python module for handling string or buffer objects as low-level binary data (think C structs).

http://docs.python.org/lib/module-struct.html

Something similar could be done for hardware index buffers, but I didn't do that since I don't need it.

Currently it is not general enough to make it official(*), so I send it here just in case someone finds it useful. Maybe it's a starting point for more a complete wrapper.

As an usage example, say you have a submesh and you want to flip the normals of some vertices, only if they are pointing backwards from any of the faces that use the vertex (this example assumes only triangles are used, but the utility code does not make such assumption):


def repairNormals(submesh):
print "repairing normais in submesh with material", submesh.materialName

# This actually locks the buffer for read/write.
buff = HardwareVertexBufferWrapper(submesh.vertexData)

# Left 'expanded' for clarity.
for ai, bi, ci in submesh.indices:
a, b, c = buff[ai], buff[bi], buff[ci]

ap = ogre.Vector3(*a.position)
bp = ogre.Vector3(*b.position)
cp = ogre.Vector3(*c.position)

an = ogre.Vector3(*a.normal)
bn = ogre.Vector3(*b.normal)
cn = ogre.Vector3(*c.normal)

face_perp = (bp - ap).crossProduct(cp - ap)

if an.dotProduct(face_perp) < 0.0:
a.normal = -an.x, -an.y, -an.z

if bn.dotProduct(face_perp) < 0.0:
b.normal = -bn.x, -bn.y, -bn.z

if cn.dotProduct(face_perp) < 0.0:
c.normal = -cn.x, -cn.y, -cn.z



When the function returns, the buffer and vertex wrappers go out of scope and the underlying hardware buffer is unlocked automatically. If you wanted to go on with other stuff in the same function, you had better release all references to buffer or vertex wrappers:


del buff, a, b, c



You need to delete vertex wrappers because they keep buff alive. This is intentional, so you don't accidentally modify an unlocked buffer.

All in all, I recommend you use the wrapper like shown above, in small self-contained functions, so you make sure that the wrapper and all references to it get cleaned up as soon as possible. And it is good style, anyway ;).

So, the listing:


import struct

from pyogre import ogre

"Map ogre.VertexElementSemantic to python attribute name."
semantic_equivs = {
ogre.VES_POSITION: 'position',
ogre.VES_NORMAL: 'normal',
ogre.VES_TEXTURE_COORDINATES: 'texCoords',
}

"Map ogre.VertexElementType to struct format string."
type_equivs = {
ogre.VET_FLOAT2: 'ff',
ogre.VET_FLOAT3: 'fff',
}

class HardwareVertexBufferWrapper:
def __init__(self, vertexData):

self._elements = {}
for i in xrange(vertexData.vertexDeclaration.getElementCount()):
el = vertexData.vertexDeclaration.getElement(i)
name = semantic_equivs[el.getSemantic()]
if name in self._elements:
print "WARNING: I assume at most one VertexElement for each semantic."
self._elements[name] = el

if vertexData.vertexBufferBinding.getBufferCount() != 1:
print "WARNING: I assume exactly one buffer per vertexData."

self.vertexSize = vertexData.vertexBufferBinding.getBuffer(0).vertexSize
self._buffer = vertexData.vertexBufferBinding.getBuffer(0).bufferLockReadWrite()

def __getitem__(self, index):
return VertexWrapper(self, index)

def __del__(self):
# XXX: Assume only one buffer is used.
self._data.vertexBufferBinding.getBuffer(0).unlock()

class VertexWrapper:
def __init__(self, bufferWrapper, index):
# I use __dict__ here to avoid clash with __getattr__ and __setattr__.
self.__dict__['buffer_wrapper'] = bufferWrapper
self.__dict__['base'] = index * bufferWrapper.vertexSize

def __getattr__(self, name):
try:
el = self.buffer_wrapper._elements[name]
except KeyError:
raise AttributeError, name

base = self.base + el.getOffset()
return struct.unpack(
type_equivs[el.getType()],
self.buffer_wrapper._buffer[
base:base+el.getSize()])

def __setattr__(self, name, value):
try:
el = self.buffer_wrapper._elements[name]
except KeyError:
raise AttributeError, name

base = self.base + el.getOffset()
self.buffer_wrapper._buffer[base:base+el.getSize()] = struct.pack(
type_equivs[el.getType()], *value)



Note that I use mixedCase (Java style) for names that are exported outside the scope in which they are defined, and names_with_underscores (Unix style) for names that are private to a class or intended only for other classes that work closely with them.

(*) From the top of my head, I can think of these limitations:

1) It assumes only one buffer per vertexData.
2) It assumes at most one VertexElement for each semantic.
3) Not all semantics are supported (this is trivial to fix; check semantic_equivs).
4) Not all VertexElementTypes are supported (also trivial; you need to update type_equivs and fix the assumption, in VertexWrapper.__setattr__, that value is a tuple). Something like:


# I don't check against tuple directly
# because I want to accept anything that
# can be used as a sequence. Also, maybe
# I want to take Vectors in the future.
if type(value) in (int, float):
value = value,



5) You may want to add converters to and from ogre.Vector*. I suggest something like:


"Map ogre.VertexElementType to struct format string and output class."
type_equivs = {
ogre.VET_FLOAT1: ('f', float),
ogre.VET_FLOAT2: ('ff', ogre.Vector2),
ogre.VET_FLOAT3: ('fff', ogre.Vector3),
}

#... [in VertexWrapper]

def __getattr__(self, name):
try:
el = self.buffer_wrapper._elements[name]
except KeyError:
raise AttributeError, name
base = self.base + el.getOffset()

format, class_ = type_equivs[el.getType]

# This should work for all types, even float or int,
# since struct.unpack always returns a tuple.
return class_(*struct.unpack(
format,
self.buffer_wrapper._buffer[
base:base+el.getSize()]))

def __setattr__(self, name, value):
try:
el = self.buffer_wrapper._elements[name]
except KeyError:
raise AttributeError, name
base = self.base + el.getOffset()

# Here you'll have to translate all by hand, I'm afraid...
if type(value) in (int, float):
value = value,
elif isinstance(value, Vector2):
value = value.x, value.y
elif isinstance(value, Vector3):
value = value.x, value.y, value.z
# ...same for colors etc.

self.buffer_wrapper._buffer[base:base+el.getSize()] = struct.pack(
type_equivs[el.getType()], *value)



I just made up these modifications and they aren't tested- I didn't need them. And quite frankly, I don't know of an use case where 1) or 2) would be limitations. Maybe an assert would be in order to warn anyone that has an use for them, anyway...

HTH,

Esteban.

Fosk

16-02-2006 12:05:45

Thank you Esteban for your class.
I am trying to translate form C++ to Python the example form http://www.ogre3d.org/wiki/index.php/GeneratingAMesh
The example in question use 2 buffers so your class cannot handle it right now as I understand it.

I cannot find any documentation as to how to use HarwareBuffer.bufferLockReadWrite. Could someone tell me if I can use it to create a mesh programatically or if it is used only to modify existing meshes ?

Here is the code that I started to work on, with a marker where the program crashes :


def createColourCube(self):

msh = ogre.MeshManager.getSingleton().createManual("ColourCube", "General")
sub = msh.createSubMesh()

sqrt13 = 0.577350269

# Define the vertices (8 vertices, each consisting of 2 groups of 3 floats
nVertices = 8
vbufCount = 3*2*nVertices
vertices= [
-100.0,100.0,-100.0, #0 position
-sqrt13,sqrt13,-sqrt13, #0 normal
100.0,100.0,-100.0, #1 position
sqrt13,sqrt13,-sqrt13, #1 normal
100.0,-100.0,-100.0, #2 position
sqrt13,-sqrt13,-sqrt13, #2 normal
-100.0,-100.0,-100.0, #3 position
-sqrt13,-sqrt13,-sqrt13, #3 normal
-100.0,100.0,100.0, #4 position
-sqrt13,sqrt13,sqrt13, #4 normal
100.0,100.0,100.0, #5 position
sqrt13,sqrt13,sqrt13, #5 normal
100.0,-100.0,100.0, #6 position
sqrt13,-sqrt13,sqrt13, #6 normal
-100.0,-100.0,100.0, #7 position
-sqrt13,-sqrt13,sqrt13, #7 normal
]

rs = self.root.renderSystem

# Use render system to convert colour value since colour packing varies
colours=[]
colours.append(rs.convertColourValue(ogre.ColourValue(1.0,0.0,0.0))) #0 colour
colours.append(rs.convertColourValue(ogre.ColourValue(1.0,1.0,0.0))) #1 colour
colours.append(rs.convertColourValue(ogre.ColourValue(0.0,1.0,0.0))) #2 colour
colours.append(rs.convertColourValue(ogre.ColourValue(0.0,0.0,0.0))) #3 colour
colours.append(rs.convertColourValue(ogre.ColourValue(1.0,0.0,1.0))) #4 colour
colours.append(rs.convertColourValue(ogre.ColourValue(1.0,1.0,1.0))) #5 colour
colours.append(rs.convertColourValue(ogre.ColourValue(0.0,1.0,1.0))) #6 colour
colours.append(rs.convertColourValue(ogre.ColourValue(0.0,0.0,1.0))) #7 colour


#/ Define 12 triangles (two triangles per cube face)
#/ The values in this table refer to vertices in the above table
ibufCount = 36
faces= [
0,2,3,
0,1,2,
1,6,2,
1,5,6,
4,6,5,
4,7,6,
0,7,4,
0,3,7,
0,5,1,
0,4,5,
2,7,3,
2,6,7
]

#/ Create vertex data structure for 8 vertices shared between submeshes
msh.sharedVertexData = ogre.VertexData()
msh.sharedVertexData.vertexCount = nVertices

#/ Create declaration (memory format) of vertex data
decl = msh.sharedVertexData.vertexDeclaration
offset = 0
# 1st buffer
decl.addElement(0, offset, ogre.VET_FLOAT3, ogre.VES_POSITION)
offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)
decl.addElement(0, offset, ogre.VET_FLOAT3, ogre.VES_NORMAL)
offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)
msh.sharedVertexData.vertexDeclaration=decl #This is probably not necessary but I just
#wanted to make sure...


#/ Allocate vertex buffer of the requested number of vertices (vertexCount)
#/ and bytes per vertex (offset)


### THIS IS WHERE I AM STARTING TO LOOSE FEET...###


vbuf = ogre.HardwareBufferManager.getSingleton().createVertexBuffer(offset,
msh.sharedVertexData.vertexCount, ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY).get()

print dir(vbuf)

buff=vbuf.bufferLockReadWrite() #<------This is where ogre crashes

### ANYTHING BEYOND THIS POINT HAS NOT BEEN TESTED SO THERE ARE PROBABLY SEVERAL ERRORS ####


#/ Upload the vertex data to the card
#vbuf.writeData(0, vbuf.sizeInBytes, vertices, True)


del buff
vbuf.unlock()
del vbuf


#/ Set vertex buffer binding so buffer 0 is bound to our vertex buffer
bind = msh.sharedVertexData.vertexBufferBinding
bind.setBinding(0, vbuf)
del vbuf

# 2nd buffer
offset = 0
decl.addElement(1, offset, ogre.VET_COLOUR, ogre.VES_DIFFUSE)
offset += ogre.VertexElement.getTypeSize(ogre.VET_COLOUR)
#/ Allocate vertex buffer of the requested number of vertices (vertexCount)
#/ and bytes per vertex (offset)
vbuf = ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
offset, msh.sharedVertexData.vertexCount, ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY).get()
#/ Upload the vertex data to the card
vbuf.writeData(0, vbuf.getSizeInBytes(), colours, True)

#/ Set vertex buffer binding so buffer 1 is bound to our colour buffer
bind.setBinding(1, vbuf)

#/ Allocate index buffer of the requested number of vertices (ibufCount)
ibuf = ogre.HardwareBufferManager.getSingleton().createIndexBuffer(
ogre.HardwareIndexBuffer.IT_16BIT,
ibufCount,
ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)

#/ Upload the index data to the card
ibuf.writeData(0, ibuf.getSizeInBytes(), faces, True)

#/ Set parameters of the submesh
sub.useSharedVertices = True
sub.indexData.indexBuffer = ibuf
sub.indexData.indexCount = ibufCount
sub.indexData.indexStart = 0

#/ Set bounding information (for culling)
msh._setBounds(ogre.AxisAlignedBox(-100,-100,-100,100,100,100))
msh._setBoundingSphereRadius((3*100*100)**0.5)

#/ Notify Mesh object that it has been loaded
msh.load()


I would be much happy if someone could point me to the source of the problem. Am I doing something wrong with bufferLockReadWrite ?

Also, something that I cannot figure out : how do I translate C++'s vbuf.writeData(0, vbuf.getSizeInBytes(), colours, True) into Python ? I assume that it is something that can be done with the object returned by
bufferLockReadWrite() but since it crashes....

Thank you in advance to anyone who will have the patience to read the code.

Fosk

Fosk

22-02-2006 10:14:34

No idea anyone ?

Does someone at least know if it is feasible given the current state of PyOgre or if I am wasting my time ?

pyTwit

24-02-2006 07:12:13

This code makes it to mesh.load() before it crashes :?. I tried to reorganize the cube sample to make it more py friendly.

I'm using methods from the sphere cpp sample code in the wiki. In particular ibuf.lock and vbuf.lock which return buffer proxy objects.

The indexBufferProxy seems to work as advertised and you can treat it like an array.

The vertexBufferProxy, is the one that's trouble. I'm not sure how I'm supposed to push values into it.


def cubeMesh(size=(10,10,10), name="cube"):
meshMgr = ogre.MeshManager.getSingleton()

mesh = meshMgr.createManual(name, ogre.ResourceManager.DEFAULT_RESOURCE_GROUP_NAME)

subMesh = mesh.createSubMesh()

sqrt13 = 0.577350269 # sqrt(1/3)

#nVertices = 8
#vbufCount = 3*2*nVertices

x,y,z = size
x /= 2.0
y /= 2.0
z /= 2.0

vert_pos = [
(-x,y,-z), #0 position
(x,y,-z), #1 position
(x,-y,-z), #2 position
(-x,-y,-z), #3 position
(-x,y,z), #4 position
(x,y,z), #5 position
(x,-y,z), #6 position
(-x,-y,z) #7 position
]

vert_norm = [
(-sqrt13,sqrt13,-sqrt13), #0 normal
(sqrt13,sqrt13,-sqrt13), #1 normal
(sqrt13,-sqrt13,-sqrt13), #2 normal
(-sqrt13,-sqrt13,-sqrt13), #3 normal
(-sqrt13,sqrt13,sqrt13), #4 normal
(sqrt13,sqrt13,sqrt13), #5 normal
(sqrt13,-sqrt13,sqrt13), #6 normal
(-sqrt13,-sqrt13,sqrt13) #7 normal
]

faces = [
0,2,3,
0,1,2,
1,6,2,
1,5,6,
4,6,5,
4,7,6,
0,7,4,
0,3,7,
0,5,1,
0,4,5,
2,7,3,
2,6,7]

mesh.sharedVertexData = ogre.VertexData()
mesh.sharedVertexData.vertexCount = len(vert_pos)

decl = mesh.sharedVertexData.vertexDeclaration
offset = 0

decl.addElement(0, offset, ogre.VET_FLOAT3, ogre.VES_POSITION)
offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)

#decl.addElement(0, offset, ogre.VET_FLOAT3, ogre.VES_NORMAL)
#offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)

hBuffMgr = ogre.HardwareBufferManager.getSingleton()
vbuf = hBuffMgr.createVertexBuffer(offset, mesh.sharedVertexData.vertexCount, ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)

bind = mesh.sharedVertexData.vertexBufferBinding
bind.setBinding(0,vbuf)

pVertex = vbuf.lock(decl, ogre.HardwareBuffer.HBL_DISCARD)

subMesh.indexData.indexCount = len(faces)
subMesh.indexData.indexBuffer = hBuffMgr.createIndexBuffer(ogre.HardwareIndexBuffer.IT_16BIT, len(faces), ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)

ibuf = subMesh.indexData.indexBuffer
pIndices = ibuf.lock(decl, ogre.HardwareBuffer.HBL_DISCARD)

# Generate face list
for i in range(0, len(faces)):
pIndices[i] = faces[i]

#loop through the vert_pos array
for i in range(0, len(vert_pos)):

vx, vy, vz = vert_pos[i]
nx, ny, nz = vert_norm[i]

pVertex.setFloat(i, ogre.VES_POSITION, vx, vy, vz)
#pVertex.setFloat(counter, ogre.VES_NORMAL, nx, ny, nz)



vbuf.unlock()
ibuf.unlock()

subMesh.useSharedVertices = True

mesh._setBounds(ogre.AxisAlignedBox(-x,-y,-z,x,y,z))
mesh._setBoundingSphereRadius(z)

mesh.load()
:? :?

Fosk

24-02-2006 10:36:23

Interesting... so you did not use the HarwareBuffer.bufferLockReadWrite? At least you got much further than me.

I will try to look at it. Thank you.

dermont

24-02-2006 12:43:11

This appears to work, not too sure about the mesh.get().sharedVertexData.


def printMesh(self,mesh):
print "Number SubMeshes",mesh.numSubMeshes
for i in range(mesh.numSubMeshes):
for f in (mesh.getSubMesh(i).indices):
print f
for v in ( mesh.getSubMesh(i).getVertices(ogre.Vector3(0.0,0.0,0.0), ogre.Quaternion.IDENTITY, ogre.Vector3(1.0,1.0,1.0))):
print v


def cubeMesh(self,size=(10,10,10), name="cubeMesh"):
meshMgr = ogre.MeshManager.getSingleton()
mesh = meshMgr.createManual(name, ogre.ResourceManager.DEFAULT_RESOURCE_GROUP_NAME)
subMesh = mesh.createSubMesh()

sqrt13 = 0.577350269 # sqrt(1/3)

x,y,z = size
x /= 2.0
y /= 2.0
z /= 2.0

vert_pos = [
(-x,y,-z), #0 position
(x,y,-z), #1 position
(x,-y,-z), #2 position
(-x,-y,-z), #3 position
(-x,y,z), #4 position
(x,y,z), #5 position
(x,-y,z), #6 position
(-x,-y,z) #7 position
]

vert_norm = [
(-sqrt13,sqrt13,-sqrt13), #0 normal
(sqrt13,sqrt13,-sqrt13), #1 normal
(sqrt13,-sqrt13,-sqrt13), #2 normal
(-sqrt13,-sqrt13,-sqrt13), #3 normal
(-sqrt13,sqrt13,sqrt13), #4 normal
(sqrt13,sqrt13,sqrt13), #5 normal
(sqrt13,-sqrt13,sqrt13), #6 normal
(-sqrt13,-sqrt13,sqrt13) #7 normal
]

faces = [
0,2,3,
0,1,2,
1,6,2,
1,5,6,
4,6,5,
4,7,6,
0,7,4,
0,3,7,
0,5,1,
0,4,5,
2,7,3,
2,6,7]

POSITION_ELEMENT = 0
NORMAL_ELEMENT = 1
UV_ELEMENT = 2
# ?????????????? / Not sure about this, without the get crash
mesh.get().sharedVertexData = ogre.VertexData()
#mesh.sharedVertexData = ogre.VertexData()
mesh.sharedVertexData.vertexCount = len(vert_pos)

#work-around to prevent destruction
self.sharedVertexData = mesh.sharedVertexData

decl = mesh.sharedVertexData.vertexDeclaration
offset = 0
offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)
print 'offset ' , offset
decl.addElement(0, offset, ogre.VET_FLOAT3, ogre.VES_POSITION)
offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)

decl.addElement(0, offset, ogre.VET_FLOAT3, ogre.VES_NORMAL)
offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)

hBuffMgr = ogre.HardwareBufferManager.getSingleton()
vbuf = hBuffMgr.createVertexBuffer(offset, mesh.sharedVertexData.vertexCount, ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)


pVertex = vbuf.lock(decl, ogre.HardwareBuffer.HBL_DISCARD)


#loop through the vert_pos array
for i in range(0, len(vert_pos)):

vx, vy, vz = vert_pos[i]
nx, ny, nz = vert_norm[i]

pVertex.setFloat(i, POSITION_ELEMENT, vx, vy, vz)
pVertex.setFloat(i, NORMAL_ELEMENT, nx, ny, nz)
bind = mesh.sharedVertexData.vertexBufferBinding
bind.setBinding(0,vbuf)

subMesh.indexData.indexCount = len(faces)
subMesh.indexData.indexBuffer = hBuffMgr.createIndexBuffer(ogre.HardwareIndexBuffer.IT_16BIT, len(faces), ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)

ibuf = subMesh.indexData.indexBuffer
#pIndices = ibuf.lock(decl, ogre.HardwareBuffer.HBL_DISCARD)
subMesh.indexData.indexBuffer.writeIndexes(0, faces)

# Generate face list
#for i in range(0, len(faces)):
# pIndices[i] = faces[i]


vbuf.unlock()
#ibuf.unlock()

subMesh.useSharedVertices = True
subMesh.indexData.indexBuffer = ibuf
subMesh.indexData.indexCount = len(faces)
subMesh.indexData.indexStart = 0

mesh._setBounds(ogre.AxisAlignedBox(-x,-y,-z,x,y,z))
mesh._setBoundingSphereRadius(z)
self.indexData = subMesh.indexData
mesh.load()

self.printMesh(mesh)


def _createScene(self):
..
self.cubeMesh()
self.cubeEntity = sceneManager.createEntity("myCubeEntity", "cubeMesh")
self.nd=sceneManager.rootSceneNode.createChildSceneNode()
self.nd.attachObject(self.cubeEntity)
..

Fosk

25-02-2006 00:17:43

Thank you very much. It works.
Now, I'll try to take care of the colour and I will also try to write a simple class to generalize the process.

Bonus Question :

Ogre gives the following message :
WARNING: Mesh instance 'cubeMesh' was defined as manually loaded, but no manual loader was provided. This Resource will be lost if it has to be reloaded.
Do you think that it can safely be ignored or would adding a definition make Ogre happy ?

dermont

25-02-2006 06:01:14

You can safely ignore the warning (happens also in c++).

For the vertex colours just add something like this:

COLOUR_ELEMENT = 0
#2nd buffer , colours
offset = 0
decl.addElement(1, offset, ogre.VET_COLOUR, ogre.VES_DIFFUSE)
offset += ogre.VertexElement.getTypeSize(ogre.VET_COLOUR)
vbuf = ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
offset, mesh.sharedVertexData.vertexCount, ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)
pVertex = vbuf.lock(decl, ogre.HardwareBuffer.HBL_DISCARD)

for i in range(0, len(colours)):
pVertex.setColour(i, COLOUR_ELEMENT, colours[i])
vbuf.unlock()

#Set vertex buffer binding so buffer 1 is bound to our colour buffer
bind.setBinding(1, vbuf)


It would be nice to see your generic class in the wiki.

Fosk

25-02-2006 13:49:00

OK, I'll try to see this tomorrow, along with the wxPython class that I am also working on.

Thank you once again.

Fosk

28-02-2006 14:27:29

Here is the simple and basic class I made. It is mostly copy and paste from Dermont's work so I have no credit in it.


class ManuallyDefinedMesh:
def __init__(self,Name, Vertices_Pos, Vertices_Norm, Faces, Vertices_Colour=None, CreateImediately=True):
"An experimental class to define meshes programatically" \
"'Name' is the name by which the mesh will be referenced"\
"Vertices_Pos, Vertices_Norm are botj lists of triplets"\
"Faces is a simple list of vertex indices"\
"Vertices_Colour is an optional list of ogre.ColourValue's"\
"You can delay the mesh loading by setting 'CreateImediately' to False" \
"Even if you assign colors to your vertexes, you will have to assign a "\
"material to each entity created based on this mesh."

assert len(Vertices_Pos)==len(Vertices_Norm)
assert (len(Faces)%3)==0 #Each face is defined by 3 consecutive vertex indices

if Vertices_Colour is not None :
assert len(Vertices_Pos)==len(Vertices_Colour)

meshMgr = ogre.MeshManager.getSingleton()
self.mesh = mesh = meshMgr.createManual(Name, ogre.ResourceManager.DEFAULT_RESOURCE_GROUP_NAME)
self.subMesh = subMesh = mesh.createSubMesh()

POSITION_ELEMENT = 0
NORMAL_ELEMENT = 1
UV_ELEMENT = 2
COLOUR_ELEMENT = 0

self.Vertices_Pos = Vertices_Pos
self.Vertices_Norm = Vertices_Norm
self.Vertices_Colour = Vertices_Colour

# ?????????????? / Not sure about this, without the get crash
mesh.get().sharedVertexData = ogre.VertexData()
mesh.sharedVertexData.vertexCount = len(Vertices_Pos)

#work-around to prevent destruction
self.sharedVertexData = mesh.sharedVertexData

declaration = mesh.sharedVertexData.vertexDeclaration
offset = 0
offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)
declaration.addElement(0, offset, ogre.VET_FLOAT3, ogre.VES_POSITION)
offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)

declaration.addElement(0, offset, ogre.VET_FLOAT3, ogre.VES_NORMAL)
offset += ogre.VertexElement.getTypeSize(ogre.VET_FLOAT3)

hBuffMgr = ogre.HardwareBufferManager.getSingleton()
vbuf = hBuffMgr.createVertexBuffer(offset, mesh.sharedVertexData.vertexCount,
ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)


pVertex = vbuf.lock(declaration, ogre.HardwareBuffer.HBL_DISCARD)


#loop through the position array
for i in range(len(Vertices_Pos)):
vx, vy, vz = Vertices_Pos[i]
nx, ny, nz = Vertices_Norm[i]

pVertex.setFloat(i, POSITION_ELEMENT, vx, vy, vz)
pVertex.setFloat(i, NORMAL_ELEMENT, nx, ny, nz)
bind = mesh.sharedVertexData.vertexBufferBinding
bind.setBinding(0,vbuf) #Set vertex buffer binding so buffer 0 is bound to positional data

subMesh.indexData.indexCount = len(Faces)
subMesh.indexData.indexBuffer = hBuffMgr.createIndexBuffer(ogre.HardwareIndexBuffer.IT_16BIT,
len(Faces), ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)

ibuf = subMesh.indexData.indexBuffer
subMesh.indexData.indexBuffer.writeIndexes(0, Faces)

vbuf.unlock()


#2nd buffer , colours
if Vertices_Colour is not None :
offset = 0
declaration.addElement(1, offset, ogre.VET_COLOUR, ogre.VES_DIFFUSE)
offset += ogre.VertexElement.getTypeSize(ogre.VET_COLOUR)
vbuf = ogre.HardwareBufferManager.getSingleton().createVertexBuffer(
offset, mesh.sharedVertexData.vertexCount, ogre.HardwareBuffer.HBU_STATIC_WRITE_ONLY)
pVertex = vbuf.lock(declaration, ogre.HardwareBuffer.HBL_DISCARD)

for i in range(len(Vertices_Colour)):
pVertex.setColour(i, COLOUR_ELEMENT, Vertices_Colour[i])
vbuf.unlock()

#Set vertex buffer binding so buffer 1 is bound to our colour buffer
bind.setBinding(1, vbuf)

subMesh.useSharedVertices = True
subMesh.indexData.indexBuffer = ibuf
subMesh.indexData.indexCount = len(Faces)
subMesh.indexData.indexStart = 0
self.indexData = subMesh.indexData

if CreateImediately:
self.MakeAvailable()

def MakeAvailable(self,BoundBox=(None,None,None,None,None,None), BoundSphereRadius=None):

if None in BoundBox: #Simple guess of the bounding box
xcoord = [i[0] for i in self.Vertices_Pos]
ycoord = [i[1] for i in self.Vertices_Pos]
zcoord = [i[2] for i in self.Vertices_Pos]
BoundBox = (min(xcoord),min(ycoord),min(zcoord),max(xcoord),max(ycoord),max(zcoord))

if BoundSphereRadius is None : #Very naive guess of the bounding sphere radius
BoundSphereRadius = max([abs(BoundBox[i+3]-BoundBox[i]) for i in range(3)])

mesh=self.mesh

mesh._setBounds(ogre.AxisAlignedBox(*BoundBox))
mesh._setBoundingSphereRadius(BoundSphereRadius)

mesh.load()

def Print(self):
mesh = self.mesh
print "Number SubMeshes",mesh.numSubMeshes
for i in range(mesh.numSubMeshes):
for f in (mesh.getSubMesh(i).indices):
print f
for v in ( mesh.getSubMesh(i).getVertices(ogre.Vector3(0.0,0.0,0.0),
ogre.Quaternion.IDENTITY, ogre.Vector3(1.0,1.0,1.0))):
print v



It works for instance with something like this :


sqrt13 = 0.577350269 # sqrt(1/3)


x = 30.0
y = 30.0
z = 30.0

vert_pos = [
(-x,y,-z), #0 position
(x,y,-z), #1 position
(x,-y,-z), #2 position
(-x,-y,-z), #3 position
(-x,y,z), #4 position
(x,y,z), #5 position
(x,-y,z), #6 position
(-x,-y,z) #7 position
]

vert_norm = [
(-sqrt13,sqrt13,-sqrt13), #0 normal
(sqrt13,sqrt13,-sqrt13), #1 normal
(sqrt13,-sqrt13,-sqrt13), #2 normal
(-sqrt13,-sqrt13,-sqrt13), #3 normal
(-sqrt13,sqrt13,sqrt13), #4 normal
(sqrt13,sqrt13,sqrt13), #5 normal
(sqrt13,-sqrt13,sqrt13), #6 normal
(-sqrt13,-sqrt13,sqrt13) #7 normal
]

faces = [
0,2,3,
0,1,2,
1,6,2,
1,5,6,
4,6,5,
4,7,6,
0,7,4,
0,3,7,
0,5,1,
0,4,5,
2,7,3,
2,6,7]

rs = self.root.renderSystem
colours=[]
colours.append(rs.convertColourValue(ogre.ColourValue(1.0,0.0,0.0))) #0 colour
colours.append(rs.convertColourValue(ogre.ColourValue(1.0,1.0,0.0))) #1 colour
colours.append(rs.convertColourValue(ogre.ColourValue(0.0,1.0,0.0))) #2 colour
colours.append(rs.convertColourValue(ogre.ColourValue(0.0,0.0,0.0))) #3 colour
colours.append(rs.convertColourValue(ogre.ColourValue(1.0,0.0,1.0))) #4 colour
colours.append(rs.convertColourValue(ogre.ColourValue(1.0,1.0,1.0))) #5 colour
colours.append(rs.convertColourValue(ogre.ColourValue(0.0,1.0,1.0))) #6 colour
colours.append(rs.convertColourValue(ogre.ColourValue(0.0,0.0,1.0))) #7 colour
ManuallyDefinedMesh("cubeMesh",vert_pos,vert_norm,faces,colours)
self.cubeEntity = sceneManager.createEntity("myCubeEntity", "cubeMesh")
self.cubeEntity.setMaterialName("Test/SimpleVertexColor")
self.nd=sceneManager.rootSceneNode.createChildSceneNode()
self.nd.attachObject(self.cubeEntity)


In this case, you also need to have a material defined as the following in you media/materials/scripts folder
(I could not manage to translate the in-line material declaration from C++ to Python)


material Test/SimpleVertexColor
{
technique
{
pass
{
ambient vertexcolour
}
}
}



That's all, not an extraordinarily general class either.

Thank you once again to every one who gave me their advice (and gave me the ready to use solution)

Fosk

rollingt

12-08-2007 05:36:23

I am trying to get manual meshes to work, and I am using the code above, but it crashes when I get to this part:


# ?????????????? / Not sure about this, without the get crash
mesh.get().sharedVertexData = ogre.VertexData()
#mesh.sharedVertexData = ogre.VertexData()
mesh.sharedVertexData.vertexCount = len(vert_pos)


When I try to run this (either with or without the get()) I get an error saying that sharedVertexData is not accessable.

Maybe something has changed with the latest version of Python or PythonOgre? According to the API sharedVertexData is "unreachable".

Am I missing something?

If not, would it work if I subclassed Mesh to get access that way?

andy

12-08-2007 08:59:15

You can have a look at demo_grass in the demos/ogre directory for some pointers on using VertexData with sub meshes..

Cheers
Andy