• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

[GELÖST] Math.pow

m1au

New member
Hallo :)

Ich befürchte, ich habe dieses mal ein Problem, das sich gar nicht lösen lässt.

Es geht nämlich um https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Math/pow und zwar um den speziellen Fall: Math.pow(-7, 0.5);

Solche Werte habe ich leider bei meinem Superellipsoid. http://regular-polygon.com/plugins/superellipsoid/images/superellipsoid-3-xlarge.png

Lässt sich dieses Problem irgendwie auf mathematischen Weg umgehen?

Hier der Code, wo ich mit pow arbeite:
Code:
  let s1 = 1.1; // superellipse-Parameter
  let s2 = 1.1;
  
  let rX = 1;
  let rY = 1;
  let rZ = 1;
  let count = 4; // Anzahl der Vertices in width und depth

  let f1 = 180 / count; // Schrittweite in Grad für kappa1
  let f2 = 360 / count; // Schrittweite in Grad für kappa2
  
  for(let i = 0; i < count; ++i) { // für kappa2
     let kappa2 = (-count / 2 + i) * f2; // von -PI bis +PI
     
     for(let j = 0; j < count; ++j) { // für kappa1
        let kappa1 = (-count / 2 + j) * f1;
        
        let cosKappa1S1 = Math.pow(Math.cos(deg2Rad(kappa1)), s1);
                
        let x = rX * cosKappa1S1 * Math.pow(Math.cos(deg2Rad(kappa2)), s2);
        let y = rY * cosKappa1S1 * Math.pow(Math.sin(deg2Rad(kappa2)), s2);
        let z = rZ * Math.pow(Math.sin(deg2Rad(kappa1)), s1);
     }
  }

Für alle, die sich das Problem anschauen wollen (nur als Background-Info gedacht):

HTML:
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <script src="https://cdn.rawgit.com/toji/gl-matrix/v1.3.7/gl-matrix-min.js" type="text/javascript"></script>
  <script src="webgl.js" type="text/javascript"></script>
</head>
<body onload="webGLStart();">
  <canvas id="webgl-canvas" width="500" height="500">
    Your browser is not supported
  </canvas>

  <script id="shader-fs" type="x-shader/x-fragment">
    precision mediump float;
    
    varying float d;

    void main(void) {
      float c = 1.0 - d / 8.0;
      gl_FragColor = vec4(c, c, c, 1.0);
    }
  </script>

  <script id="shader-vs" type="x-shader/x-vertex">
    attribute vec3 aVertexPosition;

    uniform mat4 uMVMatrix;
    uniform mat4 uPMatrix;
    
    varying float d;

    void main(void) {
      gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
      
      d = length(gl_Position);
      gl_PointSize = 8.0 - d;    
    }
  </script>
</body>
</html>
Code:
"use strict";

var gl;
var shaderProgram;
var cylinderVertexPositionBuffer;
var pMatrix = mat4.create();
var mvMatrix = mat4.create();

function webGLStart() {
  var canvas = document.getElementById( "webgl-canvas" );
  initGL( canvas );
  initShaders();
  initBuffers();

  gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
  gl.enable( gl.DEPTH_TEST );

  drawScene();
}

function initGL( canvas ) {
  try {
    gl = canvas.getContext( "experimental-webgl" );
    gl.viewportWidth = canvas.width;
    gl.viewportHeight = canvas.height;
  } catch( e ) {
  }
  if ( !gl ) {
    alert("Could not initialise WebGL");
  }
}

function initShaders() {
  var fragmentShader = getShader( gl, "shader-fs" );
  var vertexShader = getShader( gl, "shader-vs" );

  shaderProgram = gl.createProgram();
  gl.attachShader( shaderProgram, vertexShader );
  gl.attachShader( shaderProgram, fragmentShader );
  gl.linkProgram( shaderProgram );

  if ( !gl.getProgramParameter( shaderProgram, gl.LINK_STATUS )) {
    alert( "Could not initialise shaders" );
  }

  gl.useProgram( shaderProgram );

  shaderProgram.vertexPositionAttribute = gl.getAttribLocation( shaderProgram, "aVertexPosition" );
  gl.enableVertexAttribArray( shaderProgram.vertexPositionAttribute );

  shaderProgram.pMatrixUniform = gl.getUniformLocation( shaderProgram, "uPMatrix" );
  shaderProgram.mvMatrixUniform = gl.getUniformLocation( shaderProgram, "uMVMatrix" );
}

function getShader( gl, id ) {
  var shaderScript = document.getElementById( id );
  if( !shaderScript ) {
    return null;
  }

  var str = "";
  var k = shaderScript.firstChild;
  while( k ) {
    if( k.nodeType == 3 ) {
    str += k.textContent;
  }
    k = k.nextSibling;
  }

  var shader;
  if( shaderScript.type == "x-shader/x-fragment" ) {
    shader = gl.createShader( gl.FRAGMENT_SHADER );
  } else if ( shaderScript.type == "x-shader/x-vertex" ) {
    shader = gl.createShader( gl.VERTEX_SHADER );
  } else {
    return null;
  }

  gl.shaderSource( shader, str );
  gl.compileShader( shader );

  if( !gl.getShaderParameter( shader, gl.COMPILE_STATUS )) {
    alert( gl.getShaderInfoLog( shader ));
    return null;
  }

  return shader;
}
var vertices = [];
function initBuffers() {  
  // Punkte:
  
  // Hiermit gibt es Probleme mit pow:
  let s1 = 1.1; // superellipse-Parameter
  let s2 = 1.1;
  
  // Hiermit funktioniert alles:
  //let s1 = 1; // superellipse-Parameter
  //let s2 = 1;
  
  let rX = 1;
  let rY = 1;
  let rZ = 1;
  let count = 4; // Anzahl der Vertices in width und depth

  let f1 = 180 / count; // Schrittweite in Grad für kappa1
  let f2 = 360 / count; // Schrittweite in Grad für kappa2
  for(let i = 0; i < count; ++i) { // für kappa2
     let kappa2 = (-count / 2 + i) * f2; // von -PI bis +PI
     for(let j = 0; j < count; ++j) { // für kappa1
        let kappa1 = (-count / 2 + j) * f1;
        
        let cosKappa1S1 = Math.pow(Math.cos(deg2Rad(kappa1)), s1);
        
        // nur zum Testen eingefügt:
        alert(Math.cos(deg2Rad(kappa2)));
        alert(s2);
        alert(Math.pow(Math.cos(deg2Rad(kappa2)), s2));
        alert(Math.pow(-1, 1.1));
        
        let x = rX * cosKappa1S1 * Math.pow(Math.cos(deg2Rad(kappa2)), s2);
        let y = rY * cosKappa1S1 * Math.pow(Math.sin(deg2Rad(kappa2)), s2);
        let z = rZ * Math.pow(Math.sin(deg2Rad(kappa1)), s1);
        
        vertices = vertices.concat([x, y, z]);
        
        // nur zum Testen eingefügt:
        break;
     }
     
     // nur zum Testen eingefügt:
     break;
  }
  console.log(vertices);
  
  cylinderVertexPositionBuffer = gl.createBuffer();
  gl.bindBuffer( gl.ARRAY_BUFFER, cylinderVertexPositionBuffer );
  gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW );
  
  cylinderVertexPositionBuffer.itemSize = 3;
  cylinderVertexPositionBuffer.numItems = vertices.length / cylinderVertexPositionBuffer.itemSize;
}

function drawScene() {
  gl.viewport( 0, 0, gl.viewportWidth, gl.viewportHeight );
  gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );

  mat4.perspective( 45, gl.viewportWidth / gl.viewportHeight, 0.1, 20.0, pMatrix );

  mat4.identity( mvMatrix );
  mat4.translate( mvMatrix, [ 0.0, 0.0, -3.0 ] );
  //mat4.rotateY( mvMatrix, deg2Rad( -20 ) );
  mat4.rotateX( mvMatrix, deg2Rad( 25 ) );
  
  gl.bindBuffer( gl.ARRAY_BUFFER, cylinderVertexPositionBuffer );
  gl.vertexAttribPointer( shaderProgram.vertexPositionAttribute, cylinderVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0 );
  setMatrixUniforms();
  gl.drawArrays(gl.POINTS, 0, vertices.length / 3);
  //gl.drawArrays( gl.LINES, 0, cylinderVertexPositionBuffer.numItems );
}

function setMatrixUniforms() {
  gl.uniformMatrix4fv( shaderProgram.pMatrixUniform, false, pMatrix );
  gl.uniformMatrix4fv( shaderProgram.mvMatrixUniform, false, mvMatrix );
}

function deg2Rad( x ) {
  return x * Math.PI / 180;
}
Problem im initBuffers.

Meine Notlösung wäre es, die Punkte nicht alle zu berechnen, sondern sie zu duplizieren und zu manipulieren. 1/8 des Objekts lässt sich nämlich berechnen. Die restlichen 7/8 könnte ich dann mit einem Hilfsprogramm ermitteln.

Aber es würde mir viel besser gefallen, wenn ich diesen Workaround vermeiden, und statt dessen auf eine mathematische Lösung zurückgreifen könnte.

- - - Aktualisiert - - -

Problem gelöst :) Einfach 2 Hilfsfunktionen definiert.

Code:
function powSin(rad, exp) {
           let v = Math.sin(rad);
           return (v < 0) ? -Math.pow(-v, exp) : Math.pow(v, exp);
        }
        function powCos(rad, exp) {
           let v = Math.cos(rad);
           return (v < 0) ? -Math.pow(-v, exp) : Math.pow(v, exp);
        }
 
Zuletzt bearbeitet von einem Moderator:
Äh... die Wurzel von einer negativen Zahl ist in den reellen Zahlen (und das sind Numbers in JS) einfach nicht definiert. Dazu müsstest du in die Komplexen gehen. Aber deine "Notlösung" ist die einzig wahre Lösung, denn die Gleichung der Superellipsen sind mit den Beträgen der Koordinaten definiert. Wenn du somit die Gleichung nach x, y, und y auflöst, hast du das Ergebnis für |x|, |y| und |z|, was jeweils zwei Lösungen besitzt: Plus und Minus. Wenn du die drei mal zwei (bzw. besser zwei hoch 3) Lösungen kombinierst, bekommst du alle acht Raumoktanten (https://de.wikipedia.org/wiki/Oktant_(Geometrie) ). Im Grunde genommen ist deine Lösung mit den Hilfsfunktionen auch nichts anderes. Nur dass du die sehr rechenintensiven Funktionen (sin, cos und pow) achtmal so häufig aufrufst.
 
Nur dass du die sehr rechenintensiven Funktionen (sin, cos und pow) achtmal so häufig aufrufst.
Da hast du wirklich Recht. War vielleicht doch keine so gute Idee, unbedingt eine mathematische Lösung dafür finden zu wollen. Aber zumindest kenne ich jetzt 2 Lösungswege :)
 
Zurück
Oben