Deutsch
PHP, HTML & JavaScript- Forum

3D Grafik - WebGL mit three.js

 
- Seite 1 -



HofK
Auf einen heißen Tipp von IF hin, habe ich mir mal
three.js  [...]  angeschaut. Da  [...]  (ganz unten) die ersten Resultate.
 
31.01.2016  
 



 
- Seite 12 -



p.specht

Was ist von der freeware Game-Engine "Unity" zu halten?
Aufmerksam gemacht wurde ich von einem Youtube-Video des jungen US-"AI-Professors" Siraj Raval (Indisch-stämmig?):
Link:  [...] 

Bevorzugte Schnittstellensprachen sind C# und JavaScript (!!)
Download-Link:  [...] 
 
XProfan 11
Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'...
14.01.2018  
 




HofK
p.specht (14.01.2018)
Was ist von der freeware Game-Engine "Unity" zu halten?



Damit habe ich mich nicht näher beschäftigt, da mein Interesse mehr genau in die andere Richtung - zur Basis - geht. Also shader, webGL ... .

Unity ist nur in der Grundversion free und nicht nur für den Web-Browser.
Ein Ranking findet man da:  [...] 

Am Ende dort weitere Alternativen.

Babylon  [...]   [...]  und Whitestorm  [...]  sind web und open source.

Whitestorm basiert auf three.js

Da gibt es persönliche Meinungen  [...] 
 
14.01.2018  
 




p.specht

Sehr interessant, danke!
 
XProfan 11
Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'...
15.01.2018  
 




HofK
Zur Modifizierung der exportierten Geometrie (siehe Ende Dezember 2017) habe ich noch etwas mit der Benutzerinteraktion herumgespielt. Eine ähnliche Variante wie vor begrenzt die Bewegung der Ausschnitte auf den grün umrandeten Bereich.

#divMain {
width: 1000px;
height: 600px;
border: 4px solid rgba(0,255,0,0.5); padding: 12px;
}
<div id="divMain" ondragover="drag_over(event)" ondrop="drop(event)">

<!DOCTYPE html>
<!--
derived from
https://stackoverflow.com/questions/6230834/html5-drag-and-drop-anywhere-on-the-screen
-->
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<style>

body {

    margin: 0;

}

#divMain {

    width: 1000px;
    height: 600px;
    border: 4px  solid rgba(0,255,0,0.5); padding: 12px;

}

#pane1 {

    position: absolute;
    left: 0;
    top: 50px;
    width: 200px;
    background: rgba(255,255,255,0.95);
    border: 2px  solid rgba(0,0,0,0.5);
    border-radius: 12px; padding: 8px;

}

#pane2 {

    position: absolute;
    left: 0;
    top: 200px;
    width: 200px;
    background: rgba(255,255,0,0.95);
    border: 2px  solid rgba(0,0,0,0.5);
    border-radius: 12px; padding: 8px;

}

</style>
<script>

function drag_start(event) {

    var style = window.getComputedStyle(event.target, null);
    var str = (parseInt(style.getPropertyValue("left")) - event.clientX) +',' + (parseInt(style.getPropertyValue("top")) - event.clientY)+ ',' + event.target.id;
    event.dataTransfer.setData("Text",str);

}

function drop(event) {

    var offset = event.dataTransfer.getData("Text").split(',');
    var dm = document.getElementById(offset[2]);
    dm.style.left = (event.clientX + parseInt(offset[0],10)) +'px';
    dm.style.top = (event.clientY + parseInt(offset[1],10)) +'px';
    event.preventDefault();
    return false;

}

function drag_over(event) {	event.preventDefault();	return false; }
</script>
</head>
<body  >
<span id="pane1" draggable="true" ondragstart="drag_start(event)">
<span id="title1"> ziehen!<br /> </span>
Inhalt 1  <br />
<img src="natur.png" width="126" height="95">
</span>
<span id="pane2" draggable="true" ondragstart="drag_start(event)">
Inhalt 2
<img src="further_examples.png" width="79" height="48">
</span>
<div id="divMain" ondragover="drag_over(event)" ondrop="drop(event)">
Hauptinhalt ... <br /><hr/>
</div>
</body>
</html>

Dann habe ich noch eine sehr komfortable Sache gefunden. Sie ist aber für meine Zwecke nicht geeignet. Ich bekomme Probleme mit der Kamerasteuerung per Maus. (OrbitControls.js)

Die Sache stammt von zz85  [...]  (Link leider nicht mehr verfügbar!) dessen Beispiele  [...]  ( @author zz85 ) mich auch mit zur Entwicklung von THREEf gebracht haben.

Der Code ist fast unverändert von  [...]  übernommen. Einfach mal kopieren und ausprobieren.
Mein Bild <img src="further_examples.png" width="789" height="481"> durch ein eigenes ersetzen.
<!DOCTYPE html>
<html lang="de" >
<head>
<meta charset="UTF-8">
<title>Resize, Drag, Snap</title>
<style>

body {

    overflow: hidden;

}

#pane {

    overflow: hidden;
    position: absolute;
    width: 45%;
    height: 45%;
    top: 20%;
    left: 20%;
    margin: 0;
    padding: 0;
    z-index: 99;
    border: 2px solid purple;
    background: #fefefe;

}

#title {

    font-family: monospace;
    background: purple;
    color: white;
    font-size: 24px;
    height: 30px;
    text-align: center;

}

#ghostpane {

    background: #ffff33;
    opacity: 0.2;
    width: 45%;
    height: 45%;
    top: 20%;
    left: 20%;
    position: absolute;
    margin: 0;
    padding: 0;
    z-index: 98;
    -webkit-transition: all 0.25s ease-in-out;
    -moz-transition: all 0.25s ease-in-out;
    -ms-transition: all 0.25s ease-in-out;
    -o-transition: all 0.25s ease-in-out;
    transition: all 0.25s ease-in-out;

}

</style>
</head>
<body>
site content
<div id="pane">
<div id="title">Resize, Drag or Snap Me!</div>
pane content
<img src="further_examples.png" width="789" height="481">
</div>
<div id="ghostpane"> </div>
</body>
<script>
/*
* @author  https://github.com/zz85
* https://codepen.io/zz85/pen/gbOoVP
*/
"use strict";
// Minimum resizable area
var minWidth = 100;
var minHeight = 80;
// Thresholds
var FULLSCREEN_MARGINS = -10;
var MARGINS = 4;
// End of what's configurable.
var clicked = null;
var onRightEdge, onBottomEdge, onLeftEdge, onTopEdge;
var rightScreenEdge, bottomScreenEdge;
var preSnapped;
var b, event, x, y;
var redraw = false;
var pane = document.getElementById('pane');
var ghostpane = document.getElementById('ghostpane');

function setBounds(element, x, y, w, h) {

    element.style.left = x +'px';
    element.style.top = y +'px';
    element.style.width = w +'px';
    element.style.height = h +'px';

}

function hintHide() {

    setBounds(ghostpane, b.left, b.top, b.width, b.height);
    ghostpane.style.opacity = 0;

}

// Mouse events
pane.addEventListener('mousedown', onMouseDown);
document.addEventListener('mousemove', onMove);
document.addEventListener('mouseup', onUp);
// Touch events
pane.addEventListener('touchstart', onTouchDown);
document.addEventListener('touchmove', onTouchMove);
document.addEventListener('touchend', onTouchEnd);
animate();
// ................................................

function onTouchDown(event) {

    onDown(event.touches[0]);
    event.preventDefault();

}

function onTouchMove(event) {

    onMove(event.touches[0]);

}

function onTouchEnd(event) {

    if (event.touches.length ==0) onUp(event.changedTouches[0]);

    }

    function onMouseDown(event) {

        onDown(event);
        event.preventDefault();

    }

    function onDown(event) {

        calc(event);
        var isResizing = onRightEdge || onBottomEdge || onTopEdge || onLeftEdge;

        clicked = {

            x: x,
            y: y,
            cx: event.clientX,
            cy: event.clientY,
            w: b.width,
            h: b.height,
            isResizing: isResizing,
            isMoving: !isResizing && canMove(),
            onTopEdge: onTopEdge,
            onLeftEdge: onLeftEdge,
            onRightEdge: onRightEdge,
            onBottomEdge: onBottomEdge

        };

    }

    function canMove() {

        return x > 0 && x < b.width && y > 0 && y < b.height
        && y < 30;

    }

    function calc(event) {

        b = pane.getBoundingClientRect();
        x = event.clientX - b.left;
        y = event.clientY - b.top;
        onTopEdge = y < MARGINS;
        onLeftEdge = x < MARGINS;
        onRightEdge = x >= b.width - MARGINS;
        onBottomEdge = y >= b.height - MARGINS;
        rightScreenEdge = window.innerWidth - MARGINS;
        bottomScreenEdge = window.innerHeight - MARGINS;

    }

    function onMove(paneEvent) {

        calc(paneEvent);
        event = paneEvent;
        redraw = true;

    }

    function onUp(event) {

        calc(event);

        if (clicked && clicked.isMoving) {

            // Snap

            var snapped = {

                width: b.width,
                height: b.height

            };

            if (b.top < FULLSCREEN_MARGINS || b.left < FULLSCREEN_MARGINS || b.right > window.innerWidth - FULLSCREEN_MARGINS || b.bottom > window.innerHeight - FULLSCREEN_MARGINS) {

                // hintFull();
                setBounds(pane, 0, 0, window.innerWidth, window.innerHeight);
                preSnapped = snapped;

            } else if (b.top < MARGINS) {

                // hintTop();
                setBounds(pane, 0, 0, window.innerWidth, window.innerHeight / 2);
                preSnapped = snapped;

            } else if (b.left < MARGINS) {

                // hintLeft();
                setBounds(pane, 0, 0, window.innerWidth / 2, window.innerHeight);
                preSnapped = snapped;

            } else if (b.right > rightScreenEdge) {

                // hintRight();
                setBounds(pane, window.innerWidth / 2, 0, window.innerWidth / 2, window.innerHeight);
                preSnapped = snapped;

            } else if (b.bottom > bottomScreenEdge) {

                // hintBottom();
                setBounds(pane, 0, window.innerHeight / 2, window.innerWidth, window.innerWidth / 2);
                preSnapped = snapped;

            } else {

                preSnapped = null;

            }

            hintHide();

        }

        clicked = null;

    }

    function animateGhostPane() {

        if (!redraw) return;

            redraw = false;

            if (clicked && clicked.isResizing) {

                if (clicked.onRightEdge) pane.style.width = Math.max(x, minWidth) +'px';

                    if (clicked.onBottomEdge) pane.style.height = Math.max(y, minHeight) +'px';

                        if (clicked.onLeftEdge) {

                            var currentWidth = Math.max(clicked.cx - event.clientX  + clicked.w, minWidth);

                            if (currentWidth > minWidth) {

                                pane.style.width = currentWidth +'px';
                                pane.style.left = event.clientX +'px';

                            }

                        }

                        if (clicked.onTopEdge) {

                            var currentHeight = Math.max(clicked.cy - event.clientY  + clicked.h, minHeight);

                            if (currentHeight > minHeight) {

                                pane.style.height = currentHeight +'px';
                                pane.style.top = event.clientY +'px';

                            }

                        }

                        hintHide();
                        return;

                    }

                    if (clicked && clicked.isMoving) {

                        if (b.top < FULLSCREEN_MARGINS || b.left < FULLSCREEN_MARGINS || b.right > window.innerWidth - FULLSCREEN_MARGINS || b.bottom > window.innerHeight - FULLSCREEN_MARGINS) {

                            // hintFull();
                            setBounds(ghostpane, 0, 0, window.innerWidth, window.innerHeight);
                            ghostpane.style.opacity = 0.2;

                        } else if (b.top < MARGINS) {

                            // hintTop();
                            setBounds(ghostpane, 0, 0, window.innerWidth, window.innerHeight / 2);
                            ghostpane.style.opacity = 0.2;

                        } else if (b.left < MARGINS) {

                            // hintLeft();
                            setBounds(ghostpane, 0, 0, window.innerWidth / 2, window.innerHeight);
                            ghostpane.style.opacity = 0.2;

                        } else if (b.right > rightScreenEdge) {

                            // hintRight();
                            setBounds(ghostpane, window.innerWidth / 2, 0, window.innerWidth / 2, window.innerHeight);
                            ghostpane.style.opacity = 0.2;

                        } else if (b.bottom > bottomScreenEdge) {

                            // hintBottom();
                            setBounds(ghostpane, 0, window.innerHeight / 2, window.innerWidth, window.innerWidth / 2);
                            ghostpane.style.opacity = 0.2;

                        } else {

                            hintHide();

                        }

                        if (preSnapped) {

                            setBounds(pane,
                            event.clientX - preSnapped.width / 2,
                            event.clientY - Math.min(clicked.y, preSnapped.height),
                            preSnapped.width,
                            preSnapped.height
                            );
                            return;

                        }

                        // moving
                        pane.style.top = (event.clientY - clicked.y) +'px';
                        pane.style.left = (event.clientX - clicked.x) +'px';
                        return;

                    }

                    // This code executes when mouse moves without clicking
                    // style cursor

                    if (onRightEdge && onBottomEdge || onLeftEdge && onTopEdge) {

                        pane.style.cursor ='nwse-resize';

                    } else if (onRightEdge && onTopEdge || onBottomEdge && onLeftEdge) {

                        pane.style.cursor ='nesw-resize';

                    } else if (onRightEdge || onLeftEdge) {

                        pane.style.cursor ='ew-resize';

                    } else if (onBottomEdge || onTopEdge) {

                        pane.style.cursor ='ns-resize';

                    } else if (canMove()) {

                        pane.style.cursor ='move';

                    } else {

                        pane.style.cursor ='default';

                    }

                }

                function animate() {

                    requestAnimationFrame(animate);
                    animateGhostPane();

                }

                </script>
                </html>

Letztendlich habe ich mich für eine spartanische Variante entschieden. Das noch nicht ganz fertige Layout:

 
15.01.2018  
 




p.specht

Gibt es irgendwo auch den berühmten Hasen und den Teekessel in three?
 
XProfan 11
Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'...
16.01.2018  
 




HofK
p.specht (16.01.2018)
Gibt es irgendwo auch den berühmten Hasen und den Teekessel in three?


In three.js selbst kann man direkt nur sehr elementare Körper erzeugen. Also Zylinder, Kugel usw.
Deshalb habe ich ja die Addons THREEf und THREEp geschrieben, um etwas kompliziertere Geometrie einfach durch Angabe von Parametern und Funktionen zu generieren.

Ansonsten werden komplexe Objekte zur Nutzung in three mit Modellierungs-Software wie Blender (Maskottchen Affe Suzanne) oder z.B.  [...]  und weiteren erstellt. Das ist dann kreatives Design und nicht mein Ding.

Man findet Modelle mit der Suche bei  [...] 
Da es sehr viele 3D Formate gibt, muss man schauen, was man da kann und möchte. Etwas weiter oben hier habe ich ein Objekt im .obj Format in three eingebunden. Dazu gibt es in three die Lader.  [...]  dort Loader in das Suchfeld eingeben.

Hasen und Teekessel: [...]  [...] 
 
16.01.2018  
 




p.specht

Danke!
 
XProfan 11
Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'...
16.01.2018  
 




HofK
Bei der Modifizierung der Geometrie gab es ein echtes Problem.

Ich benutze Raycaster und habe irgendwann bemerkt, dass ich die Rückseiten der Flächen nicht greifen konnte.
.
Also habe ich das Beispiel  [...]  genommen und stark vereinfacht/abgewandelt und statt non-indexed eine indexed BufferGeometry und Multimaterial (array) mit THREE.DoubleSide, THREE.FrontSide, THREE.BackSide. Da  [...]  kann man es probieren. Es wird immer nur die Vorderseite erkannt. Selbst bei BackSide, wo das Material dann nicht angezeigt wird - aber die weiße Umrandung.

Also bei discourse.threejs.org eine Frage formuliert  [...] 

Ich hatte keine Chance! Multimaterial wird nicht unterstützt. Aber Mugen87 hat ein workaround  [...]  parat.

Man ersetzt in three.js
function Mesh( geometry, material ) { … }
Mesh.prototype = Object.assign( … )


und schon funktioniert es. [...] 

Trotz der Hilfsgitter ist die Orientierung im Raum schwierig. Man bewegt sich ja mit dem Handhabungspunkt (Würfel) in der sich stets selbst ausrichtenden grauen orthogonalen Hilfsebene.

Die Punkte (1, 2 oder 3) des Dreiecks bewegen sich parallel. Da muss mir noch etwas einfallen.
 
19.01.2018  
 




HofK
Nach einigen Experimenten
-------


habe ich mich entschieden, zusätzlich zur Kamera - orthogonalen Ausrichtung der Hilfsebene die Koordinatenebenen fixierbar zu gestalten. Dazu drückt man die Tasten x, y, oder z.

Die jeweilige Koordinate bleibt dann unverändert, die Hilfsebene ist orthogonal zur Achse.

Trotzdem ist die Handhabung etwas "hakelig" und man muss ein wenig üben. Problem ist, dass die Maus einerseits die Kamera steuern muss (OrbitControls.js) und andererseits auch die Geometriekoordinaten verschieben soll.

Dabei ist die praktische Umschaltung problematisch. Mag sein, dass meine Lösung nicht optimal ist. Vielleicht erhalte ich ja noch einen Expertentipp?

Wer lieber mit der Eingabe arbeitet, hat da keine Probleme. Die Genauigkeit lässt sich einstellen.



Für den Export habe ich mit Hilfe von prisoner849 (Paul West)  [...]  eine recht elegante Variante. Sie ist auch bei modifyCreateGeo.html  [...]  nachgetragen. (siehe weiter oben)

Da  [...]  bzw.  [...]  ausprobieren.

Bitte beachten, dass der Export ohne Nachfrage in der Zwischenablage landet. Steht auch da!

Export the changed code.
The code is displayed here
and is also copied to the clipboard.
 
23.01.2018  
 




HofK
THREEp ist fertiggestellt

Vor ziemlich genau einem Jahr begonnen! Da konnte ich nicht absehen, wohin das führt und wie lange es dauert.

Nun sind beide Addons fertig!
Siehe meine Seite  [...]  und GitHub  [...] 
Auch Beispiele und dazu eine Formenbibliothek zu THREEp.  [...]  Noch erweiterbar.

Von der Beseitigung der Nähte bei Geometry habe ich abgesehen. Der Aufwand ist unverhältnismäßig hoch. Besonders, da Geometry keine dauernde Zukunft hat. 

Da noch das Tool für THREEf - siehe Bild im vorherigen Beitrag  [...] 
Bei discourse  [...] 

Da kann es mit anderen Sachen weitergehen
 
27.01.2018  
 




p.specht

Gratuliere! Ausprobieren leider eine Zeitfrage, aber geplant!
Gruss

P.S.: GitHub-Link hat einen Punkt am Ende zuviel.
 
Computer: Gerät, daß es in Mikrosekunden erlaubt, 50.000 Fehler zu machen, zB 'daß' statt 'das'...
28.01.2018  
 




HofK
p.specht (28.01.2018)
P.S.: GitHub-Link hat einen Punkt am Ende zuviel.


Danke für den Hinweis, korrigiert!
 
28.01.2018  
 




Antworten


Thementitel, max. 100 Zeichen.
 

Systemprofile:

Kein Systemprofil angelegt. [anlegen]

XProfan:

 Beitrag  Schrift  Smilies  ▼ 

Bitte anmelden um einen Beitrag zu verfassen.
 

Themenoptionen

332.805 Betrachtungen

Unbenanntvor 0 min.
HofK vor 23 Tagen
Rschnett24.08.2024
Michael W.28.03.2024
Thomas Zielinski17.02.2024
Mehr...

Themeninformationen



Admins  |  AGB  |  Anwendungen  |  Autoren  |  Chat  |  Datenschutz  |  Download  |  Eingangshalle  |  Hilfe  |  Händlerportal  |  Impressum  |  Mart  |  Schnittstellen  |  SDK  |  Services  |  Spiele  |  Suche  |  Support

Ein Projekt aller XProfaner, die es gibt!


Mein XProfan
Private Nachrichten
Eigenes Ablageforum
Themen-Merkliste
Eigene Beiträge
Eigene Themen
Zwischenablage
Abmelden
 Deutsch English Français Español Italia
Übersetzungen

Datenschutz


Wir verwenden Cookies nur als Session-Cookies wegen der technischen Notwendigkeit und bei uns gibt es keine Cookies von Drittanbietern.

Wenn du hier auf unsere Webseite klickst oder navigierst, stimmst du unserer Erfassung von Informationen in unseren Cookies auf XProfan.Net zu.

Weitere Informationen zu unseren Cookies und dazu, wie du die Kontrolle darüber behältst, findest du in unserer nachfolgenden Datenschutzerklärung.


einverstandenDatenschutzerklärung
Ich möchte keinen Cookie