kurse:efcomputergrafik:kw4

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Last revision Both sides next revision
kurse:efcomputergrafik:kw4 [2020/01/22 10:52]
Ivo Blöchliger [Beschleunigung bei konstantem Geschwindigkeisbetrag 1]
kurse:efcomputergrafik:kw4 [2020/01/23 09:00]
Ivo Blöchliger [Blender]
Line 12: Line 12:
   * a(t,v,g): Effektiver Beschleunigungsvektor beim Punkt $p(t)$, wenn der Geschwindigkeitsbetrag v und Inverse Erdbeschleunigung gegeben ist.   * a(t,v,g): Effektiver Beschleunigungsvektor beim Punkt $p(t)$, wenn der Geschwindigkeitsbetrag v und Inverse Erdbeschleunigung gegeben ist.
   * koordsyst(t): Orthonormales Koordinatensystem (Liste von 3 Vektoren) mit $x$ parallel zu $v$, $y$ parallel zu $a$ und $z = x \times y$.   * koordsyst(t): Orthonormales Koordinatensystem (Liste von 3 Vektoren) mit $x$ parallel zu $v$, $y$ parallel zu $a$ und $z = x \times y$.
 +<hidden Python Code>
 <code python bezier2.py> <code python bezier2.py>
 # -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
  
-# import importlib 
-# importlib.import_module("./vector") 
 from vector import Vector from vector import Vector
  
Line 30: Line 28:
             self.pts = [pts[0].copy(), 2/3*pts[0]+1/3*pts[1], 1/3*pts[0]+2/3*pts[1], pts[1].copy()]             self.pts = [pts[0].copy(), 2/3*pts[0]+1/3*pts[1], 1/3*pts[0]+2/3*pts[1], pts[1].copy()]
                  
-    # Punkt fuer Parameter t (in [0,1])        +    # Punkt für Parameter t (in [0,1])        
     def x(self,t):     def x(self,t):
         return (1.0-t)**3*self.pts[0]+\         return (1.0-t)**3*self.pts[0]+\
Line 47: Line 45:
     def vnorm(self,t):     def vnorm(self,t):
         return self.v(t).normalize()         return self.v(t).normalize()
 +    
 +    
 +    def adl(self,t, dt=0.000001): # Ableitung der normalisierten Geschwindigkeit nach der Länge
 +        dl = self.v(t).length*dt # (self.x(t+dt)-self.x(t-dt)).length
 +        return (self.vnorm(t+dt/2)-self.vnorm(t-dt/2))/dl
 +        
 +    # Effektive Beschleunigung im Punkt zum Parameter t, mit
 +    # gegebenem Geschwindigkeitsbetrag und Gravitationsvektor
 +    def aeff(self, t, v, g):
 +        return self.adl(t)*v*v-g
 +    
 +    # Orthonnormales Bahn-Koordinatensystem im Punkt zum Parameter t, mit
 +    # gegebenem Geschwindigkeitsbetrag und Gravitationsvektor.
 +    # Resultat (v,a, v cross a)
 +    def koordsyst(self, t, v, g):
 +        x = self.vnorm(t)
 +        # Effektive Beschleunigung
 +        aeff = self.aeff(t,v,g)
 +        # Projektion von aeff auf x (d.h. normalisierte Geschwindigkeit)
 +        av = x.dot(aeff)/(x.dot(x))*x
 +        # Effektive Beschleunigung in Normalebene zur Bahn.
 +        # (ist mathematisch rechtwinklig!)
 +        aa = (aeff-av).normalize()
 +        z = x.cross(aa)
 +        return (x,aa,z)
 +        
 +        
 +        
 +        
        
     # Laenge der Bezier-Kurve     # Laenge der Bezier-Kurve
Line 62: Line 89:
     # Output: Endzeitpunkt t oder -Restlaenge     # Output: Endzeitpunkt t oder -Restlaenge
     def forward(self, l, startt, dt=0.0001):     def forward(self, l, startt, dt=0.0001):
 +        lastl = l
 +        lastt = startt
         while (startt<1.0 and l>0):         while (startt<1.0 and l>0):
             dl = self.v(startt).length*dt             dl = self.v(startt).length*dt
Line 72: Line 101:
                  
         if l>0: # Es ist noch Laenge uebrig, also auf naechster Kurve         if l>0: # Es ist noch Laenge uebrig, also auf naechster Kurve
-            return -l+            return -(lastl - (self.x(1)-self.x(lastt)).length)
         return 1.0 # Sonst genau auf dem Ende der Kurve         return 1.0 # Sonst genau auf dem Ende der Kurve
          
  
     # Zeichnet den Spline     # Zeichnet den Spline
-    # Achtung: Funktioniert nur, wenn diese Datei ausgefuehrt wird...+    # Achtung: Funktioniert nur, wenn diese Datei ausgeführt wird...
     def draw(self, steps=1000):     def draw(self, steps=1000):
         move(self.pts[0][0], self.pts[0][1]);         move(self.pts[0][0], self.pts[0][1]);
Line 95: Line 124:
     while (t>=0.0):     while (t>=0.0):
         p = b.x(t)         p = b.x(t)
-        move(p.x, p.y) +        a = b.adl(t) 
-        circle(5) +        pa = p+a*10000 
-        t = b.forward(615.274/12.0,t)+        # move(p.x, p.y) 
 +        circle(5
 +        line(p.x,p.y, pa.x, pa.y
 +        t = b.forward(10,t)
         print(t)         print(t)
-    t = 0.0 +
-    while (t<=1.0): +
-        p = b.x(t) +
-        move(p.x, p.y) +
-        circle(10) +
-        t += 1/12.0+
 </code> </code>
 +</hidden>
  
 ====== Bahn-Koordinatensystem ====== ====== Bahn-Koordinatensystem ======
Line 114: Line 141:
 \begin{align*} \begin{align*}
 x(t) & =  r \cdot \textrm{e}^{\textrm{i}t \cdot \frac{1}{r}}\\ x(t) & =  r \cdot \textrm{e}^{\textrm{i}t \cdot \frac{1}{r}}\\
-v(t) & =  x'(t) = \textrm{e}^{\textrm{i}t \cdot \frac{1}{r}}\\ +v(t) & =  x'(t) = \textrm{i}\textrm{e}^{\textrm{i}t \cdot \frac{1}{r}}\\ 
-a(t) & =  v'(t) = \frac{1}{r} \cdot \textrm{e}^{\textrm{i}t \cdot \frac{1}{r}}\\+a(t) & =  v'(t) = -\frac{1}{r} \cdot \textrm{e}^{\textrm{i}t \cdot \frac{1}{r}}\\
 \end{align*} \end{align*}
  
-Beträgt jetzt die Geschwindigkeit $\lambda$ anstatt 1, ändern sich die Gleichungen wie  folgt:+Beträgt jetzt der Betrag der Geschwindigkeit $\lambda$ anstatt 1, ändern sich die Gleichungen wie  folgt:
  
 \begin{align*} \begin{align*}
 x(t) & =  r \cdot \textrm{e}^{\textrm{i} \lambda t \cdot \frac{1}{r}}\\ x(t) & =  r \cdot \textrm{e}^{\textrm{i} \lambda t \cdot \frac{1}{r}}\\
-v(t) & =  x'(t) =  \lambda  \cdot \textrm{e}^{\textrm{i} \lambda t \cdot \frac{1}{r}}\\ +v(t) & =  x'(t) =  \textrm{i}\lambda  \cdot \textrm{e}^{\textrm{i} \lambda t \cdot \frac{1}{r}}\\ 
-a(t) & =  v'(t) =  \lambda^2 \cdot \frac{1}{r} \cdot \textrm{e}^{\textrm{i} \lambda t \cdot \frac{1}{r}}\\+a(t) & =  v'(t) =  -\lambda^2 \cdot \frac{1}{r} \cdot \textrm{e}^{\textrm{i} \lambda t \cdot \frac{1}{r}}\\
 \end{align*} \end{align*}
  
-D.h., wenn die Geschwindigkeit von $1$ auf $\lambda$ erhöht wird, wird die Beschleunigung mit $\lambda^2$ multipliziert.+D.h., wenn der Betrag der Geschwindigkeit von $1$ auf $\lambda$ erhöht wird, wird der Betrag der Beschleunigung mit $\lambda^2$ multipliziert.
  
 ===== Beschleunigung bei konstantem Geschwindigkeisbetrag 1 ===== ===== Beschleunigung bei konstantem Geschwindigkeisbetrag 1 =====
Line 133: Line 160:
  
 Sei $t(\ell)$ die Umkehrfunktion, d.h. der $t$-Parameter für eine bestimmte Länge. Die Ableitung ist dann Sei $t(\ell)$ die Umkehrfunktion, d.h. der $t$-Parameter für eine bestimmte Länge. Die Ableitung ist dann
 +(nach der Formel $(f^{-1})' = \frac{1}{f'(f^{-1})}$ mit $f^{-1}=t$ und $f=\ell$):
 $$ $$
-\frac{\textrm{d}t(\ell)}{\textrm{d}\ell} = \frac{1}{\ell'(t(\ell))} = \frac{1}{|p'(t(\ell)|}.+\frac{\textrm{d}t(\ell)}{\textrm{d}\ell} = \frac{1}{\ell'(t(\ell))} = \frac{1}{|p'(t(\ell))|}.
 $$ $$
 (D.h. der Parameter $t$ ändert sich mit der Länge indirekt proportional zur $t$-Geschwindigkeit). (D.h. der Parameter $t$ ändert sich mit der Länge indirekt proportional zur $t$-Geschwindigkeit).
Line 145: Line 173:
 p'(t(\ell)) \cdot \frac{1}{|p'(t(\ell))|} p'(t(\ell)) \cdot \frac{1}{|p'(t(\ell))|}
 \] \]
-d.h. man erhält den auf den Betrag 1 normalisierten Geschwindgkeitsvektor (was ja genau der Sinn der $p_{\ell}$ Parametrierung ist.+d.h. man erhält den auf den Betrag 1 normalisierten Geschwindgkeitsvektor (was ja genau der Sinn der $p_{\ell}$ Parametrierung ist).
  
-Die zweite Ableitung von $p_{\ell}$ nach $\ell$ ergibt die Beschleunigung $a_n(\ell)$, die rechtwinklich auf $v_n$ steht (sonst würde sich der Betrag von $v_n$ ändern).+Die zweite Ableitung von $p_{\ell}$ nach $\ell$ ergibt die Beschleunigung $a_n(\ell)$, die rechtwinklig auf $v_n$ steht (sonst würde sich der Betrag von $v_n$ ändern).
  
 Diese zweite Ableitung berechnen wir nummerisch durch Ableiten der ersten: Diese zweite Ableitung berechnen wir nummerisch durch Ableiten der ersten:
Line 154: Line 182:
 \] \]
  
 +===== Effektive Beschleunigung und Komponente in Bahnnormalebene =====
 +Sei $v_{\text{eff}}(t) \in \mathbb{R}$ der Betrag der effektiven Bahngeschwindigkeit im Punkt zum entsprechenden $t$-Parameter.
 +Die effektive Beschleunigung ist also 
 +\[
 +a_{\text{eff}}(t) =  (v_{\text{eff}}(t))^2 \cdot a_n(t) -g
 +\]
 +wobei $g$ die Gravitationsbeschleunigung ist.
  
 +Diese Beschleunigung zerlegen wir in zwei Komponenten, eine tangential zur Bahn $a_t$, eine rechtwinklig dazu $a_r$. Die Komponente $a_t$ sorgt für die Beschleunigung des Zugs, die Komponente $a_r$ ist für die Bahnneigung relevant. Diese sollte nämlich rechtwinklig zu $a_r$ sein.
 +
 +$a_t$ ist die Projektion von $a_{\text{eff}}$ auf $v_n$. Es gilt (mit $|v_n|=1$):
 +\[
 +a_t = (\vec a_{\text{eff}} \cdot \vec v_n) \cdot \vec v_n \qquad \text{Skalarprodukt in der Klammer!}
 +\]
 +Und damit 
 +\[
 +a_r = a_{\text{eff}}-a_t
 +\]
 +
 +Damit bilden wir ein Koordinatensystem $K(t)$ mit Ursprung $p(t)$ und Einheitsvektoren
 +\[
 +e_1 = v_n(t), \qquad e_2 = \frac{a_r(t)}{|a_r(t)|}, \qquad e_3 = v_n(t) \times a_r(t) \cdot \frac{1}{|a_r(t)|}
 +\]
 +
 +===== Bau der Bahn =====
 +In geeigneter Schrittgrösse der Kurve entlang gehen, an jedem Punkt mit $K(t)$ Schienen-Punkte definieren.
 +Eventuell Stützen definieren.
 +
 +Blender Code analog zur Generierung der glatten Kurve.
 +===== Simulation der Bewegung =====
 +Zustand: $t$ (Ort auf der Bahn), $v_{\text{eff}}$ (aktueller Betrag der Geschwindigkeit)
 +
 +Schritt: Zeit um 1/framerate vorrücken, der Bahn folgen (z.B. um die Strecke, die mit $v_{\text{eff}}$ in dieser Zeit zurückgelegt würde, oder genauere schrittweise Simulation). Aus der Höhendifferenz und eventuell Reibung die neue Geschwindigkeit berechnen.
 +
 +Kamera entsprechend positionieren und Keyframe setzen:
 +
 +<code python>
 +cam = bpy.data.objects['Camera']
 +frame = 0
 +cam.animation_data_clear()
 +cam.matrix_world = ( (y.x,y.y,y.z,1), (-an.x, -an.y, -an.z, 1),  (-vv.x,-vv.y,-vv.z,1),  (pp.x, pp.y, pp.z, 0))
 +cam.keyframe_insert(data_path="rotation_euler", frame=frame)
 +cam.keyframe_insert(data_path="location", frame=frame)
 +frame+=1
 +</code>
 +Siehe auch https://blender.stackexchange.com/questions/108938/how-to-interpret-the-camera-world-matrix
 +
 +D.h. die erste Koordinatenrichtung ist rechts, die zweite oben und die dritte ist entgegen der Blickrichtung.
 +
 +===== Blender =====
 +Bezier Klasse laden in Blender:
 +<code python bahn.py>
 +# Nimmt die Bezierkurven aus myspline und erzeugt 
 +# die Bahn und die Kamera-Animation
 +
 +# Import in Blender 2.8 (see https://devtalk.blender.org/t/2-80-using-multiple-internal-scripts-breaking-change/6980 )
 +Bezier = bpy.data.texts["bezier.py"].as_module().Bezier
 +
 +obj = bpy.data.objects['mySpline']
 +
 +# Kurvenpunkte auslesen
 +mypoints=[]
 +if obj.type == 'CURVE':
 +    for subcurve in obj.data.splines:
 +        curvetype = subcurve.type
 +        if curvetype == 'BEZIER':
 +            for bezpoint in subcurve.bezier_points:
 +                mypoints.append(bezpoint.handle_left)
 +                mypoints.append(bezpoint.co)
 +                mypoints.append(bezpoint.handle_right)
 +                
 +
 +# Sammlung von Bezierkurven erzeugen
 +mySplines = []
 +numpoints = len(mypoints)
 +totalLength = 0
 +for i in range(numpoints//3):
 +    mySplines.append(Bezier((mypoints[i*3+1],
 +        mypoints[i*3+2], 
 +        mypoints[(i*3+3)%numpoints], 
 +        mypoints[(i*3+4)%numpoints])))
 +    totalLength+=mySplines[-1].length()
 +
 +
 +# Bahn erzeugen
 +try:
 +    bpy.ops.collection.objects_remove(bpy.data.collections['Rails'])
 +except:
 +    pass
 +    
 +railsCol = bpy.data.collections.new('Rails')
 +linksCol = bpy.data.collections.new('RailLinks')
 +railsCol.children.link(linksCol)
 +bpy.context.scene.collection.children.link(railsCol)
 +               
 +abstand = 0.2  # Bahnpunkte
 +ldone = 0  # Erledigte Bahnstrecke
 +i=0  # Aktuelle Bezierkurve
 +t = 0 # Aktuelle t-Parameter
 +g = Vector(0,0,-9.81) # Gravitationbeschleunigung
 +hmax = 40  # Hoehe fuer v=0
 +# Bahnpunkte: Ctrl-Links, Knoten, Ctrl-Rechts
 +railspts=[[],[],[]]  # Bahnpunkte, Schiene L, Schiene R, Träger 
 +while(ldone<totalLength):
 +    dl = abstand;
 +    tnext = -1
 +    while(tnext<0):
 +        tnext = mySplines[i].forward(dl, t)
 +        if (tnext<0) : # We get the negative remaining length
 +            i=(i+1)%numSplines
 +            t = 0
 +            dl=abs(tnext)
 +        else:
 +            ldone+=dl
 +    t = tnext
 +    # Potentielle Energie mgh
 +    ekin = (hmax-mySplines[i].x(t).z)*abs(g.z)
 +    # Ek = 1/2 * m * v^2
 +    v = (2*ekin)**0.5
 +    # Koordinatensystem (vorne, oben, rechts)
 +    k = mySplines[i].koordsyst(t,v,g)
 +    # Bahnpunkte berechnen
 +    #
 +    #
 +    #
 +    
 +
 +
 +# Blender-Kurven aus den Bahnpunkten erzeugen
 +for j in range(3):
 +    curvedata = bpy.data.curves.new(name="rail"+str(j), type='CURVE')
 +    curvedata.dimensions = '3D'
 +    objectdata = bpy.data.objects.new("rail"+str(j), curvedata)    
 +    objectdata.location = (0,0,0)
 +    objectdata.data.bevel_depth = 0.01
 +
 +    railsCol.objects.link(objectdata)
 + 
 +    polyline = curvedata.splines.new('BEZIER'   
 +    polyline.bezier_points.add(len(railspts[j])-1)    
 + 
 +    for idx, (h1, knot, h2) in enumerate(railspts[j]):
 +        point = polyline.bezier_points[idx]
 +        point.co = knot
 +        point.handle_left = h1
 +        point.handle_right = h2
 +        point.handle_left_type = 'ALIGNED'
 +        point.handle_right_type = 'ALIGNED'
 +
 +</code>
  • kurse/efcomputergrafik/kw4.txt
  • Last modified: 2020/02/12 21:06
  • by Ivo Blöchliger