2015-11-17 36 views
5

Czy istnieje sposób, aby uzyskać efekt litofan użyciu Three.jslitofan efekt w trzech JS

Sample image.

Obecnie próbowałem różnych materiałów z przezroczystością i nieprzezroczystością, ale nie udało się.

<html lang="en"> 
<head> 
    <title>Lith (Three.js)</title> 
    <meta charset="utf-8"> 
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> 

</head> 
<body> 

<script src="js/three.min.js"></script> 
<script src="./js/dat.gui.min.js"></script> 
<script src="./js/STLLoader.js"></script> 
<script src="js/Detector.js"></script> 
<script src="js/OrbitControls.js"></script> 
<script src="js/SkyShader.js"></script> 
<script src="js/THREEx.WindowResize.js"></script> 

<div id="ThreeJS" style="position: absolute; left:0px; top:0px"></div> 
<script> 
var container, scene, camera, renderer, controls, stats; 
var clock = new THREE.Clock(); 
var cube; 

init(); 
animate(); 

function init() 
{ 
    // SCENE 
    scene = new THREE.Scene(); 
    // CAMERA 
    var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight; 
    var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH/SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000; 
    camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR); 
    scene.add(camera); 
    camera.position.set(0,150,400); 
    camera.lookAt(scene.position); 
    // RENDERER 
    if (Detector.webgl) 
     renderer = new THREE.WebGLRenderer({antialias:true}); 
    else 
     renderer = new THREE.CanvasRenderer(); 
    renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); 
    renderer.setClearColor(0x999999); 
    container = document.getElementById('ThreeJS'); 
    container.appendChild(renderer.domElement); 
    // EVENTS 
    THREEx.WindowResize(renderer, camera); 

    controls = new THREE.OrbitControls(camera, renderer.domElement); 

    // SKYBOX/FOG 
    var skyBoxGeometry = new THREE.CubeGeometry(10000, 10000, 10000); 
    var skyBoxMaterial = new THREE.MeshBasicMaterial({ color: 0x9999ff, side: THREE.BackSide }); 
    var skyBox = new THREE.Mesh(skyBoxGeometry, skyBoxMaterial); 
    // scene.add(skyBox); 
    scene.fog = new THREE.FogExp2(0x9999ff, 0.00025); 

    //////////// 
    // CUSTOM // 
    //////////// 

    // must enable shadows on the renderer 
    renderer.shadowMapEnabled = true; 

    // "shadow cameras" show the light source and direction 

    // spotlight #1 -- yellow, dark shadow 
    var spotlight = new THREE.SpotLight(0xffff00); 
    spotlight.position.set(0,150,-50); 
    spotlight.shadowCameraVisible = true; 
    spotlight.shadowDarkness = 0.8; 
    spotlight.intensity = 2; 
    // must enable shadow casting ability for the light 
    spotlight.castShadow = true; 
    scene.add(spotlight); 

    var sphereSize = 10; 
    var pointLightHelper = new THREE.SpotLightHelper(spotlight, sphereSize); 
    scene.add(pointLightHelper); 


    var light = new THREE.SpotLight(0x999999); 
    light.intensity = 0.6; 
    camera.add(light); 

    var loader = new THREE.STLLoader(); 
    loader.load('./TestOriginal.stl', function(object) { 
     meshObject = object; 
     var color = new THREE.Color(0xffffff); 
     var material = new THREE.MeshPhongMaterial({ 
        color: color,//'white', 
        side: THREE.DoubleSide, 
        //shading: THREE.SmoothShading, 
        opacity: 0.6, 
        transparent: true 
       }); 
     this.mesh = new THREE.Mesh(object, material); 

     mesh.position.set(0,0,0); 
     scene.add(mesh); 

     mesh.position.set(0,0,0); 
     var newScale = 1; 
     mesh.geometry.computeBoundingBox(); 
     boundingBox = mesh.geometry.boundingBox; 
     mesh.translateX(-((boundingBox.max.x + boundingBox.min.x) * newScale)/2); 
     mesh.translateY(-((boundingBox.max.y + boundingBox.min.y) * newScale)/2); 
     mesh.translateZ(-((boundingBox.max.z + boundingBox.min.z) * newScale)/2); 
    }); 

    // floor: mesh to receive shadows 
    var floorTexture = new THREE.ImageUtils.loadTexture('./checkerboard.jpg'); 
    floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping; 
    floorTexture.repeat.set(10, 10); 
    // Note the change to Lambert material. 
    var floorMaterial = new THREE.MeshLambertMaterial({ map: floorTexture, side: THREE.DoubleSide }); 
    var floorGeometry = new THREE.PlaneGeometry(1000, 1000, 100, 100); 
    var floor = new THREE.Mesh(floorGeometry, floorMaterial); 
    floor.position.y = -80.5; 
    floor.rotation.x = Math.PI/2; 
    floor.receiveShadow = true; 
    scene.add(floor); 
} 

function animate() 
{ 
    requestAnimationFrame(animate); 
    render();  
    update(); 
} 

function update() 
{ 
    controls.update(); 
} 

function render() 
{ 
    renderer.render(scene, camera); 
} 

</script> 

</body> 
</html> 

I moje wyjście jest jak:

output image

Próbowałem również materiał cieniowania i to daje mi coś takiego: Shadder output

Co chcę jest: nie powinno być światłem z tyłu obiektu i wygrawerowana część przedmiotu powinna świecić (w odniesieniu do głębokości przedmiotu).

+0

To naprawdę interesujące pytanie. Czy próbowałeś szukać shadera, być może napisanego w GLSL lub Cg, który daje efekt? Zdecydowanie nie jestem osobą, o którą pytam, ale możliwe, że ją napiszesz! Być może daj mu dźgnięcie/znajdź kogoś innego (niekompletne lub nie), a następnie zadaj nowe pytanie dotyczące tego problemu :) –

Odpowiedz

5

To nie jest odpowiedź, ale naprawdę uważam, że najlepszym podejściem byłoby pisanie (lub znajdowanie) niestandardowego modułu cieniującego. Przedmówę, mówiąc, że pisanie shaderów jest dziecinnie proste: może stać się niewiarygodnie skomplikowana, ponieważ języki programowania cieniowania są stosunkowo niskie i polegają głównie na znajomości ezoterycznej geometrii/matematyki.


Po pewnym Snooping, wygląda na to, że potrzebny jest moduł cieniujący, który osiąga coś, co nazywa rozpraszania podpowierzchniowe (znane potocznie jako SSS) - to w istocie zachowanie światła przez półprzezroczystą obiektu, na podstawie jego grubość (i niektóre inne właściwości, których nie będę zagłębiać się):

Sub Surface Scattering (SSS)

aby osiągnąć efekt litofan, trzeba by wygenerować „grubość mapę” rodzaju, który mapuje do siatki Twojego obiektu, a następnie niestandardowy moduł cieniujący prawidłowo rozprasza światło na tej mapie, aby uzyskać efekt podobny do tego pragniesz.

Nauczyłem się tego wszystkiego, przechodząc przez głównie simple presentation wykonany przez wiodącego programistę renderującego w grach DICE. Oto przykład slajd z prezentacji:

DICE Game's presentation of their SSS shader implementation

ten shader daje efekt podobny to na podstawie grubości w czasie rzeczywistym:

enter image description here

Jeśli poważnie o osiągnięciu tego efektu, zdecydowanie zalecałbym czytanie w programowaniu shaderów Cg lub GLSL. Osobiście lubię Cg, ponieważ byłem zachęcony, aby nauczyć się go, ponieważ jest kompatybilny z Unity3D. Z tego powodu znalazłem świetny materiał do nauki Cg, a mianowicie the wikibook on the subject. Jest (nieco) specyficzne dla Jedności, ale zasady będą zdrowe.

W każdym razie życzę powodzenia w tej sprawie. Mam nadzieję że to pomoże!