首页 > 解决方案 > 为什么我的法线贴图不能在球体上正常工作?

问题描述

这可能更适合另一个堆栈交换,但因为我的 3d 引擎都是我从头开始编写的,所以我认为这是最好的地方。

我在网上找到的所有关于法线贴图的资源都是关于将它们应用于网格的,所以我只是猜到了为球体做这件事的正确方法。我用来扰动法线向量的基本算法是:

struct _Vec3 {
    double x;
    double y;
    double z;
};

struct _Rgb {
    unsigned char r;
    unsigned char g;
    unsigned char b;
};

void adjustNormal(Sphere* sphere, Vec3* point, Vec3* normal) {
    double* arr = getSphereCoordinates(sphere, point); // get coordinates of point, where 0 < x, y < 1
    double x = arr[0];
    double y = arr[1];
    Rgb* color = getPixel(sphere -> normalMap, x, y); // get the data from normal map
    x = (color -> r) / 255.0;
    y = (color -> g) / 255.0;
    double z = (color -> b) / 255.0;
    Vec3** ortho = getOrthogonalVectors(normal); // basis of tangent space
    Vec3* tangent = ortho[0];
    Vec3* bitangent = ortho[1];
    scaleVec3(normal, z);    // scale normal vector by z
    scaleVec3(tangent, y);   // scale tangent vector by y
    scaleVec3(bitangent, x); // scale bitangent vector by x
    normal = add3(normal, tangent, bitangent); // add together three vectors
    normalize(normal);
}

现在,我对此非常有信心getSphereCoordinates并且getPixel可以正常工作,因为将常规纹理(不是法线贴图)应用于球体可以正常工作。我不太自信,getOrthogonalVectors因为即使我改变它,我仍然对法线贴图有问题。以防万一,这里是:

Vec3** getOrthogonalVectors(Vec3* vec) {
    Vec3 temp;
    copyVec3(&temp, vec);
    temp.x += 10; // no matter how I change
    temp.y += 1;  // this to get a nonparallel vector,
    temp.z += 1;  // the normal map isn't correct

    Vec3* v1 = cross(vec, &temp);
    Vec3* v2 = cross(vec, v1);
    scaleVec3(v2, -1); // necessary for orientation

    normalize(v1);
    normalize(v2);

    Vec3** ans = malloc(sizeof(Vec3*) * 2);
    ans[1] = v1;
    ans[0] = v2;
    return ans;
}

下面是正在使用的法线贴图以及应用贴图后球体的外观。

法线贴图 领域

这张照片的光源与相机位于同一位置,因此理论上应该照亮球体的整个正面。有什么我做错了吗?

标签: cgraphics3d

解决方案


推荐阅读