/* ----------------------------------------------------------------------------- GSFramework Copyright 2001-2013 Emmanuel Julien. All Rights Reserved. ----------------------------------------------------------------------------- */ #include #include "raytracer/raytracer_core.h" #include "core/camera.h" #include "core/geometry.h" #include "core/shader_block.h" #include "scene3d/scene.h" using namespace GS::Core; using namespace GS::Raytrace; //------------------------------------------------------------------------------ GS::Vector4 Raytracer::SampleMaterialSink(const Trace &trace, ShaderTree::ShaderSinkType sink) { if (trace.st) { // Evaluate sink. if (ShaderBlock *block = trace.st->sink[sink]) { ShaderBlockValue block_out; if (EvaluateShaderBlock(trace, block, block_out)) return block_out.v; } // Default values. switch (sink) { case ShaderTree::SinkNormal: return Vector4(0, 0, 1); case ShaderTree::SinkDiffuse: return trace.m->diffuse; case ShaderTree::SinkModulate: return Vector4(1, 1, 1); case ShaderTree::SinkSpecular: return trace.m->specular; case ShaderTree::SinkGlossiness: return Vector4(trace.m->glossiness, 0, 0); case ShaderTree::SinkConstant: return Vector4(0, 0, 0); case ShaderTree::SinkOpacity: return Vector4(1, 0, 0); case ShaderTree::SinkReflection: return Vector4(trace.m->reflection, 0, 0); } } return Vector4(1, 0, 0, 1); } GS::Vector4 Raytracer::SampleMaterialAttribute(const Trace &trace, MaterialChannel channel) { Color sample(1, 1, 1); if (!trace.m) return sample; Material::TextureStage *stage = trace.m->GetChannelStage(channel); /* Texture sampling. @TODO This is insanely slow. */ if (stage && trace.g) { float sample_uv_u = 0, sample_uv_v = 0; switch (stage->uv_mode) { case Material::UV_SphericalEnvironment: { Vector4 w; scene->current_camera->GetInverseMatrix().ApplyRotation(&w, &trace.n); // Find the Euler vector from the reflection normal. Vector4 euler_vec = trace.d - (w * 2.0f * fabs((w*-1.0f).Dot(trace.d))); euler_vec.Normalize(); // Euler to UV coordinate. // float Y = (1.0f - euler_vec.y) * 0.5f; Vector4 XZ(euler_vec.x, euler_vec.z, 0.0); XZ.Normalize(); float DotX = /*nVector(1.0f, 0.0f, 0.0f).Dot(XZ)*/XZ.x; // Set from -1;1 to 0;1. DotX = (1.0f - DotX) * 0.5f; float DotY = /*nVector(0.0f, 1.0f, 0.0f).Dot(XZ)*/XZ.y; // Set -1 or 1. DotY = (DotY >= 0 ? 1.0f :-1.0f); float value_angle = DotX * DotY; // Set from -1;1 to 0;1. value_angle = (1.0f - value_angle) * 0.5f; sample_uv_u = DotX; sample_uv_v = value_angle; } break; case Material::UV_LSN: { // Derive UV coordinates from intersection normal. Vector4 w; scene->current_camera->GetInverseMatrix().ApplyRotation(&w, &trace.n); sample_uv_u = w.x * 0.5f + 0.5f; sample_uv_v = w.y * 0.5f + 0.5f; } break; case Material::UV_FrontMap: { // Derive UV coordinated from view item projection matrix. Vector4 s; scene->current_camera->WorldToScreen(fRect(0, 0, viewport.x, viewport.y), trace.pi, s, false); float k_ar = viewport.y / viewport.x; sample_uv_u = (s.x - 0.5f) * k_ar + 0.5f; sample_uv_v = s.y; } break; case Material::UV_UV: // Compute UV from geometry topology. if (Vector2 *uv = (stage->uv_index < __UV_PER_GEOMETRY__) ? &trace.g->uv[stage->uv_index][0] : NULL) { Vector2 &uv0 = uv[trace.bi], &uv1 = uv[trace.bi + trace.it + 1], &uv2 = uv[trace.bi + trace.it + 2]; sample_uv_u = trace.w * uv0.x + trace.u * uv1.x + trace.v * uv2.x, sample_uv_v = trace.w * uv0.y + trace.u * uv1.y + trace.v * uv2.y; } break; } // UV matrix. Vector4 sample_uv = Vector4(sample_uv_u, sample_uv_v, 0.0) * stage->uv_matrix; // Handle wrapping. /* if (stage->wrap_u) { if (sample_uv.x < 0) sample_uv.x = sample_uv.x - (int)sample_uv.x + 1; else sample_uv.x = sample_uv.x - (int)sample_uv.x; } if (stage->wrap_v) { if (sample_uv.y < 0) sample_uv.y = sample_uv.y - (int)sample_uv.y + 1; else sample_uv.y = sample_uv.y - (int)sample_uv.y; } */ // FIXME performance bottleneck! if (Picture *p = gf->LoadPicture(stage->t)) p->SampleRGBA(sample_uv.x, sample_uv.y, sample); } else switch (channel) { case Channel_Diffuse: sample *= trace.m->diffuse; break; case Channel_Specular: sample *= trace.m->specular; break; case Channel_SelfIllum: sample *= trace.m->self; break; default: break; } return sample; } float Raytracer::SampleMaterialOpacity(const Trace &trace) { float opacity = 1.f; if (trace.m->GetChannelStage(Channel_Opacity)) { Vector4 sample = SampleMaterialAttribute(trace, Channel_Opacity); opacity = sample.w; } return opacity * trace.m->opacity; } //------------------------------------------------------------------------------