【问题标题】:Wobble in volumetric fixed step raymarching体积固定步长光线行进中的摆动
【发布时间】:2020-05-04 07:25:13
【问题描述】:

我的着色器遇到了错误。对于顶点:

varying vec3 worldPosition;
varying vec3 viewDirection;

void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

    worldPosition = vec3(modelMatrix * vec4(position, 1.0));
    viewDirection = normalize(worldPosition - cameraPosition);

}

对于片段:

uniform float time;
varying vec3 worldPosition;
varying vec3 viewDirection;

/// utilities

bool sphereHit (vec3 p)
{
    return distance(p,vec3(0,0,0)) < 1.0;
}

#define STEP_SIZE 0.01

bool raymarchHit (vec3 in_position, vec3 direction)
{
    for (int i = 0; i < 2000; i++)
    {
    if ( sphereHit(in_position) )
        return true;

        in_position += direction * STEP_SIZE;
    }
    return false;
}

void main() {
    if(raymarchHit(worldPosition, viewDirection)){
        gl_FragColor = vec4(1.0,0.0,0.0,1.0); 
    }else{
        gl_FragColor = vec4(0.0,0.0,1.0,0.5); 
    }


}

我正在尝试设置一个 raymarching 着色器,所以我将它附加到 ThreeJS 中的一个旋转立方体上,而不是一个固定的、面向相机的球体/圆,这是我似乎得到一个似乎从其中摆动的球体的目标立方体的旋转(但实际上包含网格本身的体积并不重要吗?)。我一直无法确定原因。

【问题讨论】:

标签: three.js glsl webgl shader


【解决方案1】:

问题是因为(来自OpenGL ES Shading Language 1.00 Specification - 4.3.5 Varying

每个顶点设置不同的变量,并以透视正确的方式进行插值 在被渲染的基元之上。

为了使您的算法有效,您必须插入射线的方向noperspective
由于 GLSL ES 1.00 不提供Interpolation qualifiers,因此您必须找到解决方法。

在片段着色器中计算光线:

void main() {
    bool hit = raymarchHit(worldPosition, normalize(worldPosition - cameraPosition));
    gl_FragColor = hit ? vec4(1.0,0.0,0.0,1.0) : vec4(0.0,0.0,1.0,0.5); 
}

看例子:

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

class VolumetricNebula_sp {
    constructor(vertexShader, fragmentShader) {
        this.clock = new THREE.Clock();
        this.uniforms = {
            time: {
                type: 'float',
                value: 2.0
            }
        }
        this.geometry = new THREE.BoxBufferGeometry(4.0, 4.0, 4.0); // width, height, depth

        this.material = new THREE.ShaderMaterial({
            uniforms: this.uniforms,
            fragmentShader: fragmentShader,
            vertexShader: vertexShader,
            transparent: true
        })

        this.mesh = new THREE.Mesh(this.geometry, this.material);
        scene.add(this.mesh);
    }
    update() {
        this.uniforms.time.value = this.clock.getElapsedTime();
        this.mesh.rotation.x += 0.01;
        this.mesh.rotation.y += 0.01;
        this.mesh.rotation.z += 0.01;
    }
}

function init() {
    // Renderer.
    renderer = new THREE.WebGLRenderer();
    //renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    // Add renderer to page
    document.body.appendChild(renderer.domElement);

    // Create camera.
    camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
    camera.position.z = 5;

    // Create scene.
    scene = new THREE.Scene();

    volVertexShader = `varying highp vec3 worldPosition;
    //varying vec3 viewDirection;

    void main() {
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

        worldPosition = vec3(modelMatrix * vec4(position, 1.0));
        //viewDirection = normalize(worldPosition - cameraPosition);

    }`;
    volFragShader = `uniform float time;
    varying vec3 worldPosition;
    //varying vec3 viewDirection;

    /// utilities

    bool sphereHit (vec3 p)
    {
        return distance(p,vec3(0,0,0)) < 1.0;
    }

    #define STEP_SIZE 0.1

    bool raymarchHit (vec3 in_position, vec3 direction)
    {
        for (int i = 0; i < 100; i++)
        {
            if ( sphereHit(in_position) )
                return true;
            in_position += direction * STEP_SIZE;
        }
        return false;
    }

    void main() {
        bool hit = raymarchHit(worldPosition, normalize(worldPosition - cameraPosition));
        gl_FragColor = hit ? vec4(1.0,0.0,0.0,1.0) : vec4(0.0,0.0,1.0,0.5); 
    }`;

    var volumetricNebulaCenterPiece = new VolumetricNebula_sp(volVertexShader, volFragShader);

    // Add listener for window resize.
    window.addEventListener('resize', onWindowResize, false);

    // Add stats to page.
    //stats = new Stats();
    //document.body.appendChild( stats.dom );
    
    function animate() {
    		volumetricNebulaCenterPiece.update();
   		 	renderer.render(scene, camera);
    		//stats.update();
    		requestAnimationFrame(animate);
		}
    animate();
}

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
}
init();
body { padding: 0; margin: 0; }
canvas { display: block; }
<!--script src="https://threejs.org/build/three.min.js"></script-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/110/three.min.js"></script>

【讨论】:

  • 啊,我明白了,我通过增加容器卷的顶点数量找到了一个临时解决方法,但这可以正确修复它!谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多