how to get Sun Rays from the middle of the object in threejs

徘徊边缘 提交于 2019-12-21 06:15:42

问题


I have an object where random open particles and others are solid. How do i place a fake sun inside of the object and get Rays through the open particles using threejs. When the object rotate either X,Y Rays should spreed through the open particles ( POST PROCESSING ) ?

SAMPLE VIDEO

My Object three.Js code is bellow

var camera, scene, renderer;
var geometry, material, mesh;

   init();
   animate();

function init() {

  camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 10, 10000);
  camera.position.z = 200;

  scene = new THREE.Scene();

  hemiLight = new THREE.HemisphereLight( 0x0000ff, 0x00ff00, 0.6 );
  scene.add(hemiLight);

  var geometry = new THREE.DodecahedronGeometry(80, 0);

  var material = new THREE.MeshPhongMaterial({
    color: 0xffffff,
    specular: 0xffffff,
    shininess: 1,
    shading: THREE.FlatShading,
    polygonOffset: true,
    polygonOffsetFactor: 1,
    wireframe:true

  });

  mesh = new THREE.Mesh(geometry, material);

  scene.add(mesh);

  var geo = new THREE.EdgesGeometry( mesh.geometry ); // or WireframeGeometry
  var mat = new THREE.LineBasicMaterial( { color: 0xffffff, linewidth: 2 } );
  var wireframe = new THREE.LineSegments( geo, mat );
  mesh.add( wireframe );

  //outer frame end

  //inner world like object start

  var sphere_material = [
      new THREE.MeshLambertMaterial( { color: 0xffff00, side: THREE.DoubleSide } ),
      new THREE.MeshBasicMaterial( { transparent: true, opacity: 0 } )
  ];

  var sphere_geometry = new THREE.OctahedronGeometry( 60, 3 );
  // assign material to each face
  for( var i = 0; i < sphere_geometry.faces.length; i++ ) {
      sphere_geometry.faces[ i ].materialIndex = THREE.Math.randInt( 0, 1 );
  }

  sphere_geometry.sortFacesByMaterialIndex();

  var sphere_mesh = new THREE.Mesh( sphere_geometry, sphere_material );
  sphere_mesh.position.set(0, 0, 0)
  mesh.add(sphere_mesh);


  renderer = new THREE.WebGLRenderer({
    antialias: true
  });

  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

}
renderer.gammaInput = true;
renderer.gammaOutput = true;

function animate() {

  requestAnimationFrame(animate);

  mesh.rotation.x += 0.003;
  mesh.rotation.y += 0.003;

  renderer.render(scene, camera);

}

DEMO


回答1:


You're looking for volumetric lights. Check this code example below or maybe better look at it on jsfiddle (to see it in full dimensions not overplayed by console log).

It's based on this article. I slightly tweaked your code and updated the colors as well as some values and the code. It still needs some playing (e.g. number of faces, light color, shader properties etc.) but hopefully will help you. It all really depends how you wish to make it look like.

THREE.VolumetericLightShader = {
  uniforms: {
    tDiffuse: {value:null},
    lightPosition: {value: new THREE.Vector2(0.5, 0.5)},
    exposure: {value: 0.18},
    decay: {value: 0.95},
    density: {value: 0.8},
    weight: {value: 0.4},
    samples: {value: 50}
  },

  vertexShader: [
    "varying vec2 vUv;",
    "void main() {",
      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
    "}"
  ].join("\n"),

  fragmentShader: [
    "varying vec2 vUv;",
    "uniform sampler2D tDiffuse;",
    "uniform vec2 lightPosition;",
    "uniform float exposure;",
    "uniform float decay;",
    "uniform float density;",
    "uniform float weight;",
    "uniform int samples;",
    "const int MAX_SAMPLES = 100;",
    "void main()",
    "{",
      "vec2 texCoord = vUv;",
      "vec2 deltaTextCoord = texCoord - lightPosition;",
      "deltaTextCoord *= 1.0 / float(samples) * density;",
      "vec4 color = texture2D(tDiffuse, texCoord);",
      "float illuminationDecay = 1.0;",
      "for(int i=0; i < MAX_SAMPLES; i++)",
      "{",
        "if(i == samples){",
          "break;",
        "}",
        "texCoord -= deltaTextCoord;",
        "vec4 sample = texture2D(tDiffuse, texCoord);",
        "sample *= illuminationDecay * weight;",
        "color += sample;",
        "illuminationDecay *= decay;",
      "}",
      "gl_FragColor = color * exposure;",
    "}"
  ].join("\n")
};

THREE.AdditiveBlendingShader = {
  uniforms: {
    tDiffuse: { value:null },
    tAdd: { value:null }
  },

  vertexShader: [
    "varying vec2 vUv;",
    "void main() {",
      "vUv = uv;",
      "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
    "}"
  ].join("\n"),

  fragmentShader: [
    "uniform sampler2D tDiffuse;",
    "uniform sampler2D tAdd;",
    "varying vec2 vUv;",
    "void main() {",
      "vec4 color = texture2D( tDiffuse, vUv );",
      "vec4 add = texture2D( tAdd, vUv );",
      "gl_FragColor = color + add;",
    "}"
  ].join("\n")
};

THREE.PassThroughShader = {
	uniforms: {
		tDiffuse: { value: null }
	},

	vertexShader: [
		"varying vec2 vUv;",
    "void main() {",
		  "vUv = uv;",
			"gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
		"}"
	].join( "\n" ),

	fragmentShader: [
    "uniform sampler2D tDiffuse;",
    "varying vec2 vUv;",
    "void main() {",
			"gl_FragColor = texture2D( tDiffuse, vec2( vUv.x, vUv.y ) );",
		"}"
	].join( "\n" )
};

(function(){
  var scene, camera, renderer, composer, box, pointLight,
      occlusionComposer, occlusionRenderTarget, occlusionBox, lightSphere,
      volumetericLightShaderUniforms,
      DEFAULT_LAYER = 0,
      OCCLUSION_LAYER = 1,
      renderScale = 0.5,
      angle = 0,
      sphere_mesh,
      mesh;
  
  scene = new THREE.Scene();
  camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
  renderer = new THREE.WebGLRenderer();
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );

  function setupScene(){
    var ambientLight,
        geometry,
        material;

    ambientLight = new THREE.AmbientLight(0x2c3e50);
    scene.add(ambientLight);
    
    pointLight = new THREE.PointLight(0xddddff);
    scene.add(pointLight);
    
    geometry = new THREE.SphereBufferGeometry( 1, 32, 32 );
    material = new THREE.MeshBasicMaterial( { color: 0x99ddff } );
    lightSphere = new THREE.Mesh( geometry, material );
    lightSphere.layers.set( OCCLUSION_LAYER );
    scene.add( lightSphere );
    
    camera.position.z = 6;
  }
  
  function addFragmentedSphere(){
    var geometry = new THREE.DodecahedronGeometry(2.9, 0);

  var material = new THREE.MeshPhongMaterial({
    color: 0x000000,
    specular: 0xffffff,
    shininess: 1,
    shading: THREE.FlatShading,
    polygonOffset: true,
    polygonOffsetFactor: 1,
    wireframe:true

  });

  mesh = new THREE.Mesh(geometry, material);

  scene.add(mesh);

  //outer frame end

  //inner world like object start

  var sphere_material = [
      new THREE.MeshLambertMaterial( { color: 0xffff00, side: THREE.DoubleSide } ),
      new THREE.MeshBasicMaterial( { transparent: true, opacity: 0 } )
  ];

  var sphere_geometry = new THREE.OctahedronGeometry( 2.7, 4 );
  // assign material to each face
  for( var i = 0; i < sphere_geometry.faces.length; i++ ) {
      sphere_geometry.faces[ i ].materialIndex = THREE.Math.randInt( 0, 1 );
  }

  sphere_geometry.sortFacesByMaterialIndex();

  sphere_mesh = new THREE.Mesh( sphere_geometry, sphere_material );
  sphere_mesh.position.set(0, 0, 0)
  mesh.add(sphere_mesh);
  sphere_mesh.layers.set( OCCLUSION_LAYER );
  }

  function setupPostprocessing(){
    var pass;
    
    occlusionRenderTarget = new THREE.WebGLRenderTarget( window.innerWidth * renderScale, window.innerHeight * renderScale );
    occlusionComposer = new THREE.EffectComposer( renderer, occlusionRenderTarget);
    occlusionComposer.addPass( new THREE.RenderPass( scene, camera ) );
    pass = new THREE.ShaderPass( THREE.VolumetericLightShader );
    pass.needsSwap = false;
    occlusionComposer.addPass( pass );
    
    volumetericLightShaderUniforms = pass.uniforms;
    volumetericLightShaderUniforms.exposure.value = 0.5;
    volumetericLightShaderUniforms.decay.value = 0.96;
    volumetericLightShaderUniforms.density.value = 0.95;
    volumetericLightShaderUniforms.weight.value = 0.59;
    volumetericLightShaderUniforms.samples.value = 100;
    
    composer = new THREE.EffectComposer( renderer );
    composer.addPass( new THREE.RenderPass( scene, camera ) );
    pass = new THREE.ShaderPass( THREE.AdditiveBlendingShader );
    pass.uniforms.tAdd.value = occlusionRenderTarget.texture;
    composer.addPass( pass );
    pass.renderToScreen = true;
  }
  
  function onFrame(){
    requestAnimationFrame( onFrame );
    update();
    render();
  }
  
  function update(){
    mesh.rotation.x += 0.003;
    mesh.rotation.y += 0.003;
  }

  function render(){
    camera.layers.set(OCCLUSION_LAYER);
    renderer.setClearColor(0x000000);
    occlusionComposer.render();
    
    camera.layers.set(DEFAULT_LAYER);
    renderer.setClearColor(0x090611);
    composer.render();
  }
  
  function addRenderTargetImage(){           
    var material,
        mesh,
        folder;

    material = new THREE.ShaderMaterial( THREE.PassThroughShader );
    material.uniforms.tDiffuse.value = occlusionRenderTarget.texture;

    mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), material );
    composer.passes[1].scene.add( mesh );
    mesh.visible = false;
  }
  
  window.addEventListener( 'resize', function(){

    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize( window.innerWidth, window.innerHeight );

    var pixelRatio = renderer.getPixelRatio(),
        newWidth  = Math.floor( window.innerWidth / pixelRatio ) || 1,
        newHeight = Math.floor( window.innerHeight / pixelRatio ) || 1;

    composer.setSize( newWidth, newHeight );
    occlusionComposer.setSize( newWidth * renderScale, newHeight * renderScale );
        
  }, false );
  
  setupScene();
  setupPostprocessing();
  addFragmentedSphere();//
  addRenderTargetImage();
  onFrame();
}())
<script src="//cdn.rawgit.com/mrdoob/three.js/master/build/three.min.js"></script>
<script src="https://abberg.github.io/lib/shaders/CopyShader.js"></script>
<script src="https://abberg.github.io/lib/postprocessing/EffectComposer.js"></script>
<script src="https://abberg.github.io/lib/postprocessing/RenderPass.js"></script>
<script src="https://abberg.github.io/lib/postprocessing/ShaderPass.js"></script>


来源:https://stackoverflow.com/questions/46864037/how-to-get-sun-rays-from-the-middle-of-the-object-in-threejs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!