2016-10-30 2 views
1

Wie können Sie eine Ray-Nachverfolgung zu einer Punktwolke mit einem benutzerdefinierten Vertexshader in three.js durchführen?Raytracing zu einer Punktwolke mit einem benutzerdefinierten Vertexshader in Three.js

Dies ist mein Vertex-Shader

void main() { 
    vUvP = vec2(position.x/(width*2.0), position.y/(height*2.0)+0.5); 
    colorP = vec2(position.x/(width*2.0)+0.5 , position.y/(height*2.0) ); 
    vec4 pos = vec4(0.0,0.0,0.0,0.0); 
    depthVariance = 0.0; 
    if ((vUvP.x<0.0)|| (vUvP.x>0.5) || (vUvP.y<0.5) || (vUvP.y>0.0)) { 
    vec2 smp = decodeDepth(vec2(position.x, position.y)); 
    float depth = smp.x; 
    depthVariance = smp.y; 
    float z = -depth; 
    pos = vec4((position.x/width - 0.5) * z * (1000.0/focallength) * -1.0,(position.y/height - 0.5) * z * (1000.0/focallength),(- z + zOffset/1000.0) * 2.0,1.0); 
    vec2 maskP = vec2(position.x/(width*2.0), position.y/(height*2.0) ); 
    vec4 maskColor = texture2D(map, maskP); 
    maskVal = (maskColor.r + maskColor.g + maskColor.b)/3.0 ; 
    } 
    gl_PointSize = pointSize; 
    gl_Position = projectionMatrix * modelViewMatrix * pos; 
} 

In der Punkte-Klasse wird Raytracing wie folgt umgesetzt:

function testPoint(point, index) { 
    var rayPointDistanceSq = ray.distanceSqToPoint(point); 
    if (rayPointDistanceSq < localThresholdSq) { 
     var intersectPoint = ray.closestPointToPoint(point); 
     intersectPoint.applyMatrix4(matrixWorld); 
     var distance = raycaster.ray.origin.distanceTo(intersectPoint); 
     if (distance < raycaster.near || distance > raycaster.far) return; 
     intersects.push({ 
      distance: distance, 
      distanceToRay: Math.sqrt(rayPointDistanceSq), 
      point: intersectPoint.clone(), 
      index: index, 
      face: null, 
      object: object 
     }); 
    } 
} 

var vertices = geometry.vertices; 
for (var i = 0, l = vertices.length; i < l; i ++) { 
     testPoint(vertices[ i ], i); 
} 

Da ich einen Vertex-Shader verwenden, die geometry.vertices passen Sie nicht zu den Scheitelpunkten auf dem Bildschirm, die verhindert, dass die Ray-Trace funktioniert.

Können wir die Punkte vom Vertex-Shader zurückholen?

Antwort

2

Ich habe mich nicht mit dem beschäftigt, was Ihr Vertex-Shader tatsächlich tut, und ich nehme an, es gibt gute Gründe dafür, dies im Shader zu tun. Daher ist es wahrscheinlich nicht machbar, die Berechnungen in Javascript zu wiederholen. Gießen.

Ein Ansatz könnte sein, eine Art von Schätzung für die Punkte zu haben, diese für eine Vorauswahl zu verwenden und eine kompliziertere Berechnung für die Punkte durchzuführen, die dem Strahl am nächsten sind.

Wenn das nicht funktioniert, wäre es am besten, eine Lookup-Map Ihrer Szene zu rendern, wobei Farbwerte die ID eines Punktes sind, der an den Koordinaten gerendert wird (dies wird auch als GPU bezeichnet) -Picking, Beispiele here, here und sogar einige Bibliothek here obwohl das nicht wirklich das tut, was Sie brauchen werden).

Um dies zu tun, müssen Sie Ihre Szene zweimal rendern: Erstellen Sie eine Lookup-Map im ersten Durchgang und rendern Sie sie regelmäßig im zweiten Durchgang. Die Lookup-Map speichert für jedes Pixel, welches Partikel dort gerendert wurde.

Um diese Informationen zu erhalten, müssen Sie ein THREE.RenderTarget (dies könnte für eine bessere Leistung auf die Hälfte der Breite/Höhe herunterskaliert werden) und ein anderes Material. Der Vertex-Shader bleibt so wie er ist, aber der Fragment-Shader gibt nur einen einzigen, eindeutigen Farbwert für jedes Partikel aus (oder irgendetwas, das Sie verwenden können, um sie zu identifizieren). Dann macht die Szene (oder besser: nur die Teile, die Raycast-Ziele werden soll) in die renderTarget:

var size = renderer.getSize(); 
var renderTarget = new THREE.WebGLRenderTarget(size.width/2, size.height/2); 
renderer.render(pickingScene, camera, renderTarget); 

Nach dem Rendern können Sie den Inhalt dieser Lookup-Textur erhalten mit dem renderer.readRenderTargetPixels -Methode:

var pixelData = new Uint8Array(width * height * 4); 
renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, pixelData); 

(das Layout von Pixeldata ist hier die gleiche wie für eine reguläre Leinwand imageData.data)

Sobald Sie, dass nur die Raycaster eine einzige Koordinate Lookup müssen, lesen und den Farbwert als Objekt zu interpretieren -id an t tu etwas damit.

+0

Danke !! Ich füge nur für jeden hinzu, der dies in der Zukunft versucht. Im Vertex-Shader können Sie eine Variation festlegen, die Sie dann im Fragment-Shader verwenden können, in dem Sie die Farben der Scheitelpunkte festlegen würden – cjds