【问题标题】:Three.js / Webgl X-RAY effect三.js/Webgl X-RAY 效果
【发布时间】:2014-12-07 19:36:31
【问题描述】:

如何在three.js/webgl中实现X射线风格的效果?有点这样的

UPD

我需要使用这些东西进行实时渲染,而不是静止图像。这可以通过着色器来完成,它根据距离在重叠上以非线性方式改变密度。我简单了解理论,但没有实践,这就是我需要帮助的原因

【问题讨论】:

  • 看起来它与 3d 建模有关,而不是 webgl - 带有光线跟踪渲染的透明材料,询问 3d 相关资源。
  • 我需要用这些东西进行实时渲染,而不是静止图像。这可以通过着色器来完成,它根据距离在重叠上以非线性方式改变密度。我只是简单地了解理论,但没有实践,这就是我问的原因

标签: javascript html 3d three.js webgl


【解决方案1】:

这是 Владимир Корнилов 的示例,只是我稍微更改了着色器。

我不确定他使用dot(vNormal, vNormel) 的目的。做abs(dot(vNormal, vec3(0, 0, 1)) 会在面对或远离视图时给你一些更亮的东西。让它1.0 - abs(dot(vNormal, vec3(0, 0, 1)) 会翻转,这样垂直于视图就会更亮。然后添加战俘,我觉得它看起来更好,但我想这是主观的

var human;

var $ = document.querySelector.bind(document);

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000);
var renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});
renderer.setClearColor(0x000000, 1.0);

lookAt = scene.position;
lookAt.y = 15;
camera.lookAt(lookAt);

document.body.appendChild(renderer.domElement);

var customMaterial = new THREE.ShaderMaterial(
  {
    uniforms: {
      p: { type: "f", value: 2 },
      glowColor: { type: "c", value: new THREE.Color(0x84ccff) },
    },
    vertexShader: $('#vertexShader').text,
    fragmentShader: $('#fragmentShader').text,
    side: THREE.DoubleSide,
    blending: THREE.AdditiveBlending,
    transparent: true,
    depthWrite: false
  });

var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load('http://greggman.github.io/doodles/assets/woman.dae', function (collada) {
  dae = collada.scene;

  dae.traverse( function ( child ) {

    if (child instanceof THREE.Mesh) {
      console.log(child);
      child.material = customMaterial;
    }

  } );

  dae.scale.x = 0.2;
  dae.scale.y = 0.2;
  dae.scale.z = 0.2;
  human = dae;
  scene.add(human);
});


function resize() {
  var canvas = renderer.domElement;
  var width  = canvas.clientWidth;
  var height = canvas.clientHeight;
  if (canvas.width !== width || canvas.height !== height) {
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}
    
// call the render function
function render(time) {
  time *= 0.001;
  
  resize();

  camera.position.x = -20 * (Math.cos(time));
  camera.position.z = (20 * (Math.sin(time)));
  camera.position.y = 20;

  camera.lookAt(lookAt);

  renderer.render(scene, camera);
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/r123/three.min.js"></script>
<script src="//greggman.github.io/doodles/js/three/js/loaders/ColladaLoader.js"></script>

<script id="vertexShader" type="x-shader/x-vertex">
        uniform float p;
        varying float intensity;
        void main()
        {
            vec3 vNormal = normalize( normalMatrix * normal );
            intensity = pow(1.0 - abs(dot(vNormal, vec3(0, 0, 1))), p);
            gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }
</script>

<!-- fragment shader a.k.a. pixel shader -->
<script id="fragmentShader" type="x-shader/x-vertex">
        uniform vec3 glowColor;
        varying float intensity;
        void main()
        {
            vec3 glow = glowColor * intensity;
            gl_FragColor = vec4( glow, 1.0 );
        }
</script>
<style>
  html, body {
    margin: 0;
    overflow: hidden;
    height: 100%;
  }
  canvas {
    width: 100%;
    height: 100%;
  }
</style>

【讨论】:

  • 你的例子非常适合我,谢谢!只是一个问题:是否可以有透明而不是黑色?
  • 谢谢,但这并不是我真正要问的。我已经有了透明画布。我的目标是让着色器从发光颜色变为透明,现在显示为黑色。但是我通过将片段着色器从gl_FragColor = vec4( glow, 1.0 ); 更改为gl_FragColor = vec4( glow, intensity ); 得到了它。无论如何,谢谢!
  • 甚至更好gl_FragColor = vec4( glow * intensity, intensity );
【解决方案2】:

好的,得到了​​可以接受的结果:

<!DOCTYPE html>
<html>

<head>
    <title>X-ray</title>
    <script type="text/javascript" src="js/three.js/build/three.js"></script>
    <script type="text/javascript" src="js/three.js/examples/js/loaders/OBJLoader.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script type="text/javascript" src="js/stats.min.js"></script>
    <script type="text/javascript" src="js/three.js/examples/js/renderers/SVGRenderer.js"></script>

    <script id="vertexShader" type="x-shader/x-vertex">
        uniform vec3 viewVector;
        uniform float c;
        uniform float p;
        varying float intensity;
        void main()
        {
            vec3 vNormal = normalize( normalMatrix * normal );
            vec3 vNormel = normalize( normalMatrix * viewVector );
            intensity = pow( c - dot(vNormal, vNormel), p );

            gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
        }
    </script>

    <!-- fragment shader a.k.a. pixel shader -->
    <script id="fragmentShader" type="x-shader/x-vertex">
        uniform vec3 glowColor;
        varying float intensity;
        void main()
        {
            vec3 glow = glowColor * intensity;
            gl_FragColor = vec4( glow, 1.0 );
        }
    </script>
    <style>
        body {
            /* set margin to 0 and overflow to hidden, to go fullscreen */

            margin: 0;
            overflow: hidden;
        }
    </style>
</head>

<body>

<div id="Stats-output">
</div>
<!-- Div which will hold the Output -->
<div id="WebGL-output">
</div>

<!-- Javascript code that runs our Three.js examples -->
<script type="text/javascript">
    // once everything is loaded, we run our Three.js stuff.
    $(function () {
        var mouseX = 0, mouseY = 0;
        var human;
        camstep = 0;

        var stats = initStats();

        // create a scene, that will hold all our elements such as objects, cameras and lights.
        var scene = new THREE.Scene();

        // create a camera, which defines where we're looking at.
        var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);

        // create a render and set the size
        var renderer = new THREE.WebGLRenderer({antialias: true, alpha: true});

        renderer.setClearColor(0x000000, 1.0);
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.shadowMapEnabled = true;
        renderer.shadowMapType = THREE.PCFShadowMap;


        materialCameraPosition = camera.position.clone();
        materialCameraPosition.z += 10;

        // position and point the camera to the center of the scene
        camera.position.x = -10;
        camera.position.y = 0;
        camera.position.z = 15;
        lookAt = scene.position;
        lookAt.y = 15;
        camera.lookAt(lookAt);

        // add subtle ambient lighting
        var ambientLight = new THREE.AmbientLight(0x0c0c0c);
        //scene.add(ambientLight);


        // add the output of the renderer to the html element
        $("#WebGL-output").append(renderer.domElement);

        var customMaterial = new THREE.ShaderMaterial(
                {
                    uniforms: {
                        "c": { type: "f", value: 1.0 },
                        "p": { type: "f", value: 3 },
                        glowColor: { type: "c", value: new THREE.Color(0x84ccff) },
                        viewVector: { type: "v3", value: materialCameraPosition }
                    },
                    vertexShader: document.getElementById('vertexShader').textContent,
                    fragmentShader: document.getElementById('fragmentShader').textContent,
                    side: THREE.FrontSide,
                    blending: THREE.AdditiveBlending,
                    transparent: true,
                    //opacity: 0.5,
                    depthWrite: false
                });

        var manager = new THREE.LoadingManager();
        manager.onProgress = function (item, loaded, total) {
            console.log(item, loaded, total);
        };
        var loader = new THREE.OBJLoader(manager);
        loader.load('body_anatomy3.obj', function (object) {
            console.log(object);
            object.traverse(function (child) {
                if (child instanceof THREE.Mesh) {
                    console.log(child);
                    child.material = customMaterial;
                }
            });
            object.position.y = 4;
            object.scale.x = 0.01;
            object.scale.y = 0.01;
            object.scale.z = 0.01;
            human = object;
            scene.add(human);
        });


        // call the render function
        var step = 0;
        render();

        function render() {
            stats.update();

            camstep += 0.02;

            camera.position.x = -20 * (Math.cos(camstep));
            camera.position.z = (20 * (Math.sin(camstep)));
            camera.position.y = 20;

            camera.lookAt(lookAt);

            if (human) {
                //human.rotation.y += 0.02;
                materialCameraPosition = camera.position.clone();
                materialCameraPosition.z += 10;
                human.traverse(function (child) {
                    if (child instanceof THREE.Mesh) {
                        //console.log(child.material.uniforms.viewVector);
                        child.material.uniforms.viewVector.value =
                                new THREE.Vector3().subVectors(camera.position, human.position);
                    }
                });
            }

            //sphere.material.uniforms.viewVector.value = new THREE.Vector3().subVectors(camera.position, sphere.position);

            // render using requestAnimationFrame
            requestAnimationFrame(render);
            renderer.render(scene, camera);
        }

        function initStats() {

            var stats = new Stats();

            stats.setMode(0); // 0: fps, 1: ms

            // Align top-left
            stats.domElement.style.position = 'absolute';
            stats.domElement.style.left = '0px';
            stats.domElement.style.top = '0px';

            $("#Stats-output").append(stats.domElement);

            return stats;
        }
    });
</script>
</body>

</html>

【讨论】:

    【解决方案3】:

    目前基于此演示 http://stemkoski.github.io/Three.js/Shader-Glow.html 使用发光着色器获得了接近结果

    【讨论】:

    • 您需要关闭背面剔除或渲染两次,一次背面,一次正面背面。您还需要关闭深度测试。我不知道如何在 Three.js 中做这些事情,但我确信它在文档中
    猜你喜欢
    • 1970-01-01
    • 2013-07-02
    • 2014-01-23
    • 2013-11-01
    • 1970-01-01
    • 2013-07-23
    • 2016-07-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多