Я пишу трассировщик Sphere и обнаружил ошибку, когда мой шейдер превышает windows 'TDR и вылетает. Я подумал, что это может быть из-за моего интенсивного использования циклов, но меняю TdrDelay на 30 se c в реестре не помогло. Затем я попытался поместить тот же код в ShaderToy, и там он работает нормально (~ 7FPS) после длительного периода компиляции. Скопируйте, вставив этот точный код (и изменив основные методы и униформу по мере необходимости, чтобы они были совместимы с моим кодом) в моем приложении, компиляция занимает несколько секунд, а затем остается на 3FPS, пока TDR не закроет приложение. Chrome использует мой встроенный графический процессор (Intel UHD630), в то время как мое приложение использует мой выделенный NVidia 1650. При использовании моей карты Intel в моем приложении OpenGL просто прибегает к конвейеру с фиксированными функциями и ничего не делает с ограничением fps. Использование моей карты NVidia в shadertoy работает и отрисовывает быстрее ~ 25 кадров в секунду. Согласно glGetShaderInfo()
шейдер не выдает ошибок компиляции. В моем приложении вершинный шейдер просто создает четырехугольник, как и shaderToy. Я пробовал все, что мог придумать, и ничего не изменил, и я не мог найти похожие проблемы в Google. Эта проблема кажется мне очень странной, поскольку Shadertoy использует более базовую c версию OpenGL (WebGL), чем мое приложение, и работает на гораздо более слабом графическом процессоре. По этим двум причинам я не думаю, что мое приложение зависает из-за ограничений вычислений. Любая помощь будет принята с благодарностью. Если потребуется дополнительная информация, я могу ее добавить.
Фрагментный шейдер:
#version 400 core
in vec2 uvPos;
in vec4 backColor;
out vec4 outColor;
uniform vec2 iResolution = vec2(1536, 864);
uniform int MAX_AA = 50;
uniform int MAX_MARCH = 100;
uniform float MAX_DIST = 20.0;
#define OBJ_COUNT 2
#define FLT_MAX 3.402823466e+38
uint hash(uint x){
x+=(x<<10u);
x^=(x>>6u);
x+=(x<<3u);
x^=(x>>11u);
x+=(x<<15u);
return x;
}
uint hash(uvec2 v){return hash(v.x^hash(v.y));}
uint hash(uvec3 v){return hash( v.x ^ hash(v.y) ^ hash(v.z));}
uint hash(uvec4 v){return hash( v.x ^ hash(v.y) ^ hash(v.z) ^ hash(v.w));}
float floatConstruct(uint m){
const uint ieeeMantissa = 0x007FFFFFu;
const uint ieeeOne = 0x3F800000u;
m &= ieeeMantissa;
m |= ieeeOne;
return uintBitsToFloat(m) - 1.0;
}
float randf(float x){return floatConstruct(hash(floatBitsToUint(x)));}
float randf(int x){return randf(float(x));}
float randf(vec2 v){return floatConstruct(hash(floatBitsToUint(v)));}
float randf(vec3 v){return floatConstruct(hash(floatBitsToUint(v)));}
float randf(vec4 v){return floatConstruct(hash(floatBitsToUint(v)));}
//random: range [0, 1]
int randIterator = 0;
vec3 randomOnBall(){
vec3 p;
do{
p = vec3(randf(randIterator++)*2+1,
randf(randIterator++)*2+1,
randf(randIterator++)*2+1);
}while(length(p) > 1.0);
return p;
}
struct Material{
int type;
vec3 albedo;
};
struct Object{
int type;
vec3 c;
float r;
vec3 size;
Material mat;
};
struct Scene{
Object objects[OBJ_COUNT];
};
struct HitRecord{
vec3 p;
vec3 n;
Object o;
Material m;
};
struct Ray {
vec3 o;
vec3 d;
};
float sphereSDF(Object o, vec3 p){
return length(p-o.c)-o.r;
}
float boxSDF(Object o, vec3 p){
vec3 q = abs(p-o.c) - o.size;
return (length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0));
}
float sceneSDF(vec3 p, Scene s){
float dist = FLT_MAX;
for(int i = 0; i < OBJ_COUNT; i++){
switch(s.objects[i].type){
case 1:
dist = min(dist, sphereSDF(s.objects[i], p));
break;
case 2:
dist = min(dist, boxSDF(s.objects[i], p));
break;
}
}
return dist;
}
float sceneSDF(vec3 p, Scene s, inout HitRecord rec){
float dist = FLT_MAX;
for(int i = 0; i < OBJ_COUNT; i++){
float tmpDist = FLT_MAX;
switch(s.objects[i].type){
case 1:
tmpDist = sphereSDF(s.objects[i], p);
break;
case 2:
tmpDist = boxSDF(s.objects[i], p);
break;
}
if(tmpDist < dist){
dist = tmpDist;
rec.o = s.objects[i];
rec.m = s.objects[i].mat;
}
}
return dist;
}
Ray getRay(vec2 uv){
const vec3 lookFrom = vec3(0.0, 0.0, 2.0);
const vec3 lookAt = vec3(0.0, 0.0, 0.0);
const vec3 viewUp = vec3(0.0, 1.0, 0.0);
const float verticalFOV = 90.0;
float aspect = float(iResolution.x)/float(iResolution.y);
vec3 u, v, w;
float theta = radians(verticalFOV);
float halfHeight = tan(theta/2.0);
float halfWidth = aspect*halfHeight;
vec3 origin = lookFrom;
w = normalize(lookFrom-lookAt);
u = normalize(cross(viewUp, w));
v = cross(w, u);
vec3 lowerLeftCorner = origin-u*halfWidth-v*halfHeight-w;
vec3 hor = u*2.0*halfWidth;
vec3 ver = v*2.0*halfHeight;
return Ray(origin, normalize(lowerLeftCorner-origin+hor*uv.x+ver*uv.y));
}
vec3 calcNormal(vec3 p, Scene s){
#if 0
const float eps = 0.0001; // or some other value
const vec2 h = vec2(eps,0);
return normalize( vec3(sceneSDF(p+h.xyy, s) - sceneSDF(p-h.xyy, s),
sceneSDF(p+h.yxy, s) - sceneSDF(p-h.yxy, s),
sceneSDF(p+h.yyx, s) - sceneSDF(p-h.yyx, s) ) );
#else //From Inigo Quilez https://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm
const float h = 0.0001; // replace by an appropriate value
const vec2 k = vec2(1,-1);
return normalize( k.xyy*sceneSDF( p + k.xyy*h, s ) +
k.yyx*sceneSDF( p + k.yyx*h, s ) +
k.yxy*sceneSDF( p + k.yxy*h, s ) +
k.xxx*sceneSDF( p + k.xxx*h, s ) );
#endif
}
float findSceneIntersect(Ray r, Scene s, inout HitRecord rec){
float t = 0.005;
vec3 p;
for(int i = 0; i < 100; i++){
p = r.o+r.d*t;
float dist = sceneSDF(p, s, rec);
if(dist < 0.001){
rec.n = calcNormal(p, s);
rec.p = p;
return t;
}else{
t+=dist;
if(t >= MAX_DIST)
return -1.0;
}
}
return -1.0;
}
bool scatter(inout Ray r, HitRecord rec, inout vec3 tmpAtt){
tmpAtt = rec.m.albedo;
r = Ray(rec.p, rec.n+randomOnBall());
return true;
}
vec3 calcColor(Ray ray, Scene s){
HitRecord rec = HitRecord(vec3(0.0), vec3(0.0), Object(0, vec3(0.0), 0.0, vec3(0.0), Material(1, vec3(0.0))), Material(1, vec3(0.0)));
vec3 color = vec3(0);
float t = findSceneIntersect(ray, s, rec);
int reflections = 0;
vec3 att = vec3(1.0);
for(int ref = 0; ref < 50; ref++){
if(t != -1.0){
vec3 tmpAtt = vec3(0.0);
if(scatter(ray, rec, tmpAtt)){
att *= tmpAtt;
t = findSceneIntersect(ray, s, rec);
reflections++;
}else{
att *= tmpAtt;
t = -1.0;
}
}else{
color = mix(vec3(1.0), vec3(0.5, 0.7, 1.0), ray.d.y*0.5+0.5)*att;
break;
}
}
return color;
}
Scene scene = Scene(Object[OBJ_COUNT](
Object(1, vec3(0.0, 0.5, 0.0), 1.0, vec3(0.0), Material(1, vec3(0.5))),
Object(1, vec3(0.0, -100.5, 0.0), 100.0, vec3(0.0), Material(1, vec3(0.5)))
));
void main(void){
HitRecord rec = HitRecord(vec3(0.0), vec3(0.0), Object(0, vec3(0.0), 0.0, vec3(0.0), Material(1, vec3(0.0))), Material(1, vec3(0.0)));
#if 1
const int AA = 50;
vec3 color = vec3(0.0);
for(int s = 0; s < AA; s++){
vec2 xy = uvPos * iResolution;
vec2 uv = (xy+vec2(randf(randIterator++)*2.0-1.0, randf(randIterator++)*2.0-1.0))/iResolution.xy;
color += calcColor(getRay(uv), scene);
}
outColor = vec4(color/float(AA), 1.0);
#else
vec2 uv = uvPos;
Ray ray = getRay(uv);
float t = findSceneIntersect(ray, scene, rec);
if(t == -1.0){
outColor = vec4(mix(vec3(1.0), vec3(0.5, 0.7, 1.0), uv.y), 1.0);
}else
outColor = vec4(rec.n*0.5+0.5, 1.0);
#endif
outColor.xyz = pow(outColor.xyz, vec3(1.0/2.2));
}
Вершинный шейдер: (отображает четырехугольник)
#version 400 core
in vec3 position;
out vec2 uvPos;
out vec4 backColor;
void main(void){
gl_Position = vec4(position, 1.0);
uvPos = position.xy*0.5+0.5;
backColor = mix(vec4(1, 1, 1, 1), vec4(0.5, 0.7, 1, 1), uvPos.y);
}
Код загрузки шейдера (LWJGL):
private static int loadShader(String file, int type) {
System.out.println("Loading shader at path: " + file);
StringBuilder shaderSource = new StringBuilder();
try{
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine())!=null){
shaderSource.append(line).append("//\n");
}
reader.close();
}catch(IOException e){
e.printStackTrace();
System.exit(-1);
}
int shaderID = glCreateShader(type);
glShaderSource(shaderID, shaderSource);
glCompileShader(shaderID);
System.out.println(glGetShaderInfoLog(shaderID, 1000)); //Returns empty string --> no compile error
if(glGetShaderi(shaderID, GL_COMPILE_STATUS )== GL_FALSE){
System.out.println(glGetShaderInfoLog(shaderID, 500));
System.err.println("Could not compile shader!");
System.exit(-1);
}
return shaderID;
}