【问题标题】:How do I use texture-mapping in a simple ray tracer?如何在简单的光线追踪器中使用纹理映射?
【发布时间】:2010-10-25 07:46:51
【问题描述】:

我正在尝试向 C++ 中的光线追踪器添加功能。也就是说,我正在尝试将纹理映射添加到球体。为简单起见,我使用数组来存储纹理数据。我通过使用十六进制编辑器并将正确的字节值复制到我的代码中的数组中来获取纹理数据。这只是为了我的测试目的。当这个数组的值对应于一个简单的红色图像时,它似乎工作接近预期,除了没有阴影。 first image http://dl.dropbox.com/u/367232/Texture.jpg 图像的右下角显示了正确的球体应该是什么样子。此球体的颜色使用一种设置颜色,而不是纹理贴图。

另一个问题是,当纹理贴图不是只有一种颜色像素时,它会变成白色。我的测试图像是一张水图片,当它映射时,它只显示围绕白色的一圈蓝色像素。

bmp http://dl.dropbox.com/u/367232/vPoolWater.bmp

完成后,它会简单地显示为: second image http://dl.dropbox.com/u/367232/texture2.jpg

这里有几个sn-ps的代码:

  Color getColor(const Object *object,const Ray *ray, float *t)
  {
   if (object->materialType == TEXTDIF || object->materialType == TEXTMATTE) {
    float distance = *t;
    Point pnt = ray->origin + ray->direction * distance;
    Point oc = object->center; 
    Vector ve = Point(oc.x,oc.y,oc.z+1) - oc;
    Normalize(&ve);
    Vector vn = Point(oc.x,oc.y+1,oc.z) - oc;
    Normalize(&vn);
    Vector vp = pnt - oc;
    Normalize(&vp);

    double phi = acos(-vn.dot(vp));

    float v = phi / M_PI;
    float u;

    float num1 = (float)acos(vp.dot(ve));
    float num = (num1 /(float) sin(phi));

    float theta = num /(float) (2 * M_PI);
    if (theta < 0 || theta == NAN) {theta = 0;}
    if (vn.cross(ve).dot(vp) > 0) {
        u = theta;
    }
    else {
        u = 1 - theta;
    }
    int x = (u * IMAGE_WIDTH) -1;
    int y = (v * IMAGE_WIDTH) -1;
    int p = (y * IMAGE_WIDTH + x)*3;

    return Color(TEXT_DATA[p+2],TEXT_DATA[p+1],TEXT_DATA[p]);

}
else {
    return object->color;
}
};

我在这里在 Trace 中调用颜色代码:

if (object->materialType == MATTE)
    return getColor(object, ray, &t);

Ray shadowRay;
int isInShadow = 0;
shadowRay.origin.x = pHit.x + nHit.x * bias;
shadowRay.origin.y = pHit.y + nHit.y * bias;
shadowRay.origin.z = pHit.z + nHit.z * bias;
shadowRay.direction = light->object->center - pHit;
float len = shadowRay.direction.length();
Normalize(&shadowRay.direction);
float LdotN = shadowRay.direction.dot(nHit);
if (LdotN < 0)
    return 0;
Color lightColor = light->object->color;
for (int k = 0; k < numObjects; k++) {
    if (Intersect(objects[k], &shadowRay, &t) && !objects[k]->isLight) {
        if (objects[k]->materialType == GLASS)
            lightColor *= getColor(objects[k], &shadowRay, &t); // attenuate light color by glass color
        else
            isInShadow = 1;
        break;
    }
}
lightColor *= 1.f/(len*len);
return (isInShadow) ? 0 : getColor(object, &shadowRay, &t) * lightColor * LdotN;
}

为了不让帖子陷入困境,我省略了其余代码,但可以看到 here。任何帮助是极大的赞赏。代码中唯一没有包含的部分是我定义纹理数据的地方,正如我所说,它只是直接取自上图的位图文件。

谢谢。

【问题讨论】:

    标签: c++ graphics texture-mapping


    【解决方案1】:

    可能是因为光线太亮太近,所以纹理刚刚被洗掉了。请注意,在纯红色的情况下,球体周围似乎没有任何渐变。红色看起来已经饱和了。

    您的 u,v 映射看起来正确,但那里可能有错误。我会添加一些 assert 语句以确保 u 和 v 确实介于 0 和 1 之间,并且 TEXT_DATA 数组的 p 索引也在范围内。

    【讨论】:

    • 然后我不确定我是否将球体设置为仅显示颜色而没有纹理,渐变看起来很好。我会考虑添加断言语句,并看看当我降低灯光亮度时会发生什么。
    • 这是问题的一部分。光线太亮了,它正在洗掉球体,但球体仍然只显示单一的纯色,有什么想法吗? dl.dropbox.com/u/367232/image3.jpg
    • 尝试使用floatdouble 作为渲染缓冲区(以及所有计算),而不是渲染到int 中。然后检查结果并将缓冲区转换为整数,方法是将每个像素的强度除以整个图像的最亮(最大强度)像素。
    【解决方案2】:

    如果您正在调试纹理,则应使用仅由纹理而非灯光决定颜色的常量材质。这样,您可以确保在对其进行任何照明之前正确地将纹理映射到图元并对其进行正确过滤。然后你知道那部分不是问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-03
      • 2021-05-13
      • 2016-03-11
      • 1970-01-01
      • 2011-05-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多