⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trianglemesh.java

📁 Sunflow是一个照片级的渲染系统
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
package org.sunflow.core.primitive;

import java.io.FileWriter;
import java.io.IOException;

import org.sunflow.SunflowAPI;
import org.sunflow.core.Instance;
import org.sunflow.core.IntersectionState;
import org.sunflow.core.ParameterList;
import org.sunflow.core.PrimitiveList;
import org.sunflow.core.Ray;
import org.sunflow.core.ShadingState;
import org.sunflow.core.ParameterList.FloatParameter;
import org.sunflow.core.ParameterList.InterpolationType;
import org.sunflow.math.BoundingBox;
import org.sunflow.math.MathUtils;
import org.sunflow.math.Matrix4;
import org.sunflow.math.OrthoNormalBasis;
import org.sunflow.math.Point3;
import org.sunflow.math.Vector3;
import org.sunflow.system.UI;
import org.sunflow.system.UI.Module;

public class TriangleMesh implements PrimitiveList {
    private static boolean smallTriangles = false;
    protected float[] points;
    protected int[] triangles;
    private WaldTriangle[] triaccel;
    private FloatParameter normals;
    private FloatParameter uvs;
    private byte[] faceShaders;

    public static void setSmallTriangles(boolean smallTriangles) {
        if (smallTriangles)
            UI.printInfo(Module.GEOM, "Small trimesh mode: enabled");
        else
            UI.printInfo(Module.GEOM, "Small trimesh mode: disabled");
        TriangleMesh.smallTriangles = smallTriangles;
    }

    public TriangleMesh() {
        triangles = null;
        points = null;
        normals = uvs = new FloatParameter();
        faceShaders = null;
    }

    public void writeObj(String filename) {
        try {
            FileWriter file = new FileWriter(filename);
            file.write(String.format("o object\n"));
            for (int i = 0; i < points.length; i += 3)
                file.write(String.format("v %g %g %g\n", points[i], points[i + 1], points[i + 2]));
            file.write("s off\n");
            for (int i = 0; i < triangles.length; i += 3)
                file.write(String.format("f %d %d %d\n", triangles[i] + 1, triangles[i + 1] + 1, triangles[i + 2] + 1));
            file.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public boolean update(ParameterList pl, SunflowAPI api) {
        boolean updatedTopology = false;
        {
            int[] triangles = pl.getIntArray("triangles");
            if (triangles != null) {
                this.triangles = triangles;
                updatedTopology = true;
            }
        }
        if (triangles == null) {
            UI.printError(Module.GEOM, "Unable to update mesh - triangle indices are missing");
            return false;
        }
        if (triangles.length % 3 != 0)
            UI.printWarning(Module.GEOM, "Triangle index data is not a multiple of 3 - triangles may be missing");
        pl.setFaceCount(triangles.length / 3);
        {
            FloatParameter pointsP = pl.getPointArray("points");
            if (pointsP != null)
                if (pointsP.interp != InterpolationType.VERTEX)
                    UI.printError(Module.GEOM, "Point interpolation type must be set to \"vertex\" - was \"%s\"", pointsP.interp.name().toLowerCase());
                else {
                    points = pointsP.data;
                    updatedTopology = true;
                }
        }
        if (points == null) {
            UI.printError(Module.GEOM, "Unable to update mesh - vertices are missing");
            return false;
        }
        pl.setVertexCount(points.length / 3);
        pl.setFaceVertexCount(3 * (triangles.length / 3));
        FloatParameter normals = pl.getVectorArray("normals");
        if (normals != null)
            this.normals = normals;
        FloatParameter uvs = pl.getTexCoordArray("uvs");
        if (uvs != null)
            this.uvs = uvs;
        int[] faceShaders = pl.getIntArray("faceshaders");
        if (faceShaders != null && faceShaders.length == triangles.length / 3) {
            this.faceShaders = new byte[faceShaders.length];
            for (int i = 0; i < faceShaders.length; i++) {
                int v = faceShaders[i];
                if (v > 255)
                    UI.printWarning(Module.GEOM, "Shader index too large on triangle %d", i);
                this.faceShaders[i] = (byte) (v & 0xFF);
            }
        }
        if (updatedTopology) {
            // create triangle acceleration structure
            init();
        }
        return true;
    }

    public float getPrimitiveBound(int primID, int i) {
        int tri = 3 * primID;
        int a = 3 * triangles[tri + 0];
        int b = 3 * triangles[tri + 1];
        int c = 3 * triangles[tri + 2];
        int axis = i >>> 1;
        if ((i & 1) == 0)
            return MathUtils.min(points[a + axis], points[b + axis], points[c + axis]);
        else
            return MathUtils.max(points[a + axis], points[b + axis], points[c + axis]);
    }

    public BoundingBox getWorldBounds(Matrix4 o2w) {
        BoundingBox bounds = new BoundingBox();
        if (o2w == null) {
            for (int i = 0; i < points.length; i += 3)
                bounds.include(points[i], points[i + 1], points[i + 2]);
        } else {
            // transform vertices first
            for (int i = 0; i < points.length; i += 3) {
                float x = points[i];
                float y = points[i + 1];
                float z = points[i + 2];
                float wx = o2w.transformPX(x, y, z);
                float wy = o2w.transformPY(x, y, z);
                float wz = o2w.transformPZ(x, y, z);
                bounds.include(wx, wy, wz);
            }
        }
        return bounds;
    }

    public void intersectPrimitiveRobust(Ray r, int primID, IntersectionState state) {
        // ray-triangle intersection here
        int tri = 3 * primID;
        int a = 3 * triangles[tri + 0];
        int b = 3 * triangles[tri + 1];
        int c = 3 * triangles[tri + 2];
        final float[] stack = state.getRobustStack();
        for (int i = 0, i3 = 0; i < 3; i++, i3 += 3) {
            stack[i3 + 0] = points[a + i];
            stack[i3 + 1] = points[b + i];
            stack[i3 + 2] = points[c + i];
        }
        stack[9] = Float.POSITIVE_INFINITY;
        int stackpos = 0;
        float orgX = r.ox;
        float dirX = r.dx, invDirX = 1 / dirX;
        float orgY = r.oy;
        float dirY = r.dy, invDirY = 1 / dirY;
        float orgZ = r.oz;
        float dirZ = r.dz, invDirZ = 1 / dirZ;
        float t1, t2;
        float minx, maxx;
        float miny, maxy;
        float minz, maxz;
        float mint = r.getMin();
        float maxt = r.getMax();
        while (stackpos >= 0) {
            float intervalMin = mint;
            float intervalMax = maxt;
            float p0x = stack[stackpos + 0];
            float p1x = stack[stackpos + 1];
            float p2x = stack[stackpos + 2];
            t1 = ((minx = MathUtils.min(p0x, p1x, p2x)) - orgX) * invDirX;
            t2 = ((maxx = MathUtils.max(p0x, p1x, p2x)) - orgX) * invDirX;
            if (invDirX > 0) {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            } else {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax) {
                stackpos -= 10;
                continue;
            }
            float p0y = stack[stackpos + 3];
            float p1y = stack[stackpos + 4];
            float p2y = stack[stackpos + 5];
            t1 = ((miny = MathUtils.min(p0y, p1y, p2y)) - orgY) * invDirY;
            t2 = ((maxy = MathUtils.max(p0y, p1y, p2y)) - orgY) * invDirY;
            if (invDirY > 0) {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            } else {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax) {
                stackpos -= 10;
                continue;
            }
            float p0z = stack[stackpos + 6];
            float p1z = stack[stackpos + 7];
            float p2z = stack[stackpos + 8];
            t1 = ((minz = MathUtils.min(p0z, p1z, p2z)) - orgZ) * invDirZ;
            t2 = ((maxz = MathUtils.max(p0z, p1z, p2z)) - orgZ) * invDirZ;
            if (invDirZ > 0) {
                if (t1 > intervalMin)
                    intervalMin = t1;
                if (t2 < intervalMax)
                    intervalMax = t2;
            } else {
                if (t2 > intervalMin)
                    intervalMin = t2;
                if (t1 < intervalMax)
                    intervalMax = t1;
            }
            if (intervalMin > intervalMax) {
                stackpos -= 10;
                continue;
            }
            // intersection was found - keep going
            float size = (maxx - minx) + (maxy - miny) + (maxz - minz);
            if (Float.floatToRawIntBits(stack[stackpos + 9]) == Float.floatToRawIntBits(size)) {
                // L1 norm is 0, we are done
                r.setMax(intervalMin);
                triaccel[primID].intersectBox(r, p0x, p0y, p0z, primID, state);
                return; // safe to return, only one intersection per primitive
            }
            // not small enough yet - subdivide
            float p01x = (p0x + p1x) * 0.5f;
            float p01y = (p0y + p1y) * 0.5f;
            float p01z = (p0z + p1z) * 0.5f;

            float p12x = (p1x + p2x) * 0.5f;
            float p12y = (p1y + p2y) * 0.5f;
            float p12z = (p1z + p2z) * 0.5f;

            float p20x = (p2x + p0x) * 0.5f;
            float p20y = (p2y + p0y) * 0.5f;
            float p20z = (p2z + p0z) * 0.5f;

            // triangle 0
            stack[stackpos + 0] = p0x;
            stack[stackpos + 1] = p01x;
            stack[stackpos + 2] = p20x;
            stack[stackpos + 3] = p0y;
            stack[stackpos + 4] = p01y;
            stack[stackpos + 5] = p20y;
            stack[stackpos + 6] = p0z;
            stack[stackpos + 7] = p01z;
            stack[stackpos + 8] = p20z;
            stack[stackpos + 9] = size;
            stackpos += 10;
            // triangle 1
            stack[stackpos + 0] = p1x;
            stack[stackpos + 1] = p12x;
            stack[stackpos + 2] = p01x;
            stack[stackpos + 3] = p1y;
            stack[stackpos + 4] = p12y;
            stack[stackpos + 5] = p01y;
            stack[stackpos + 6] = p1z;
            stack[stackpos + 7] = p12z;
            stack[stackpos + 8] = p01z;
            stack[stackpos + 9] = size;
            stackpos += 10;
            // triangle 2
            stack[stackpos + 0] = p2x;
            stack[stackpos + 1] = p20x;
            stack[stackpos + 2] = p12x;
            stack[stackpos + 3] = p2y;
            stack[stackpos + 4] = p20y;
            stack[stackpos + 5] = p12y;
            stack[stackpos + 6] = p2z;
            stack[stackpos + 7] = p20z;
            stack[stackpos + 8] = p12z;
            stack[stackpos + 9] = size;
            stackpos += 10;
            // triangle 4
            stack[stackpos + 0] = p20x;
            stack[stackpos + 1] = p12x;
            stack[stackpos + 2] = p01x;
            stack[stackpos + 3] = p20y;
            stack[stackpos + 4] = p12y;
            stack[stackpos + 5] = p01y;
            stack[stackpos + 6] = p20z;
            stack[stackpos + 7] = p12z;
            stack[stackpos + 8] = p01z;
            stack[stackpos + 9] = size;
        }
    }

    private final void intersectTriangleKensler(Ray r, int primID, IntersectionState state) {
        int tri = 3 * primID;
        int a = 3 * triangles[tri + 0];
        int b = 3 * triangles[tri + 1];
        int c = 3 * triangles[tri + 2];
        float edge0x = points[b + 0] - points[a + 0];
        float edge0y = points[b + 1] - points[a + 1];
        float edge0z = points[b + 2] - points[a + 2];
        float edge1x = points[a + 0] - points[c + 0];
        float edge1y = points[a + 1] - points[c + 1];
        float edge1z = points[a + 2] - points[c + 2];
        float nx = edge0y * edge1z - edge0z * edge1y;
        float ny = edge0z * edge1x - edge0x * edge1z;
        float nz = edge0x * edge1y - edge0y * edge1x;
        float v = r.dot(nx, ny, nz);
        float iv = 1 / v;
        float edge2x = points[a + 0] - r.ox;
        float edge2y = points[a + 1] - r.oy;
        float edge2z = points[a + 2] - r.oz;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -