Постобработка: наложение сферы сцены на сферу постобработки

#javascript #three.js #post-processing

#язык JavaScript #three.js #постобработка

Вопрос:

Я пробую свои силы в постобработке. Моя цель состоит в том, чтобы поместить сферу, сгенерированную в шейдере постобработки, поверх сферы в сцене. но эти две сферы не хотят быть одинаковыми. всегда есть различия. в шейдер включен параметр raymarcher (viewDir), который создает сферу с функцией raySphere. однако для этого я использую УФ-координаты в шейдере. Я думаю, что моя проблема в том, что я не знаю, как связать мировые координаты и мировую камеру с УФ-координатами. текстура tdepht вторична, она работает. Цель состоит в том, чтобы в шейдере постобработки была сфера, которая всегда находится над сферой в сцене.

 import Three from '../lib/three/build/three.js'; import * as THREE from "../lib/three/build/three.module.js"; import { OrbitControls } from '../lib/three/examples/jsm/controls/OrbitControls.js'; import { EffectComposer } from '../lib/three/examples/jsm/postprocessing/EffectComposer.js';  import { RenderPass } from '../lib/three/examples/jsm/postprocessing/RenderPass.js';  import { ShaderPass } from '../lib/three/examples/jsm/postprocessing/ShaderPass.js';    class Main {  constructor(){    this.renderer;  this.container;  this.camera;  this.scene;  this.controls;  this.composer;    this.sphere;  this.sphereGeo;    this.depthRenderTarget;  this.depthShader;      this.init();  this.animate();  }    init(){    this.renderer = new THREE.WebGLRenderer( { antialias: true } );  this.renderer.setPixelRatio( window.devicePixelRatio );   this.renderer.shadowMap.enabled = true;   this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;    this.container = document.getElementById('container');  this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);  this.container.appendChild( this.renderer.domElement );   var aspect = this.container.clientWidth / this.container.clientHeight;   this.scene = new THREE.Scene();  this.scene.background = new THREE.Color( 0x000000 );    this.camera = new THREE.PerspectiveCamera( 45, aspect, 1, 10000000 );  this.camera.position.set(0, 0, 10000);    this.controls = new OrbitControls( this.camera, this.renderer.domElement );  this.controls.enableZoom = true;  this.controls.enabled = true;  this.controls.target.set(0, 0, 0);    this.composer = new EffectComposer( this.renderer );  this.renderPass = new RenderPass( this.scene, this.camera );   this.composer.addPass( this.renderPass );   //-------------   var ambientlight = new THREE.AmbientLight( 0xF0F0F0 ); // soft white light   this.scene.add( ambientlight );    const radius = 1000 ; //var texture = new THREE.TextureLoader().load("img/earthmap.jpg"); this.sphereGeo = new THREE.SphereBufferGeometry( radius, 64, 64 );  //const material = new THREE.MeshPhysicalMaterial({ map: texture,});  const material = new THREE.MeshBasicMaterial( { color: 0x777777 } ); this.sphere = new THREE.Mesh( this.sphereGeo, material );  this.scene.add( this.sphere );    this.depthRenderTarget = new THREE.WebGLRenderTarget(this.container.clientWidth, this.container.clientHeight); this.depthRenderTarget.texture.format = THREE.RGBFormat; this.depthRenderTarget.texture.minFilter = THREE.NearestFilter; this.depthRenderTarget.texture.magFilter = THREE.NearestFilter; this.depthRenderTarget.texture.generateMipmaps = false; this.depthRenderTarget.stencilBuffer = false; this.depthRenderTarget.depthBuffer = true; this.depthRenderTarget.depthTexture = new THREE.DepthTexture(); this.depthRenderTarget.depthTexture.type = THREE.UnsignedShortType;  this.depthRenderTarget.depthTexture.format = THREE.DepthFormat;     this.depthShader = {   uniforms: {   'tDiffuse': { value: null },   'tDepth': { value: null },  'aspect': { value: aspect },  'cameraPos': {value: this.camera.position },  'cameraNear': { value: this.camera.near },  'cameraFar': { value: this.camera.far },   'cameraFov': { value: this.camera.fov },   'screenpos': {value: this.projector(this.sphere)},   'sphereradius': { value: radius },  },   vertexShader:`    varying vec2 vUv;    void main() {    vUv = uv;   gl_Position = vec4( (uv - 0.5)*2.0, 0.0, 1.0 );  }`,   fragmentShader:`  #include lt;packinggt;  #define PI 3.1415926535897932384626433832795    uniform sampler2D tDiffuse;  uniform sampler2D tDepth;  uniform float cameraNear;  uniform float cameraFar;   uniform float cameraFov;  uniform float aspect;  uniform vec3 cameraPos;  uniform vec3 screenpos;  uniform float sphereradius;  varying vec2 vUv;   float readDepth( sampler2D depthSampler, vec2 coord ) {  float fragCoordZ = texture2D( depthSampler, coord ).x;  float viewZ = perspectiveDepthToViewZ( fragCoordZ, cameraNear, cameraFar );  return viewZToOrthographicDepth( viewZ, cameraNear, cameraFar );  }   float adjust(float fov, float depth){  float vfov = fov*PI/180.;  float result = 2.*tan(vfov/2.)*depth;//length(camPos - depth);  return result;  }   vec2 raySphere(vec3 center, vec3 rayOrigin, vec3 rayDir, float radius){    vec3 offset = rayOrigin - center;   float a = dot(rayDir, rayDir);  float b = 2.0 * dot(offset, rayDir);  float c = dot(offset, offset) - radius*radius;  float d = b*b - 4.0*a*c;    if(d gt; 0.0){  float s = sqrt(d);  float dstToSphereNear = - b-s;  float dstToSphereFar = -b s;    if(dstToSphereFar lt; 0.0){  dstToSphereFar = -1.0;   }  if(dstToSphereNear lt; 0.0){  dstToSphereNear = -1.0;  }  dstToSphereNear = dstToSphereNear/(2.0*a);  dstToSphereFar = dstToSphereFar/(2.0*a);    return vec2(dstToSphereNear, dstToSphereFar - dstToSphereNear);  }    return vec2(-1.0, 0.0);  }    void main() {   float depth = readDepth(tDepth, vUv);  vec4 color = texture2D(tDiffuse, vUv);    vec3 viewOrigin = vec3(0., 0., 1.);  //I think here is the problem. I use the vUv coordinates from the flat postprocessing plane  //But i have no clue how i can connect the worldcoordinates from the scene camera with this vUv coordinates from the postprocessing shader.  vec3 viewDir = vec3((vUv.x-0.5)*aspect, (vUv.y-0.5), -1.);    float adj = adjust(cameraFov, screenpos.z);  vec3 planetcenter = vec3(screenpos.x/2.*aspect , screenpos.y/2., 0.);   vec2 hitinfo = raySphere(planetcenter, viewOrigin, viewDir, sphereradius/adj);   float dst = hitinfo.y/(2.*sphereradius/adj);  //gl_FragColor.rgb = 1.0 - vec3( depth );    gl_FragColor = color   vec4(0.,1.,0.,1.)*dst;    }`  };   //create a custom postprocessing with the shader  this.depthPass = new ShaderPass( this.depthShader );  this.depthPass.uniforms.cameraNear.value = this.camera.near;  this.depthPass.uniforms.cameraFar.value = this.camera.far;  this.depthPass.uniforms.tDepth.value = this.depthRenderTarget.depthTexture;  this.composer.addPass(this.depthPass);  this.depthPass.renderToScreen =true;    }//end init      animate(){  requestAnimationFrame( this.animate.bind(this) );   this.render();  }      render(){   this.controls.update();  this.camera.updateMatrixWorld();  this.camera.updateProjectionMatrix();    this.depthPass.uniforms.screenpos.value = this.projector(this.sphere);    this.renderer.setRenderTarget( this.depthRenderTarget );  this.renderer.render( this.scene, this.camera );    this.composer.render();    }    projector(obj){  var pos = new THREE.Vector3();   pos = pos.setFromMatrixPosition(obj.matrixWorld);   pos.project(this.camera);     var viewDir = new THREE.Vector3();  this.camera.getWorldDirection(viewDir);  var a = new THREE.Vector3();  var b = new THREE.Vector3();  a.copy(this.camera.position);  b.copy(this.sphere.position);   var distance = a.distanceTo(b);  var cosab = viewDir.dot((b.sub(a)).normalize());  var depth = distance*cosab;     pos.z = depth;  return pos;  } }  export default Main;   /*the projector function gives the coordinates xy from the sphere in screencoordinates between -1 and  1. the z value gives the depth in worldcoordinates. the depth is neccessary to calculate the size in the postprocessingshader with the adjust function.*/  // project the xy position to screencoordinates // | // __________O lt;--sphere // | / // | / // | / // depth | / // between --gt; | / lt;--distance between camera and sphere // camera | / // and | / // sphere |/ // in world [ ] lt;--camera // distance