在体积固定步长raymarching中的摆动

问题描述 投票:1回答:1

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

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); 
    }


}

我正在尝试设置一个光线行进着色器,因此我将它附加到ThreeJS中的旋转立方体上,但是不是固定的,面向镜头的球体/圆,这似乎是我的目标,我似乎得到了一个看起来像是从球体摆动的球体。立方体的旋转(但实际上包含网格本身的体积不应该真正重要吗?)。我无法确定原因。

three.js glsl webgl shader
1个回答
0
投票

引起问题,因为(来自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>
© www.soinside.com 2019 - 2024. All rights reserved.