297 lines
8.2 KiB
C++
297 lines
8.2 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#include <cmath>
|
|
#include "raytracer/raytracer_core.h"
|
|
#include "core/shader_block.h"
|
|
#include "core/geometry.h"
|
|
#include "core/object.h"
|
|
|
|
using namespace GS::Core;
|
|
using namespace GS::Raytrace;
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool Raytracer::EvaluateShaderBlock(const Trace &trace, const ShaderBlock *block, ShaderBlockValue &out)
|
|
{
|
|
ShaderBlockValue in[4]; // No more than 4 inputs supported.
|
|
|
|
// Validity check.
|
|
if (!block)
|
|
return true;
|
|
|
|
// Evaluate inputs.
|
|
for (uint n = 0; n < block->GetInputCount(); ++n)
|
|
if (!EvaluateShaderBlock(trace, block->GetInput(n), in[n]))
|
|
return false;
|
|
|
|
// Evaluate block.
|
|
switch (block->type)
|
|
{
|
|
case ShaderBlock::TypeGeometryVertex:
|
|
out.Set(trace.pi * trace.o->GetInverseMatrix());
|
|
break;
|
|
|
|
case ShaderBlock::TypeGeometryNormal:
|
|
if (Vector4 *nrm = trace.g->vtx_normal)
|
|
{
|
|
Vector4 &nm0 = nrm[trace.bi],
|
|
&nm1 = nrm[trace.bi + trace.it + 1],
|
|
&nm2 = nrm[trace.bi + trace.it + 2];
|
|
|
|
out.Set(nm0 * trace.w + nm1 * trace.u + nm2 * trace.v);
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeGeometryVertexColor:
|
|
if (Vector4 *rgb = trace.g->rgb)
|
|
{
|
|
Vector4 &cl0 = rgb[trace.bi],
|
|
&cl1 = rgb[trace.bi + trace.it + 1],
|
|
&cl2 = rgb[trace.bi + trace.it + 2];
|
|
|
|
out.Set(cl0 * trace.w + cl1 * trace.u + cl2 * trace.v);
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeGeometryUV:
|
|
{
|
|
GeometryUVShaderBlock *b = (GeometryUVShaderBlock *)block;
|
|
|
|
if (Vector2 *uv = trace.g->uv[b->channel])
|
|
{
|
|
Vector2 &uv0 = uv[trace.bi],
|
|
&uv1 = uv[trace.bi + trace.it + 1],
|
|
&uv2 = uv[trace.bi + trace.it + 2];
|
|
|
|
out.Set(Vector4(trace.w * uv0.x + trace.u * uv1.x + trace.v * uv2.x, trace.w * uv0.y + trace.u * uv1.y + trace.v * uv2.y, 0, 0));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeGeometrySkinning:
|
|
break;
|
|
case ShaderBlock::TypeGeometryTangentFrame:
|
|
{
|
|
Vector4 sample = ( trace.g->vtx_normal[trace.bi] * trace.w +
|
|
trace.g->vtx_normal[trace.bi + trace.it + 1] * trace.u +
|
|
trace.g->vtx_normal[trace.bi + trace.it + 2] * trace.v ).Normalized();
|
|
|
|
Vector4 T, B;
|
|
|
|
if (trace.g->vtx_tangent)
|
|
{
|
|
// Interpolated tangent basis.
|
|
T = (trace.g->vtx_tangent[trace.bi + 0].T * trace.w +
|
|
trace.g->vtx_tangent[trace.bi + trace.it + 1].T * trace.u +
|
|
trace.g->vtx_tangent[trace.bi + trace.it + 2].T * trace.v ).Normalized();
|
|
B = (trace.g->vtx_tangent[trace.bi + 0].B * trace.w +
|
|
trace.g->vtx_tangent[trace.bi + trace.it + 1].B * trace.u +
|
|
trace.g->vtx_tangent[trace.bi + trace.it + 2].B * trace.v ).Normalized();
|
|
}
|
|
else
|
|
{
|
|
T.Set(1, 0, 0);
|
|
B.Set(0, 1, 0);
|
|
}
|
|
|
|
// Build tangent frame.
|
|
Matrix3 tangent_matrix(T, B, sample);
|
|
out.Set(tangent_matrix);
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeTexture:
|
|
out.Set(((TextureShaderBlock *)block)->texture);
|
|
break;
|
|
|
|
case ShaderBlock::TypeTextureSampler:
|
|
{
|
|
if (in[0].t)
|
|
{
|
|
Color sample;
|
|
if (Picture *p = gf->LoadPicture(in[0].t))
|
|
p->SampleRGBA(in[1].v.x < 0 ? 1 + fmodf(in[1].v.x, 1) : fmodf(in[1].v.x, 1), in[1].v.y < 0 ? 1 + fmodf(in[1].v.y, 1) : fmodf(in[1].v.y, 1), sample);
|
|
out.Set(sample);
|
|
}
|
|
else
|
|
out.Set(Vector4(0, 0, 0));
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeConstant:
|
|
{
|
|
ConstantShaderBlock *b = (ConstantShaderBlock *)block;
|
|
out.Set(Vector4(b->constant[0], b->constant[1], b->constant[2], b->constant[3]));
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeColor:
|
|
{
|
|
ColorShaderBlock *b = (ColorShaderBlock *)block;
|
|
out.Set(b->color);
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeMaterialParam:
|
|
{
|
|
MaterialParamShaderBlock *b = (MaterialParamShaderBlock *)block;
|
|
switch (b->param)
|
|
{
|
|
case MaterialParamShaderBlock::MaterialAmbient:
|
|
out.Set(trace.m->ambient);
|
|
break;
|
|
case MaterialParamShaderBlock::MaterialDiffuse:
|
|
out.Set(trace.m->diffuse);
|
|
break;
|
|
case MaterialParamShaderBlock::MaterialSpecular:
|
|
out.Set(trace.m->specular);
|
|
break;
|
|
case MaterialParamShaderBlock::MaterialSelf:
|
|
out.Set(trace.m->self);
|
|
break;
|
|
case MaterialParamShaderBlock::MaterialGlossiness:
|
|
out.Set(trace.m->glossiness);
|
|
break;
|
|
case MaterialParamShaderBlock::MaterialOpacity:
|
|
out.Set(trace.m->opacity);
|
|
break;
|
|
case MaterialParamShaderBlock::MaterialReflection:
|
|
out.Set(trace.m->reflection);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeScreenUV:
|
|
out.Set(Vector4(0.5f,0.5f,0.5f));
|
|
break;
|
|
case ShaderBlock::TypeViewVector:
|
|
out.Set(trace.d);
|
|
break;
|
|
|
|
case ShaderBlock::TypeNormalViewMatrix:
|
|
out.Set(Matrix3::FromOrthonormalBasis(trace.d).Transposed() * trace.o->GetRotationMatrix());
|
|
break;
|
|
case ShaderBlock::TypeNormalMatrix:
|
|
out.Set(trace.o->GetRotationMatrix());
|
|
break;
|
|
case ShaderBlock::TypeModelViewMatrix:
|
|
{
|
|
Matrix4 view_matrix = Matrix4::FromMatrix3(Matrix3::FromOrthonormalBasis(trace.d).Transposed());
|
|
view_matrix.SetRow(3, trace.s.Reversed());
|
|
out.Set(view_matrix * trace.o->GetMatrix());
|
|
}
|
|
break;
|
|
case ShaderBlock::TypeModelMatrix:
|
|
out.Set(trace.o->GetMatrix());
|
|
break;
|
|
|
|
case ShaderBlock::TypeMix: out.Set(in[0].v * in[2].v.x + in[1].v * (1 - in[2].v.x)); break;
|
|
case ShaderBlock::TypeAdd: out.Set(in[0].v + in[1].v); break;
|
|
case ShaderBlock::TypeMul:
|
|
{
|
|
if (in[0].type == in[1].type)
|
|
switch (in[0].type)
|
|
{
|
|
case ShaderBlockValue::BlockValueVector: out.Set(in[0].v * in[1].v); break;
|
|
case ShaderBlockValue::BlockValueMatrix3: out.Set(in[0].m3 * in[1].m3); break;
|
|
case ShaderBlockValue::BlockValueMatrix4: out.Set(in[0].m4 * in[1].m4); break;
|
|
}
|
|
else
|
|
{
|
|
ShaderBlockValue *_a = &in[0], *_b = &in[1];
|
|
if (_b->type < _a->type)
|
|
{ ShaderBlockValue *tmp = _a; _a = _b; _b = tmp; }
|
|
|
|
if (_a->type == ShaderBlockValue::BlockValueVector)
|
|
{
|
|
if (_b->type == ShaderBlockValue::BlockValueMatrix3)
|
|
out.Set(_a->v * _b->m3);
|
|
else if (_b->type == ShaderBlockValue::BlockValueMatrix4)
|
|
out.Set(_a->v * _b->m4);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeSub: out.Set(in[0].v - in[1].v); break;
|
|
case ShaderBlock::TypeDiv: out.Set(in[0].v / in[1].v); break;
|
|
|
|
case ShaderBlock::TypeDot: out.Set(in[0].v.Dot(in[1].v)); break;
|
|
case ShaderBlock::TypeCross: out.Set(in[0].v.Cross(in[1].v)); break;
|
|
|
|
case ShaderBlock::TypeClamp:
|
|
out.Set(Vector4(
|
|
Types::Clamp(in[0].v.x, in[1].v.x, in[2].v.x),
|
|
Types::Clamp(in[0].v.y, in[1].v.y, in[2].v.y),
|
|
Types::Clamp(in[0].v.z, in[1].v.z, in[2].v.z),
|
|
Types::Clamp(in[0].v.w, in[1].v.w, in[2].v.w) ) );
|
|
break;
|
|
|
|
case ShaderBlock::TypeNormalize: out.Set(in[0].v.Normalized()); break;
|
|
|
|
case ShaderBlock::TypeSwizzle:
|
|
{
|
|
SwizzleShaderBlock *b = (SwizzleShaderBlock *)block;
|
|
|
|
Vector4 v(0, 0, 0);
|
|
for (int n = 0; n < 4; ++n)
|
|
if (b->swizzle[n] != SwizzleShaderBlock::SwizzleNone)
|
|
v[n] = in[0].v[b->swizzle[n] - SwizzleShaderBlock::SwizzleX];
|
|
|
|
out.Set(v);
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeBuild:
|
|
{
|
|
BuildShaderBlock *b = (BuildShaderBlock *)block;
|
|
|
|
Vector4 v(0, 0, 0);
|
|
for (int n = 0; n < 4; ++n)
|
|
{
|
|
if (b->build[n] == BuildShaderBlock::BuildOne)
|
|
v[n] = 1;
|
|
else if (b->build[n] == BuildShaderBlock::BuildZero)
|
|
v[n] = 0;
|
|
else v[n] = in[n].v[b->build[n] - BuildShaderBlock::BuildX];
|
|
}
|
|
|
|
out.Set(v);
|
|
}
|
|
break;
|
|
|
|
case ShaderBlock::TypeSin: out.Set(sin(in[0].v.x)); break;
|
|
case ShaderBlock::TypeCos: out.Set(cos(in[0].v.x)); break;
|
|
|
|
case ShaderBlock::TypeUnpackColorToVector:
|
|
out.Set((in[0].v - Vector4(0.5, 0.5, 0.0)) * Vector4(2.0, 2.0, 1.0));
|
|
break;
|
|
case ShaderBlock::TypePackVectorToColor:
|
|
out.Set((in[0].v + Vector4(1.0, 1.0, 0.0)) * Vector4(0.5, 0.5, 1.0));
|
|
break;
|
|
|
|
case ShaderBlock::TypeClock:
|
|
out.Set(render_clock);
|
|
break;
|
|
|
|
case ShaderBlock::TypePow:
|
|
out.Set(float(pow(in[0].v.x, in[1].v.x)));
|
|
break;
|
|
|
|
case ShaderBlock::TypeAbs:
|
|
if (in[0].type == ShaderBlockValue::BlockValueVector)
|
|
{
|
|
Vector4 o = in[0].v.Abs();
|
|
out.Set(Vector4(o.x, o.y, o.z));
|
|
}
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
//------------------------------------------------------------------------------
|