3D Engine für Python

Bisher habe ich unter Python mit pygame+Box2d gearbeitet und war damit im Großen und Ganzen zufrieden. Mit relativ wenig Code konnte man eine Szene erzeugen, die sogar über eine Physik verfügte. Leider häuften sich in letzter Zeit die Mängel. Zum einen reagiert Box2D bei mehreren Ground-Objekten etwas hackelig in der Steuerung und zum zweiten ist sowohl pygame als auch Box2D nur in 2d erhältlich.

Nur zur Probe habe ich mal über den Tellerrand geblickt und panda3d entdeckt. Installiert wird das über „sudo pip install panda3d“ und ein Demoprogramm gibt es auf https://www.panda3d.org/manual/index.php/Loading_and_Animating_the_Panda_Model Wenn man das Demoprogramm startet sieht man eine Bären in 3d laufen und die Kamera bewegt sich um ihn herum. Für die wenigen Lines of Code eine beachtliche Leistung. Und ruckelfrei ist das ganze auch. Ob ich wirklich zu panda3d wechseln werde ist noch unklar, aber ein wenig rumspielen kann nicht schaden.

UPDATE
Leider hat sich herausgestellt dass Panda3D nicht praxixtauglich ist. Die Game-Engine ist überwiegend auf das Anzeigen von schicken Texturen und Lichtverhältnissen spezialisiert. Dazu gibt es die meisten Tutorials. Wenn man so simple Dinge tun will wie einfach eine Linie zeichnen oder zwei Boxen mit einem Joint zu koppeln muss man schon das Forum fragen. Und dort entdeckt man dann dass in Panda3D gleich mehrere Physik-Engines (Panda-original, ODE, Bullet) integriert sind die sich alle unterschiedlich konfigurieren lassen. Kurz gesagt, Panda3D ist einerseits an Funktionen überladen auf der andere Seite gibt es weniger als bei Box2D. Es hat schon seine Gründe warum sich Box2D so großer Beliebtheit erfreut obwohl die Library viele Schwächen besitzt.

UPDATE2
Was ist die Alternative zu Panda3D? Diese lautet, dass man sich selber eine Physik-Engine hernimmt wie pybullet oder pyode und ontop dann eine Graphic-Engine drauflegt. Leider gibt es das Problem, dass sich pyode unter Ubuntu nicht installieren lässt. Es gibt eine Compiler-Fehlermeldung, und zu pybullet gibt es keine gute Doku. Aber was ist gibt, ist eine Ode-Doku unter Panda3d https://www.panda3d.org/manual/index.php/Collision_Detection_with_ODE#Example Das abgedruckte Beispielprogramm hat zwar nichts mehr mit Panda3D zu tun ist aber dafür erfrischend simpel aufgebaut. Und das beste ist, es läuft reibungslos durch, man sieht nach dem Starten eine Fläche auf die würfel hinabpurzeln. Ist also ODE unter panda3D eine Art von Geheimtipp wie man leicht und ähnlich wie in Box2D komplexe Animationen erstellen kann? Derzeit kann ich das nicht sagen, dafür ist es noch zu früh.

Der eigentliche Grund dennoch bei Box2D zu bleiben hat weniger etwas mit panda3d zu tun als vielmehr mit dem Umstand dass Spieleprogrammierung in 2D um sehr vieles leichter ist. Man denke nur mal an einen Pathplanning Algorithmus wie PRM. Wollte man den in 3D realisieren muss man schon ziemlich fit sein. Kurz gesagt, fürs erste bietet 2D genug Herausforderung, auch wenn natürlich 3D sehr reizvoll ist.

3D Grafik mit Python

Schaut man einmal um, was laut Google Scholar eine gute Programmiersprache zur Spieleentwicklung ist, so wird dort von der überwältigenden Mehrheit der Autoren die Meinung vertreten, dass C++ das Nonplusultra ist. Die Anzahl der Lehrbücher ist groß, es gibt sogar welche die auf Deutsch verfasst sind und in den letzten 2 Jahren geschrieben wurden. Leider offenbart sich beim Blick in derartige Fachliteratur das blanke Grauen. Der Neueinsteiger wird mit dem vollen Sprachumfang von C++ traktiert. Polymorphe Vererbung, Pointer und copy-Konstruktoren werden bereits im Einleitungskapitel diskutiert auf die dann im weiteren Verlauf aufgebaut wird. Weiterhin heißt es, dass gute Spiele wenigstens aus 10000 Lines of Code in C++ bestehen und alles darunter ist die Amateurliga.

Ganz unrecht haben die Autoren nicht, und was in den Büchern erläutern ist durchweg korrekt. Aber, die Einstiegshürde ist viel zu hoch, auf diese Weise ein Spiel zu entwickeln ist für Leute außerhalb der Spielebranche nicht möglich. Die nach meiner Ansicht nach bessere Wahl ist die Programmiersprache Python. Es gibt dort zwar nicht soviele Bücher die speziell für Spieleentwicklung unter Linux geschrieben wurden, aber immerhin wird pygame noch relativ ausführlich erläutert. Solange man 2D Plattformer Games entwickeln will kommt man mit Linux+pygame+eine Anleitung von Google Scholar schon ziemlich weit. Die Programmierung geht deutlich leichter von der Hand als mit C++ und das Ergebnis kann sich durchaus sehen lassen. Schwieriger wird es jedoch, wenn man 3D Spiele entwickeln möchte. Hier gibt es leider keine Anleitung.

Ganz unmöglich ist das jedoch nicht, es ist nur weniger gut dokumentiert. Als Basis sollte man den Begriff OpenGL kennen, es handelt sich dabei um einen Grafikstandard der in Linux GUIs wie GTK+ und Qt eingesetzt wird um 3D Inhalte anzuzeigen und der Zugriff hat auf die Grafikkarte. Um in OpenGL zu programmieren würde man normalerweise eine Game/Grafik-Engine einsetzen wie z.B. Unity3d. Die ist zwar auch für Linux verfügbar ist jedoch kostenpflichtig. Und OpenSource Alternativen wie Ogre3d, oder Panda3D sind leider keine gute Wahl. Sie sind grottenschlecht dokumentiert und selbst einfachste Dinge wie das Zeichnen eines 3d Cube auf den Bildschirms erfordert bereits sehr tiefe Kenntnisse. Es ist nicht komplett unmöglich, aber es ist nicht geeignet für Einsteiger.

Einen halbwegs leichten Zugang zu der Thematik „3D Grafik mit Python und Linux“ bietet der Blogpost https://pythonprogramming.net/opengl-rotating-cube-example-pyopengl-tutorial/ Dort werden zwei Dinge verwendet: pygame und pyopengl. Beides muss man in Ubuntu zunächst über den Paketmanager installieren, dann aber kann man das Beispielprogramm starten und erhält die folgende Grafik:

opengl

Der Vorteil bei diesem Ansatz ist, dass es sehr weit unten anfängt. Es werden Punkte im Raum definiert, zwischen diesen dann Edges (Linien) gezogen werden und zum Schluss wird in der pygame Gameloop das Objekt rotiert. Bemerkenswert ist vor allem, was in der Grafik alles nicht enthalten ist: es gibt keine animierten Charaktere, keine Physik-Engine, keine Mouse-Listener, keine Texturen und keine Lichtquellen. Stattdessen wird einem minimalistischen Ansatz bei dem wirklich nur ein 3d Cube angezeigt wird und sonst gar nichts. Gerade für Einsteiger ist das ein guter Zugang, weil klar ist wie man das System erweitern muss, wenn man ein Spiel daraus machen möchte.

Von der Performance gibt es keine Probleme. Obwohl Python als Programmiersprache genutzt wird, ist dank OpenGL eine hohe Framerate möglich. Auch die CPU Auslastung geht bei der 3D Darstellung nicht auf 100% hoch, sondern ist kaum wahrnehmbar.

Sourcecode three.js

<!doctype html>
<html> Splines, http://www.gingerleprechaun.com/javascript/threejs-tween-along-motion-path<br>
http://stackoverflow.com/questions/18578249/three-js-splinecurve3-without-round-edges-or-linecurve3-replacement
<head>
	<meta charset="utf-8">
  <title>Spline following</title>
</head>

<body>

<script src="three.min.js"></script> 
<script> // Our Javascript will go here. 

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);
var renderer = new THREE.WebGLRenderer();
var geometry = new THREE.CubeGeometry(.5,.5,.5);
var material = new THREE.MeshBasicMaterial({
  color: 0x01ff00f, 
  wireframe: true, 
  wireframeLinewidth: 2
});
var materialCube = new THREE.MeshBasicMaterial({
  color: 0x00aa30, 
  wireframe: false, 
  wireframeLinewidth: 2
});



var cube = new THREE.Mesh(geometry, materialCube);
var cube2 = new THREE.Mesh(geometry, materialCube);

// Spline Definition
// ----------------------------------------
 
// spline = new THREE.ClosedSplineCurve3([
spline = new THREE.SplineCurve3([
   new THREE.Vector3(0, 10, 0),
   new THREE.Vector3(2, 9, 0),
   new THREE.Vector3(5, 11, 0),
   new THREE.Vector3(6, 10, 0),
   new THREE.Vector3(8, 9.5, 0),
]);
spline2 = new THREE.SplineCurve3([
   new THREE.Vector3(0, 5, 0),
   new THREE.Vector3(3, 3, 0),
   new THREE.Vector3(4, 6, 0),
   new THREE.Vector3(7, 2, 0),
   new THREE.Vector3(8, 5, 0),
]);

var numPoints = 100;
var splinePoints = spline.getPoints(numPoints);
var spline2Points = spline2.getPoints(numPoints);
var geometry3 = new THREE.Geometry(); 
var geometry4 = new THREE.Geometry();
 
for(var i = 0; i < splinePoints.length; i++){
    geometry3.vertices.push(splinePoints[i]);  
    geometry4.vertices.push(spline2Points[i]);  
}

var line2 = new THREE.Line(geometry3, material);
var line3 = new THREE.Line(geometry4, material);



// ----------------------------------------
var t = 0.0;

function render() {
  requestAnimationFrame(render);
//  cube.rotation.x += 0.01;
//  cube.rotation.y += 0.01;

  t = t + 0.001;
  cube.position = spline.getPointAt(t)
  cube2.position = spline2.getPointAt(t)
//  camera.position.z += 0.1;
  renderer.render(scene, camera);
};

// ----------------------------------------
// Animation
//var t = 0;
//function update(){
//    t = t + 0.05;
//    particle.position = spline.getPointAt(t)
//}



renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
scene.add(cube);
scene.add(cube2);
scene.add(line2);
scene.add(line3);

// camera.position.set(0, 0, 100);
camera.position.set(0, 0, 30);
camera.lookAt(new THREE.Vector3(10, 5, 0));

render();

</script>

</body>
</html>