为什么网格对象后面没有阴影?
Why there is no shadows behind the mesh object?
我正在为多边形模型创建一个基于 OpenGL 的光线追踪器。基本结构是将结果从片段着色器渲染到四边形。为了加速应用程序,使用了 BVH 树。
问题是,该方法测试阴影光线是否与某物相交 return 为真,而不应 return 为真,这意味着根本没有阴影。只有立方体的两侧是黑色的,它们不面向光源。
这是一个屏幕截图,您可以在其中看到平面上的立方体。还有一个光源。
以下是片段着色器的有用部分:trace
和 shadowIntersect
方法:
bool shadowIntersect(Ray ray1){ // for testing if the shadowray intersects something
for (int i;i<nodes.length();i++){
for (int j=0;j<nodes[i].indices.length();j++){
if (mod(nodes[i].indices[j].x,1)==0 && mod(nodes[i].indices[j].y, 1)==0 && mod(nodes[i].indices[j].z, 1)==0){
vec3 TrianglePointA=getCoordinatefromIndices(nodes[i].indices[j].x).xyz;
vec3 TrianglePointB=getCoordinatefromIndices(nodes[i].indices[j].y).xyz;
vec3 TrianglePointC=getCoordinatefromIndices(nodes[i].indices[j].z).xyz;
Hit hit=rayTriangleIntersect(ray1, TrianglePointA, TrianglePointB, TrianglePointC);
if (hit.t>0){
return true;
}
}
}
}
return false;
}
vec3 trace(Ray ray){
const float epsilon = 0.0001f;
vec3 outRadiance = vec3(0, 0, 0);
vec3 gold_ka = vec3(0.24725f, 0.1995f, 0.0745f);
vec3 gold_kd = vec3 (40.75164f, 0.60648f, 0.22648f);
vec3 gold_ks = vec3 (0.628281f, 0.555802f, 0.366065f);
float goldshininess= 0.4f;
// Traversing the bounding volume hierachies tree
Hit hit=traverseBvhTree(ray);
if (hit.t<0){ return lights[0].La;}
outRadiance+= gold_ka * lights[0].La;
Ray shadowRay;
shadowRay.orig = normalize(hit.orig) + normalize(hit.normal) * epsilon;
shadowRay.dir = normalize(lights[0].direction);
float cosTheta = dot(normalize(hit.normal), normalize(lights[0].direction));
// if the shadow ray intersects nothing, we add the emission coefficient of the light.
if (cosTheta>0 && shadowIntersect(shadowRay)==false) {
outRadiance +=lights[0].Le * gold_kd * cosTheta;
}
return outRadiance;
}
感谢任何帮助!
更新 1:
我根据codetiger的建议更新了代码,避免了归一化shadowray的原点,换了一种计算shadowray方向的方法。
Ray shadowRay;
shadowRay.dir = normalize(lights[0].position - hit.orig);
shadowRay.orig = hit.orig + shadowRay.dir * epsilon
以上更改为我提供了只有环境照明的立方体。
我还测试了以下几行:
if(shadowIntersect(shadowRay)==false){
return vec3(1,1,1);
}
return vec3(0,0,0);
而且这次整个对象都变黑了,所以问题应该也出在shadowIntersect方法上。
这里是完整的片段着色器:
#version 460 core
layout(std140, binding=0) buffer primitives{
vec4 primitiveCoordinates[];
};
struct FlatBvhNode
{
// base aligment aligned offset
vec4 min;// 16 byte 0
vec4 max;// 16 byte 16
int order;// 4 byte 32
int isLeaf;// 4 byte 36
int createdEmpty;// 4 byte 40
int leftOrRight;
vec4 indices[100];// 32 byte 48
};
layout(std430, binding=1) buffer TNodes
{
FlatBvhNode nodes[];
};
out vec4 FragColor;
in vec3 p;
uniform vec3 wEye;
struct Light{
vec3 Le, La;
vec3 direction;
vec3 position;
};
uniform Light lights[];
struct Ray{
vec3 orig, dir;
};
struct Hit{
vec3 orig, dir, normal;
float t;
};
Hit rayTriangleIntersect(Ray ray, vec3 v0, vec3 v1, vec3 v2){
Hit hit;
hit.t=-1;
float t; float u; float v;
vec3 v0v1 = v1 - v0;
vec3 v0v2 = v2 - v0;
vec3 pvec = cross(ray.dir, v0v2);
float det = dot(v0v1, pvec);
if (abs(det) < 0.0001){
hit.t=-1;
return hit;// Culling is off
}
float invDet = 1 / det;
vec3 tvec = ray.orig - v0;
u = dot(tvec, pvec) * invDet;
if (u < 0 || u > 1){
hit.t=-1;
return hit;
}
vec3 qvec = cross(tvec, v0v1);
v = dot(ray.dir, qvec) * invDet;
if (v < 0 || u + v > 1) {
hit.t=-1;
return hit;
}
hit.t = dot(v0v2, qvec) * invDet;
hit.normal=cross(v0v1, v0v2);
return hit;
}
vec4 getCoordinatefromIndices(float index){
return primitiveCoordinates[int(index)];
}
FlatBvhNode leftChild(FlatBvhNode node){
return nodes[2*node.order+1];
}
FlatBvhNode rightChild(FlatBvhNode node){
return nodes[2*node.order+2];
}
bool rayIntersectWithBox(vec4 boxMin, vec4 boxMax, Ray r) {
vec3 invdir = 1.0 / r.dir.xyz;
vec3 f = (boxMax.xyz - r.orig.xyz) * invdir;
vec3 n = (boxMin.xyz - r.orig.xyz) * invdir;
vec3 tmax = f * sign(invdir);
vec3 tmin = n * sign(invdir);
return tmin.x < tmax.x && tmin.y < tmax.y && tmin.z < tmax.z;
}
Hit traverseBvhNode(Ray ray, FlatBvhNode node){
Hit besthit;
besthit.t=-1;
bool hit;
Hit hitreal;
int i=0;
while (i<=nodes.length()) {
if (nodes[i].isLeaf==1){
for (int j=0;j<nodes[i].indices.length();j++){
if (mod(nodes[i].indices[j].x, 1)==0 && mod(nodes[i].indices[j].y, 1)==0 && mod(nodes[i].indices[j].z, 1)==0){
vec3 TrianglePointA=getCoordinatefromIndices(nodes[i].indices[j].x).xyz;
vec3 TrianglePointB=getCoordinatefromIndices(nodes[i].indices[j].y).xyz;
vec3 TrianglePointC=getCoordinatefromIndices(nodes[i].indices[j].z).xyz;
hitreal=rayTriangleIntersect(ray, TrianglePointA, TrianglePointB, TrianglePointC);
if (hitreal.t==-1){ continue; }
if (hitreal.t>0 && (besthit.t>hitreal.t || besthit.t<0)){
besthit=hitreal;
}
if(dot(ray.dir, besthit.normal)>0) besthit.normal = besthit.normal * (-1);
}
}
if (nodes[i].leftOrRight==0){
i=i+1;
continue;
}
else if (nodes[i].leftOrRight==1){
int id=int(ceil(i-2)/2);
FlatBvhNode parent=nodes[id];
while (parent.leftOrRight==1){
parent=nodes[int(ceil(parent.order-2)/2)];
if (parent.order==0){
return besthit;
}
}
i = parent.order+1;
continue;
}
}
hit = rayIntersectWithBox(nodes[i].min, nodes[i].max, ray);
if (hit) {
if (nodes[i].isLeaf==0){
i=2*i+1;
continue;
}
}
else {
if (nodes[i].order==0){
break;
}
if (nodes[i].leftOrRight==0) {
i=i+1;
continue;
}
else if (nodes[i].leftOrRight==1){
FlatBvhNode parent=nodes[int(ceil(i-2)/2)];
while (parent.leftOrRight==1){
parent=nodes[int(ceil(parent.order-2)/2)];
if (parent.order==0){
if (parent.order==0){
return besthit;
}
}
}
i = parent.order+1;
continue;
}
}
}
return besthit;
}
Hit traverseBvhTree(Ray ray){
return traverseBvhNode(ray, nodes[0]);
}
bool shadowIntersect(Ray ray1){ // for testing if the shadowray intersects something
for (int i;i<nodes.length();i++){
for (int j=0;j<nodes[i].indices.length();j++){
if (mod(nodes[i].indices[j].x, 1)==0 && mod(nodes[i].indices[j].y, 1)==0 && mod(nodes[i].indices[j].z, 1)==0){
vec3 TrianglePointA=getCoordinatefromIndices(nodes[i].indices[j].x).xyz;
vec3 TrianglePointB=getCoordinatefromIndices(nodes[i].indices[j].y).xyz;
vec3 TrianglePointC=getCoordinatefromIndices(nodes[i].indices[j].z).xyz;
if (rayTriangleIntersect(ray1, TrianglePointA, TrianglePointB, TrianglePointC).t>0){
return true;
}
}
}
}
return false;
}
vec3 trace(Ray ray){
const float epsilon = 0.0001f;
vec3 outRadiance = vec3(0, 0, 0);
vec3 gold_ka = vec3(0.44725f, 0.3995f, 0.2745f);
vec3 gold_kd = vec3 (40.75164f, 0.60648f, 0.22648f);
vec3 gold_ks = vec3 (0.628281f, 0.555802f, 0.366065f);
float goldshininess= 0.4f;
// Traversing the bounding volume hierachies tree
Hit hit=traverseBvhTree(ray);
if (hit.t<0){ return lights[0].La; }
outRadiance+= gold_ka * lights[0].La;
Ray shadowRay;
/*shadowRay.orig = hit.orig + normalize(hit.normal) * epsilon;
shadowRay.dir = normalize(lights[0].direction);*/
shadowRay.dir = normalize(lights[0].direction);
shadowRay.orig = hit.orig + shadowRay.dir * epsilon;
float cosTheta = dot(normalize(hit.normal), normalize(lights[0].direction));
// if the shadow ray intersects nothing, we add the emission coefficient of the light.
if (cosTheta>0 && shadowIntersect(shadowRay)==false) {
outRadiance +=lights[0].Le * gold_kd * cosTheta;
vec3 halfway = normalize(-normalize(ray.dir) + normalize(lights[0].direction));
float cosDelta = dot(normalize(hit.normal), halfway);
if (cosDelta > 0) outRadiance += lights[0].Le * gold_ks * pow(cosDelta, goldshininess);
}
return outRadiance;
}
void main()
{
Ray ray;
ray.orig = wEye;
ray.dir = normalize(p - wEye);
FragColor = vec4(trace(ray), 1);
// FragColor = vec4(nodes[4].isLeaf, 1, 1, 1);
}
我认为你的 shadowRay 配置有问题
Ray shadowRay;
shadowRay.dir = normalize(lights[0].position - hit.orig);
shadowRay.orig = hit.orig + shadowRay.dir * epsilon
假设阴影光线从交点和朝向光的方向开始。
问题是,我没有在光线相交算法中计算出相交的原点。
添加这一行解决了问题:
hit.orig=ray.orig+normalize(ray.dir)*hit.t;
我正在为多边形模型创建一个基于 OpenGL 的光线追踪器。基本结构是将结果从片段着色器渲染到四边形。为了加速应用程序,使用了 BVH 树。
问题是,该方法测试阴影光线是否与某物相交 return 为真,而不应 return 为真,这意味着根本没有阴影。只有立方体的两侧是黑色的,它们不面向光源。
这是一个屏幕截图,您可以在其中看到平面上的立方体。还有一个光源。
以下是片段着色器的有用部分:trace
和 shadowIntersect
方法:
bool shadowIntersect(Ray ray1){ // for testing if the shadowray intersects something
for (int i;i<nodes.length();i++){
for (int j=0;j<nodes[i].indices.length();j++){
if (mod(nodes[i].indices[j].x,1)==0 && mod(nodes[i].indices[j].y, 1)==0 && mod(nodes[i].indices[j].z, 1)==0){
vec3 TrianglePointA=getCoordinatefromIndices(nodes[i].indices[j].x).xyz;
vec3 TrianglePointB=getCoordinatefromIndices(nodes[i].indices[j].y).xyz;
vec3 TrianglePointC=getCoordinatefromIndices(nodes[i].indices[j].z).xyz;
Hit hit=rayTriangleIntersect(ray1, TrianglePointA, TrianglePointB, TrianglePointC);
if (hit.t>0){
return true;
}
}
}
}
return false;
}
vec3 trace(Ray ray){
const float epsilon = 0.0001f;
vec3 outRadiance = vec3(0, 0, 0);
vec3 gold_ka = vec3(0.24725f, 0.1995f, 0.0745f);
vec3 gold_kd = vec3 (40.75164f, 0.60648f, 0.22648f);
vec3 gold_ks = vec3 (0.628281f, 0.555802f, 0.366065f);
float goldshininess= 0.4f;
// Traversing the bounding volume hierachies tree
Hit hit=traverseBvhTree(ray);
if (hit.t<0){ return lights[0].La;}
outRadiance+= gold_ka * lights[0].La;
Ray shadowRay;
shadowRay.orig = normalize(hit.orig) + normalize(hit.normal) * epsilon;
shadowRay.dir = normalize(lights[0].direction);
float cosTheta = dot(normalize(hit.normal), normalize(lights[0].direction));
// if the shadow ray intersects nothing, we add the emission coefficient of the light.
if (cosTheta>0 && shadowIntersect(shadowRay)==false) {
outRadiance +=lights[0].Le * gold_kd * cosTheta;
}
return outRadiance;
}
感谢任何帮助!
更新 1:
我根据codetiger的建议更新了代码,避免了归一化shadowray的原点,换了一种计算shadowray方向的方法。
Ray shadowRay;
shadowRay.dir = normalize(lights[0].position - hit.orig);
shadowRay.orig = hit.orig + shadowRay.dir * epsilon
以上更改为我提供了只有环境照明的立方体。
我还测试了以下几行:
if(shadowIntersect(shadowRay)==false){
return vec3(1,1,1);
}
return vec3(0,0,0);
而且这次整个对象都变黑了,所以问题应该也出在shadowIntersect方法上。
这里是完整的片段着色器:
#version 460 core
layout(std140, binding=0) buffer primitives{
vec4 primitiveCoordinates[];
};
struct FlatBvhNode
{
// base aligment aligned offset
vec4 min;// 16 byte 0
vec4 max;// 16 byte 16
int order;// 4 byte 32
int isLeaf;// 4 byte 36
int createdEmpty;// 4 byte 40
int leftOrRight;
vec4 indices[100];// 32 byte 48
};
layout(std430, binding=1) buffer TNodes
{
FlatBvhNode nodes[];
};
out vec4 FragColor;
in vec3 p;
uniform vec3 wEye;
struct Light{
vec3 Le, La;
vec3 direction;
vec3 position;
};
uniform Light lights[];
struct Ray{
vec3 orig, dir;
};
struct Hit{
vec3 orig, dir, normal;
float t;
};
Hit rayTriangleIntersect(Ray ray, vec3 v0, vec3 v1, vec3 v2){
Hit hit;
hit.t=-1;
float t; float u; float v;
vec3 v0v1 = v1 - v0;
vec3 v0v2 = v2 - v0;
vec3 pvec = cross(ray.dir, v0v2);
float det = dot(v0v1, pvec);
if (abs(det) < 0.0001){
hit.t=-1;
return hit;// Culling is off
}
float invDet = 1 / det;
vec3 tvec = ray.orig - v0;
u = dot(tvec, pvec) * invDet;
if (u < 0 || u > 1){
hit.t=-1;
return hit;
}
vec3 qvec = cross(tvec, v0v1);
v = dot(ray.dir, qvec) * invDet;
if (v < 0 || u + v > 1) {
hit.t=-1;
return hit;
}
hit.t = dot(v0v2, qvec) * invDet;
hit.normal=cross(v0v1, v0v2);
return hit;
}
vec4 getCoordinatefromIndices(float index){
return primitiveCoordinates[int(index)];
}
FlatBvhNode leftChild(FlatBvhNode node){
return nodes[2*node.order+1];
}
FlatBvhNode rightChild(FlatBvhNode node){
return nodes[2*node.order+2];
}
bool rayIntersectWithBox(vec4 boxMin, vec4 boxMax, Ray r) {
vec3 invdir = 1.0 / r.dir.xyz;
vec3 f = (boxMax.xyz - r.orig.xyz) * invdir;
vec3 n = (boxMin.xyz - r.orig.xyz) * invdir;
vec3 tmax = f * sign(invdir);
vec3 tmin = n * sign(invdir);
return tmin.x < tmax.x && tmin.y < tmax.y && tmin.z < tmax.z;
}
Hit traverseBvhNode(Ray ray, FlatBvhNode node){
Hit besthit;
besthit.t=-1;
bool hit;
Hit hitreal;
int i=0;
while (i<=nodes.length()) {
if (nodes[i].isLeaf==1){
for (int j=0;j<nodes[i].indices.length();j++){
if (mod(nodes[i].indices[j].x, 1)==0 && mod(nodes[i].indices[j].y, 1)==0 && mod(nodes[i].indices[j].z, 1)==0){
vec3 TrianglePointA=getCoordinatefromIndices(nodes[i].indices[j].x).xyz;
vec3 TrianglePointB=getCoordinatefromIndices(nodes[i].indices[j].y).xyz;
vec3 TrianglePointC=getCoordinatefromIndices(nodes[i].indices[j].z).xyz;
hitreal=rayTriangleIntersect(ray, TrianglePointA, TrianglePointB, TrianglePointC);
if (hitreal.t==-1){ continue; }
if (hitreal.t>0 && (besthit.t>hitreal.t || besthit.t<0)){
besthit=hitreal;
}
if(dot(ray.dir, besthit.normal)>0) besthit.normal = besthit.normal * (-1);
}
}
if (nodes[i].leftOrRight==0){
i=i+1;
continue;
}
else if (nodes[i].leftOrRight==1){
int id=int(ceil(i-2)/2);
FlatBvhNode parent=nodes[id];
while (parent.leftOrRight==1){
parent=nodes[int(ceil(parent.order-2)/2)];
if (parent.order==0){
return besthit;
}
}
i = parent.order+1;
continue;
}
}
hit = rayIntersectWithBox(nodes[i].min, nodes[i].max, ray);
if (hit) {
if (nodes[i].isLeaf==0){
i=2*i+1;
continue;
}
}
else {
if (nodes[i].order==0){
break;
}
if (nodes[i].leftOrRight==0) {
i=i+1;
continue;
}
else if (nodes[i].leftOrRight==1){
FlatBvhNode parent=nodes[int(ceil(i-2)/2)];
while (parent.leftOrRight==1){
parent=nodes[int(ceil(parent.order-2)/2)];
if (parent.order==0){
if (parent.order==0){
return besthit;
}
}
}
i = parent.order+1;
continue;
}
}
}
return besthit;
}
Hit traverseBvhTree(Ray ray){
return traverseBvhNode(ray, nodes[0]);
}
bool shadowIntersect(Ray ray1){ // for testing if the shadowray intersects something
for (int i;i<nodes.length();i++){
for (int j=0;j<nodes[i].indices.length();j++){
if (mod(nodes[i].indices[j].x, 1)==0 && mod(nodes[i].indices[j].y, 1)==0 && mod(nodes[i].indices[j].z, 1)==0){
vec3 TrianglePointA=getCoordinatefromIndices(nodes[i].indices[j].x).xyz;
vec3 TrianglePointB=getCoordinatefromIndices(nodes[i].indices[j].y).xyz;
vec3 TrianglePointC=getCoordinatefromIndices(nodes[i].indices[j].z).xyz;
if (rayTriangleIntersect(ray1, TrianglePointA, TrianglePointB, TrianglePointC).t>0){
return true;
}
}
}
}
return false;
}
vec3 trace(Ray ray){
const float epsilon = 0.0001f;
vec3 outRadiance = vec3(0, 0, 0);
vec3 gold_ka = vec3(0.44725f, 0.3995f, 0.2745f);
vec3 gold_kd = vec3 (40.75164f, 0.60648f, 0.22648f);
vec3 gold_ks = vec3 (0.628281f, 0.555802f, 0.366065f);
float goldshininess= 0.4f;
// Traversing the bounding volume hierachies tree
Hit hit=traverseBvhTree(ray);
if (hit.t<0){ return lights[0].La; }
outRadiance+= gold_ka * lights[0].La;
Ray shadowRay;
/*shadowRay.orig = hit.orig + normalize(hit.normal) * epsilon;
shadowRay.dir = normalize(lights[0].direction);*/
shadowRay.dir = normalize(lights[0].direction);
shadowRay.orig = hit.orig + shadowRay.dir * epsilon;
float cosTheta = dot(normalize(hit.normal), normalize(lights[0].direction));
// if the shadow ray intersects nothing, we add the emission coefficient of the light.
if (cosTheta>0 && shadowIntersect(shadowRay)==false) {
outRadiance +=lights[0].Le * gold_kd * cosTheta;
vec3 halfway = normalize(-normalize(ray.dir) + normalize(lights[0].direction));
float cosDelta = dot(normalize(hit.normal), halfway);
if (cosDelta > 0) outRadiance += lights[0].Le * gold_ks * pow(cosDelta, goldshininess);
}
return outRadiance;
}
void main()
{
Ray ray;
ray.orig = wEye;
ray.dir = normalize(p - wEye);
FragColor = vec4(trace(ray), 1);
// FragColor = vec4(nodes[4].isLeaf, 1, 1, 1);
}
我认为你的 shadowRay 配置有问题
Ray shadowRay;
shadowRay.dir = normalize(lights[0].position - hit.orig);
shadowRay.orig = hit.orig + shadowRay.dir * epsilon
假设阴影光线从交点和朝向光的方向开始。
问题是,我没有在光线相交算法中计算出相交的原点。
添加这一行解决了问题:
hit.orig=ray.orig+normalize(ray.dir)*hit.t;