最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

three.js - Is there a way to find out why the front faces are culled instead of the back in my procedurally generated 3D model?

programmeradmin0浏览0评论

I have been working on procedural generation of 3d models using threeJS. I have been able to successfully procure a model with the help of marching cubes algorithm and smoothened it with the help of Gaussian filter. However when I try to view the model on the window the surface on the front view is completely culled out and the insides of the model is seen through it. The code used to view the model is as follows

const marchingCubes = (scalarField, dims, threshold) => {
    const geometry = new THREE.BufferGeometry();
    
    const vertices = [];
    const colors = [];
    const normals = [];

    const pA = new THREE.Vector3();
    const pB = new THREE.Vector3();
    const pC = new THREE.Vector3();

    const cB = new THREE.Vector3();
    const aB = new THREE.Vector3();

    const color = new THREE.Color();

    for(let z = 0; z < dims[2] - 1; z++) {
        for(let y = 0; y < dims[1] - 1; y++) {
            for(let x = 0; x < dims[0] - 1; x++) {
                const cube = getCube(scalarField, x, y, z);
                const cubeIndex = getCubeIndex(cube, threshold);

                const edges = EdgeMasks[cubeIndex];
                if(edges === 0) {
                    continue;
                }

                const interpolatedVertices = interpolateEdges(cube, edges, threshold);
                const triangles = triangleTable[cubeIndex]

                let i = 0;

                while(triangles[i] != -1) {
                    const v1 = interpolatedVertices[triangles[i]];
                    const v2 = interpolatedVertices[triangles[i + 1]];
                    const v3 = interpolatedVertices[triangles[i + 2]];

                    pA.set(v1[0], v1[1], v1[2]);
                    pB.set(v2[0], v2[1], v2[2]);
                    pC.set(v3[0], v3[1], v3[2]);

                    cB.subVectors(pC, pB);
                    aB.subVectors(pA, pB);
                    cB.cross(aB);

                    cB.normalize();

                    const nx = cB.x;
                    const ny = cB.y;
                    const nz = cB.z;

                    const n0 = [nx, ny, nz];

                    const vx = (x / dims[0]) + 0.5;
                    const vy = (y / dims[1]) + 0.5;
                    const vz = (z / dims[2]) + 0.5;

                    color.setRGB(vx, vy, vz);
                    const c0 = [color.r, color.g, color.b];

                    vertices.push(...v1, ...v2, ...v3);
                    normals.push(...n0, ...n0, ...n0);
                    colors.push(...c0, ...c0, ...c0);
                    i += 3;
                }
            }
        }
    }

    geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));
    geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));

    geometryputeBoundingSphere();

    return geometry;
}

const WebApplication = () => {

    const Ref = useRef(null);

    const handleButtonClick = async () => {
        const scene = new THREE.Scene();
        scene.add(new THREE.AmbientLight(0x444444, 3));

        const light1 = new THREE.DirectionalLight(0xffffff, 1.5);
        light1.position.set(1, 1, 1);
        scene.add(light1);

        const light2 = new THREE.DirectionalLight(0xffffff, 4.5);
        light2.position.set(0, -1, 0);
        scene.add(light2);

        const renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x000000, 0.5);
        renderer.setPixelRatio(window.devicePixelRatio);

        if(Ref.current) {
            Ref.current.innerHTML = '';
            Ref.current.appendChild(renderer.domElement);
        }

        const camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500);

        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.5;
        controls.update();
        .
        .
        .
        const scalarField = generateScalarField(int16Array, dims);
        const threshold = 0.166666666665;

        const size = 5;
        const sigma = 1.0;

        const kernel = createGaussianKernel(size, sigma);
        const gaussianFilter = applyGaussianFilter(scalarField, dims, kernel);

        let geometry = marchingCubes(gaussianFilter, dims, threshold);

        let material = new THREE.MeshBasicMaterial({color: 0xaaaaaa, specular: 0xffffff, shininess: 250, side: THREE.FrontSide, vertexColors: true})
        const cubes = new THREE.Mesh(geometry, material);
        cubes.position.set(Math.trunc(-(dims[0] / 2)), Math.trunc(-(dims[1] / 2)), Math.trunc(-(dims[2] / 2)));
        scene.add(cubes);

        camera.position.z = Math.max(dims[0], dims[1], dims[2]) * 1.5;

        

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

  return (
    <div>
        <button onClick={handleButtonClick}>vroom vroom</button>
        <div ref={Ref} style={{ width: "100vw", height: "100vh" }}></div>
  </div>
  );
};

I am a beginner to a lot of these and in this code the color and normal attributes are copied off of a code block and are not verified (all code is copied off but mostly verified on the working). I don't know what portion is causing the error or what else should have I added to the code to make it work. All suggestions and remarks are welcome :)

The model in here is actually rendered in the code itself. I know it is not a good thing to do on the frontend but I am kinda brute forcing the whole thing in one file. After the model is created I downloaded it and checked whether if its rendered with no issues in blender and the model had no issues. I tried custom shaders on the model, didn't work. I don't know shader code much and I tried my best with it couldn't do it. The only material that gave any color to the model was MeshBasicMaterial but it didn't fix my current issue. Tried THREE.FrontSide, no effect. the last thing i tried was the vertex normals. I am a bit on the fot side on "Vectors", so the way i understood it was that the normals decide to which side the triangle is facing and that didn't happen in the result.

I have been working on procedural generation of 3d models using threeJS. I have been able to successfully procure a model with the help of marching cubes algorithm and smoothened it with the help of Gaussian filter. However when I try to view the model on the window the surface on the front view is completely culled out and the insides of the model is seen through it. The code used to view the model is as follows

const marchingCubes = (scalarField, dims, threshold) => {
    const geometry = new THREE.BufferGeometry();
    
    const vertices = [];
    const colors = [];
    const normals = [];

    const pA = new THREE.Vector3();
    const pB = new THREE.Vector3();
    const pC = new THREE.Vector3();

    const cB = new THREE.Vector3();
    const aB = new THREE.Vector3();

    const color = new THREE.Color();

    for(let z = 0; z < dims[2] - 1; z++) {
        for(let y = 0; y < dims[1] - 1; y++) {
            for(let x = 0; x < dims[0] - 1; x++) {
                const cube = getCube(scalarField, x, y, z);
                const cubeIndex = getCubeIndex(cube, threshold);

                const edges = EdgeMasks[cubeIndex];
                if(edges === 0) {
                    continue;
                }

                const interpolatedVertices = interpolateEdges(cube, edges, threshold);
                const triangles = triangleTable[cubeIndex]

                let i = 0;

                while(triangles[i] != -1) {
                    const v1 = interpolatedVertices[triangles[i]];
                    const v2 = interpolatedVertices[triangles[i + 1]];
                    const v3 = interpolatedVertices[triangles[i + 2]];

                    pA.set(v1[0], v1[1], v1[2]);
                    pB.set(v2[0], v2[1], v2[2]);
                    pC.set(v3[0], v3[1], v3[2]);

                    cB.subVectors(pC, pB);
                    aB.subVectors(pA, pB);
                    cB.cross(aB);

                    cB.normalize();

                    const nx = cB.x;
                    const ny = cB.y;
                    const nz = cB.z;

                    const n0 = [nx, ny, nz];

                    const vx = (x / dims[0]) + 0.5;
                    const vy = (y / dims[1]) + 0.5;
                    const vz = (z / dims[2]) + 0.5;

                    color.setRGB(vx, vy, vz);
                    const c0 = [color.r, color.g, color.b];

                    vertices.push(...v1, ...v2, ...v3);
                    normals.push(...n0, ...n0, ...n0);
                    colors.push(...c0, ...c0, ...c0);
                    i += 3;
                }
            }
        }
    }

    geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));
    geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));

    geometryputeBoundingSphere();

    return geometry;
}

const WebApplication = () => {

    const Ref = useRef(null);

    const handleButtonClick = async () => {
        const scene = new THREE.Scene();
        scene.add(new THREE.AmbientLight(0x444444, 3));

        const light1 = new THREE.DirectionalLight(0xffffff, 1.5);
        light1.position.set(1, 1, 1);
        scene.add(light1);

        const light2 = new THREE.DirectionalLight(0xffffff, 4.5);
        light2.position.set(0, -1, 0);
        scene.add(light2);

        const renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setClearColor(0x000000, 0.5);
        renderer.setPixelRatio(window.devicePixelRatio);

        if(Ref.current) {
            Ref.current.innerHTML = '';
            Ref.current.appendChild(renderer.domElement);
        }

        const camera = new THREE.PerspectiveCamera(27, window.innerWidth / window.innerHeight, 1, 3500);

        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.5;
        controls.update();
        .
        .
        .
        const scalarField = generateScalarField(int16Array, dims);
        const threshold = 0.166666666665;

        const size = 5;
        const sigma = 1.0;

        const kernel = createGaussianKernel(size, sigma);
        const gaussianFilter = applyGaussianFilter(scalarField, dims, kernel);

        let geometry = marchingCubes(gaussianFilter, dims, threshold);

        let material = new THREE.MeshBasicMaterial({color: 0xaaaaaa, specular: 0xffffff, shininess: 250, side: THREE.FrontSide, vertexColors: true})
        const cubes = new THREE.Mesh(geometry, material);
        cubes.position.set(Math.trunc(-(dims[0] / 2)), Math.trunc(-(dims[1] / 2)), Math.trunc(-(dims[2] / 2)));
        scene.add(cubes);

        camera.position.z = Math.max(dims[0], dims[1], dims[2]) * 1.5;

        

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

  return (
    <div>
        <button onClick={handleButtonClick}>vroom vroom</button>
        <div ref={Ref} style={{ width: "100vw", height: "100vh" }}></div>
  </div>
  );
};

I am a beginner to a lot of these and in this code the color and normal attributes are copied off of a code block and are not verified (all code is copied off but mostly verified on the working). I don't know what portion is causing the error or what else should have I added to the code to make it work. All suggestions and remarks are welcome :)

The model in here is actually rendered in the code itself. I know it is not a good thing to do on the frontend but I am kinda brute forcing the whole thing in one file. After the model is created I downloaded it and checked whether if its rendered with no issues in blender and the model had no issues. I tried custom shaders on the model, didn't work. I don't know shader code much and I tried my best with it couldn't do it. The only material that gave any color to the model was MeshBasicMaterial but it didn't fix my current issue. Tried THREE.FrontSide, no effect. the last thing i tried was the vertex normals. I am a bit on the fot side on "Vectors", so the way i understood it was that the normals decide to which side the triangle is facing and that didn't happen in the result.

Share Improve this question edited Jan 31 at 6:32 DarkBee 15.6k8 gold badges72 silver badges117 bronze badges asked Jan 31 at 6:16 Anto AlexAnto Alex 55 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

The reason why the model was seen as inside out when rendered was because the side was the wrong one and since there was a large number of vertices joined together simply assigning THREE.FrontSide didn't help with it. So from the information I gathered, in THREE.BufferGeometry whether a triangle is rendered as FrontSide or BackSide depends on the winding order of the vertices. So I flipped all the values in the triangleTable (the triangleTable consist of three edges of the triangle, may contain multiple triangle values so flipped here doesn't mean total reversal just the triangle edges, so 3 each until the end). If the winding order is in Counter Clock Wise then FrontSide will be shown and BackSide when the order is Clock Wise.

I used the lookup table from https://gist.github/dwilliamson/c041e3454a713e58baf6e4f8e5fffecd

and ran this code block to flip the values

const transform = [];
        let i = 0;
        let j = 0;
        for(i = 0; i < 256; i++){
            transform[i] = [];
            for(j = 0; triangleTable[i][j] != -1; j += 3) {
                transform[i][j] = triangleTable[i][j + 2];
                transform[i][j + 1] = triangleTable[i][j + 1];
                transform[i][j + 2] = triangleTable[i][j];
            }
            transform[i][j] = -1;
        }
        console.log(transform);

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论