Files
Webcam/include/modules/raytracer/raytracer_material.cpp

182 lines
4.9 KiB
C++

/* -----------------------------------------------------------------------------
GSFramework
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */
#include <math.h>
#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;
}
//------------------------------------------------------------------------------