182 lines
4.9 KiB
C++
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;
|
|
}
|
|
//------------------------------------------------------------------------------
|