Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to make only parts of a component invisible?

I have an interaction concept that i want to build using Aframe. The scene consists out of 2 components.

  1. ball
  2. cube with elements inside of it

The elements inside of the cube are not visible because of the shell occludes them.

Now the tricky part: The ball has a radius, that hides the part of the shell inside its radius.

I think a picture would be good for clarification:

first image: cube with object inside; second image: circle with its radius; third image: case of cube dissapears inside radius of ball

  • Is this possible with Aframe or three.js?
  • How do I approach this?

edit: typo

like image 858
Thmsbrhn Avatar asked Sep 03 '25 03:09

Thmsbrhn


2 Answers

Just an option with the solution, mentioned in my comment:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(-5, 8, -8).setLength(8);
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target = new THREE.Vector3(0, 2, 0);
controls.update();

var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(-10, 10, 10);
scene.add(light);
scene.add(new THREE.AmbientLight(0xffffff, 0.25));

scene.add(new THREE.GridHelper(4, 4, 0x404040, 0x404040));

// boxes
var boxGeom = new THREE.BoxBufferGeometry();
boxGeom.translate(0, 0.5, 0);
var boxMaterial = new THREE.MeshLambertMaterial({
  color: "gray"
});
for (let x = 0; x <= 1; x++) {
  for (let z = 0; z <= 1; z++) {
    let box = new THREE.Mesh(boxGeom, boxMaterial);
    box.position.set(x - 0.5, 0, z - 0.5).multiplyScalar(1.5);
    box.scale.set(1, Math.abs(x) + Math.abs(z) + 1, 1);
    scene.add(box);
  }
}

// wrapping box
var wrappingBoxGeom = new THREE.BoxBufferGeometry(4, 4, 4);
wrappingBoxGeom.translate(0, 2, 0);
var wrappingBoxMaterial = getMaterial({
  diffuse: 0xaaaaaa,
  inside: false
});
var wrappingBox = new THREE.Mesh(wrappingBoxGeom, wrappingBoxMaterial);
scene.add(wrappingBox);

var clock = new THREE.Clock();
var time = 0;

render();

function render() {
  requestAnimationFrame(render);
  time += clock.getDelta();
  wrappingBoxMaterial.uniforms.clippingSphere.value.x = Math.sin(time) * 2;
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js"></script>
<script>
  var sphereRadius = {
    value: 2.5
  };

  function getMaterial(params) {

    var diffuse = params.diffuse === undefined ? 0xffffff : params.diffuse;
    var diffuseBack = params.diffuseBack === undefined ? diffuse : params.diffuseBack;

    var inside = params.inside === undefined ? true : params.inside;
    inside = inside ? 1 : -1;

    let lambert = new THREE.ShaderMaterial({
      uniforms: THREE.UniformsUtils.merge([THREE.ShaderLib.lambert.uniforms, {
        clippingSphere: {
          value: new THREE.Vector4()
        },
        diffuseBack: {
          value: new THREE.Color()
        }
      }]),

      vertexShader: THREE.ShaderLib.lambert.vertexShader
        .replace(/varying vec3 vLightFront;/g, 'varying vec3 vLightFront;\nvarying vec4 worldPosition;')
        .replace(/#include <worldpos_vertex>/g, 'worldPosition = modelMatrix * vec4( transformed, 1.0 );'),

      fragmentShader: THREE.ShaderLib.lambert.fragmentShader
        .replace(/uniform float opacity;/g, 'uniform float opacity;\nuniform vec4 clippingSphere;\nuniform vec3 diffuseBack;')
        .replace(/varying vec3 vLightFront;/g, 'varying vec3 vLightFront;\nvarying vec4 worldPosition;')
        .replace(/#include <clipping_planes_fragment>/g, '#include <clipping_planes_fragment>\n if (distance(worldPosition.xyz, clippingSphere.xyz) * sign(clippingSphere.w) > clippingSphere.w) discard;')
        .replace(/#include <dithering_fragment>/g, '#include <dithering_fragment>\n if (!gl_FrontFacing) gl_FragColor.xyz = diffuseBack;'),

      lights: true,

      side: THREE.DoubleSide
    });

    lambert.uniforms.clippingSphere.value.set(0, 3, -1, sphereRadius.value * inside);
    lambert.uniforms.diffuse.value.set(diffuse);
    lambert.uniforms.diffuseBack.value.set(diffuseBack);

    return lambert;
  }
</script>
like image 194
prisoner849 Avatar answered Sep 05 '25 00:09

prisoner849


Try csg.js with three.js with THREEBSP: https://github.com/sshirokov/ThreeBSP

Here's an example:

var box = new THREE.Mesh( new THREE.BoxGeometry( 10, 1, 10 ) );
var cube_bsp = new ThreeBSP( box );

var cutgeo = new THREE.SphereGeometry( 1, 16, 8 );
var sub =  new THREE.Mesh( cutgeo );
var substract_bsp  = new ThreeBSP( sub );
var subtract_bsp  = cube_bsp.subtract( substract_bsp );

var result = subtract_bsp.toMesh(); 

http://jsfiddle.net/L0rdzbej/151/

like image 29
ngokevin Avatar answered Sep 05 '25 01:09

ngokevin