2017-10-01 4 views
0

Problem: Bestimmte gerade Linien (die blaue z-Achse in diesem Beispiel) werden nicht auf gerade Linien projiziert, wenn das Bild einer gedrehten Kubikamera mit dem Würfel projiziert wird Shader auf einem Nicht-Cube-Bildschirm und Betrachten des Bildschirms von der idealen Position mit einer Perspektivenkamera. Warum? Was mache ich falsch?Perspektivische Projektion von GLSL textureCube auf beliebige Geometrie vom selben Ursprung erhält keine geraden Linien

Mein Verständnis der Würfelkamera besteht darin, dass sie aus 6 perspektivischen Kameras mit fov = 90 und aspect = 1 besteht, die jeweils auf eine positive oder negative Hauptachse ausgerichtet sind, um den gesamten Raum (zwischen nah und fern) abzudecken. Es kann frei positioniert und rotiert werden (und sogar skaliert und verzerrt sein, nehme ich an), und dann werden die erzeugten Bilder dies erklären. Die Bilder sind eine CubeTexture, die mehr oder weniger nur aus 6 quadratischen Texturen besteht. Die "Würfelgröße" in den Parametern ist die Auflösung der quadratischen Texturen.

Mein Verständnis des Würfelshaders und von textureCube ist, dass der gelieferte Vektor nur als eine Richtung behandelt wird, und dass die Farbe durch Schneiden eines Strahls in dieser Richtung (von der Mitte) mit der Oberfläche des Würfels erhalten wird.

Beim Positionieren einer Perspektivenkamera verstehe ich, dass die Position der Kamera die Augenposition ist, nicht die Position der Projektionsebene oder etwas anderes.

In diesen Sinne würde ich erwarte dass: Wenn die Projektionsfläche Geometrie deckt den gesamten Blick der Betrachter (Perspektive) Kamera und die Beobachter-Kamera im gleichen Ursprung positioniert ist, wie der Würfel-Shader verwendet, Selbst wenn die Cube-Kamera gedreht wird, ist das Bild von der Überwachungskamera für alle möglichen Projektionsflächengeometrien das gleiche ( ) (abgesehen von einigen kleineren Sampling/Aliasing-Artefakten). Nur wenn der Ursprung der Beobachterkamera oder des Cube-Shaders verschoben wurde, würde ich Unterschiede aufgrund der Geometrie erwarten.

Stattdessen erhalten I diese mit dem Bild eines gedrehten CubeCamera zu einem Zylinder projiziert: The blue z axis is broken (presumably on the edge of the cylinder) bemerken, wie die blauen z-Achse „gebrochen“ ist (vermutlich auf dem Rand des Zylinders).

dies mit dem gleichen Bild eines Würfels projiziert: enter image description here

dies mit dem Bild eines nicht gedrehten CubeCamera zu einem Zylinder projiziert: enter image description here

und dies mit dem gleichen Bild eines Würfels projiziert: enter image description here

Der Ausschnitt ist für jedes Bild unterschiedlich (manuell), aber die Kameraeinstellungen und die Drehung der Beobachter sind identisch. Es sieht so aus, als ob die nicht rotierte CubeCamera das gleiche Bild für den Würfel und den Zylinder liefert, während die gedrehte CubeCamera sehr unterschiedliche Bilder liefert.

Ausreichend Code, um das Problem zu demonstrieren, ist unten beigefügt. Ich habe auch eine laufende Version here hochgeladen.

<html> 
<head> 
    <title>Projectors problem test</title> 
    <script src="three.js-master/build/three.js"></script> 
</head> 

<body> 
<script> 
"use strict"; 

//Globals 
var renderer, simulatedScene, simulationCubeCamera, idealSimulatorScene, camera; 

(function main() { 
    //Renderer setup 
    document.body.style = "overflow: hidden;"; 
    var container = document.createElement("div"); 
    container.style = "position: absolute; top: 0; left: 0;" 
    document.body.appendChild(container); 
    renderer = new THREE.WebGLRenderer({antialias: true}); 
    renderer.setSize(window.innerWidth, window.innerHeight); 
    container.appendChild(renderer.domElement); 

    //Setup of simulated scene: 
    simulatedScene = new THREE.Scene(); 

    simulatedScene.add(new THREE.AxisHelper(500)); 

    //Cubecamera setup 
    simulationCubeCamera = new THREE.CubeCamera(5, 1000, 2048); 
    simulationCubeCamera.position.set(0,50,0); 
    //Comment out CubeCamera rotation to see the difference: 
    simulationCubeCamera.rotation.z = -0.25*Math.PI; 
    simulatedScene.add(simulationCubeCamera); 
    simulationCubeCamera.update(renderer, simulatedScene); 

    //Define (arbitrary mesh-based) projector screen geometry: 
    //Box geometry seems to work. Cylinder geometry works(?) for non-rotated  CubeCamera: 
    var screenGeometry = /*new THREE.BoxBufferGeometry(5,5,5, 1,1,1);*/new  THREE.CylinderBufferGeometry(5,5,5, 12288, 1); 

    //Make "ideal" projection on the screen geometry using cube shader: 
    idealSimulatorScene = new THREE.Scene(); 
    let cubeShader = THREE.ShaderLib.cube; 
    cubeShader.uniforms.tCube.value =  simulationCubeCamera.renderTarget.texture; 
    let idealScreenMat = new THREE.ShaderMaterial({ 
     uniforms: cubeShader.uniforms, 
     vertexShader: cubeShader.vertexShader, 
     fragmentShader: cubeShader.fragmentShader, 
     //depthWrite: false, 
     side: THREE.BackSide}); 

    var idealProjectorScreen = new THREE.Mesh(
     screenGeometry, 
     idealScreenMat 
    ); 
    idealSimulatorScene.add(idealProjectorScreen); 

    //Observer camera setup: 
    camera = new THREE.PerspectiveCamera(90, window.innerWidth/ window.innerHeight, 0.01, 15); 
    camera.lookAt(new THREE.Vector3(5,-50,35)); 

    renderer.render(idealSimulatorScene, camera); 
})(); 

</script> 
</body> 
</html> 

Antwort

0

Ich löste es. Es stellt sich heraus, dass der Cube Shader auf die Darstellung eines Himmelswürfels spezialisiert ist. Ironischerweise war die Lösung eine Vereinfachung.Ich hatte gerade statt transformDirection die Weltposition zu verwenden:

Nun mein Vertex-Shader sieht wie folgt aus (nach einigen Makros, Funktionsaufrufe und Zwischenvariablen ersetzt):

varying vec3 vWorldPosition; 

void main() { 
    //With transformDirection: 
    //vWorldPosition = normalize((modelMatrix * vec4(position, 0.0)).xyz); 
    //With just the world position (interpreted by the textureCube as a direction) 
    vWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz; 

    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 
} 

Beachten Sie, dass die Normalisierung auch entfernt . textureCube behandelt nicht normalisierte Vektoren, und tatsächlich würden die interpolierten Vektoren im Allgemeinen sowieso nicht normalisiert werden.

Ich kann den alten Fragment-Shader wiederverwenden.

Verwandte Themen