commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
748
include/modules/raytracer/raytracer_core.cpp
Normal file
748
include/modules/raytracer/raytracer_core.cpp
Normal file
@ -0,0 +1,748 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "raytracer/raytracer_core.h"
|
||||
#include "raytracer/raytracer_job.h"
|
||||
#include "scene3d/mobject.h"
|
||||
#include "scene3d/mlight.h"
|
||||
#include "scene3d/mcamera.h"
|
||||
#include "scene3d/scene.h"
|
||||
#include "rand/rand.h"
|
||||
#include "platform.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::Core;
|
||||
using namespace GS::Raytrace;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float Raytracer::Fresnel(const Vector4 &v, const Vector4 &np, float eta)
|
||||
{
|
||||
float const r0 = Math::Pow(1.0f - eta, 2.0f) / Math::Pow(1.0f + eta, 2.0f);
|
||||
// Light vector and normal are assumed to be normalized.
|
||||
return Types::Clamp <float> (r0 + (1.0f - r0) * Math::Pow(1 - Types::Abs(v.Dot(np)), 5.0f), 0.0f, 1.0f);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
float Raytracer::ShadowFeel(const Vector4 &s, const Vector4 &d, float l, int r)
|
||||
{
|
||||
float k_shadow = 1;
|
||||
|
||||
if (configuration.trace_transparency)
|
||||
{
|
||||
if (!r)
|
||||
return k_shadow;
|
||||
|
||||
// Get closest hit.
|
||||
Trace trace;
|
||||
scene_shadow_tree.RaytraceScene(trace, s, d, l);
|
||||
statistics.ray_count++;
|
||||
statistics.tri_test += trace.tri_test;
|
||||
|
||||
if (trace.has_i && (trace.i_t > 0))
|
||||
{
|
||||
// Check opacity.
|
||||
float opacity = SampleMaterialOpacity(trace);
|
||||
|
||||
// Early exit on fully opaque hit.
|
||||
if (opacity == 1)
|
||||
return 0;
|
||||
k_shadow = 1 - opacity;
|
||||
|
||||
// Recurse.
|
||||
Vector4 offset_pi = trace.s + trace.d * (trace.i_t + Units::Mm(1));
|
||||
k_shadow *= ShadowFeel(offset_pi, trace.d, l - Vector4::Dist(trace.s, offset_pi), --r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Any hit within range will do.
|
||||
Trace trace(false);
|
||||
scene_shadow_tree.RaytraceScene(trace, s, d, l);
|
||||
|
||||
if (trace.has_i && (trace.i_t > 0))
|
||||
return 0; // Occluded.
|
||||
}
|
||||
|
||||
return k_shadow;
|
||||
}
|
||||
void Raytracer::ComputeRadiance(Trace &trace, Color &o, Bounce &bounce)
|
||||
{
|
||||
bool use_fixed_function = trace.m->shader.IsEmpty();
|
||||
bool blend_additive = trace.m->blendop == Material::Blend_Add;
|
||||
|
||||
// Evaluate material alpha.
|
||||
float alpha;
|
||||
if (use_fixed_function)
|
||||
alpha = SampleMaterialOpacity(trace);
|
||||
else alpha = SampleMaterialSink(trace, ShaderTree::SinkOpacity).x;
|
||||
alpha *= trace.o->opacity;
|
||||
|
||||
// Compute direct lighting, if the material does not care about the alpha test, or if the material cares about it and its alpha is up to the threshold.
|
||||
if (!(trace.m->renderword & Material::Render_AlphaTest) || alpha > trace.m->athreshold)
|
||||
{
|
||||
// Evaluate material glossiness.
|
||||
float glossiness;
|
||||
if (use_fixed_function)
|
||||
glossiness = trace.m->glossiness;
|
||||
else glossiness = SampleMaterialSink(trace, ShaderTree::SinkGlossiness).x;
|
||||
|
||||
// Evaluate light contribution.
|
||||
Color l_diff(0, 0, 0), l_spec(0, 0, 0);
|
||||
Vector4 offset_pi = trace.pi + trace.n * Units::Mm(1.f);
|
||||
|
||||
for (uint n = 0; n < lgt.GetCount(); ++n)
|
||||
if (S3D::MLight *l = lgt[n].l)
|
||||
{
|
||||
Core::Light *light = (Core::Light *)l;
|
||||
float k_shadow = 1.f;
|
||||
|
||||
if ((light->shadow != Core::Light::Shadow_None) && configuration.trace_shadow)
|
||||
{
|
||||
Vector4 d;
|
||||
|
||||
switch (light->model)
|
||||
{
|
||||
default:
|
||||
case Core::Light::Model_Point:
|
||||
d = light->GetMatrix().GetRow(3) - offset_pi;
|
||||
break;
|
||||
|
||||
case Core::Light::Model_Linear:
|
||||
d = light->GetMatrix().GetRow(2).Reversed() * light->clip_distance;
|
||||
break;
|
||||
}
|
||||
|
||||
if (d.Dot(trace.n) > 0)
|
||||
{
|
||||
float l = d.Len();
|
||||
d /= l;
|
||||
|
||||
k_shadow = ShadowFeel(offset_pi, d, l, configuration.trace_shadow_transparency_max_recursion);
|
||||
if (!k_shadow)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute contribution.
|
||||
float k_d, k_s;
|
||||
if (light->SampleEnergy(trace.pi, trace.n, &k_d, &k_s, &trace.d, glossiness))
|
||||
{
|
||||
l_diff += light->diffuse_color * light->diffuse_intensity * k_d * k_shadow;
|
||||
l_spec += light->specular_color * light->specular_intensity * k_s * k_shadow;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute indirect lighting.
|
||||
Color l_indirect(0, 0, 0), ambient(0, 0, 0);
|
||||
|
||||
if (configuration.trace_gi && bounce.indirect)
|
||||
{
|
||||
bounce.indirect--;
|
||||
|
||||
Spread &mc = monte_carlo[Random::Rand(32)];
|
||||
Matrix3 nm(Matrix3::FromOrthonormalBasis(trace.n));
|
||||
Color l;
|
||||
|
||||
// divide by the number of bounce, to avoid full bounce each time.
|
||||
int count_spread = mc.spread.GetCount();
|
||||
if (configuration.indirect_gi_bounce - bounce.indirect != 0)
|
||||
count_spread /= configuration.indirect_gi_bounce - bounce.indirect + 1;
|
||||
count_spread = Types::Max(count_spread, 1);
|
||||
|
||||
for (int n = 0; n < count_spread; ++n)
|
||||
{
|
||||
Bounce ibounce;
|
||||
|
||||
ibounce.indirect = bounce.indirect;
|
||||
ibounce.reflection = 0;
|
||||
ibounce.refraction = 0;
|
||||
|
||||
Raytrace(RayGrid(offset_pi, mc.spread[n] * nm), l, ibounce);
|
||||
l_indirect += l;
|
||||
}
|
||||
l_indirect /= (float)count_spread;
|
||||
}
|
||||
else
|
||||
ambient = (configuration.gi_use_ambient || !configuration.trace_gi) ? scene->ambient_color * scene->ambient_intensity : Vector4(0.f, 0.f, 0.f);
|
||||
|
||||
// Compute ambient occlusion.
|
||||
float ambient_occlusion = 1.0f;
|
||||
|
||||
if ((alpha >= 1.0f) && configuration.ao_activate)
|
||||
{
|
||||
Spread &mc = monte_carlo[Random::Rand(32)];
|
||||
Matrix3 nm(Matrix3::FromOrthonormalBasis(trace.n));
|
||||
|
||||
float countouch = 0.0f;
|
||||
float lengthmax = configuration.ao_length;
|
||||
float divlengthmaxsq = 1.0f / lengthmax;
|
||||
|
||||
for (uint n = 0; n < mc.spread.GetCount(); ++n)
|
||||
{
|
||||
// Create the direction vector from the normal of the point with a bit of random.
|
||||
Trace traceOcclusion;
|
||||
Vector4 start(trace.pi + mc.spread[n] * nm * Units::Mm(1.f));
|
||||
/*
|
||||
nVector DirVect(mc.spread[n] * nm);
|
||||
scene_tree.RaytraceScene(traceOcclusion, start, DirVect, lengthmax);
|
||||
|
||||
// check the raytrace pass if the alpha of the map and continue to raytrace then
|
||||
float alphaOcclusion = 0.0f;
|
||||
float current_length = 0.0f;
|
||||
|
||||
while(alphaOcclusion < 1.0f && current_length < lengthmax &&
|
||||
traceOcclusion.has_i && (traceOcclusion.i_t > 0.0f))
|
||||
{
|
||||
current_length += traceOcclusion.i_t;
|
||||
|
||||
// Compute intersection point and fetch material.
|
||||
traceOcclusion.pi = traceOcclusion.s + traceOcclusion.d * traceOcclusion.i_t;
|
||||
traceOcclusion.m = traceOcclusion.g->material_table[traceOcclusion.g->pol[traceOcclusion.ip].material];
|
||||
|
||||
bool use_fixed_functionOcclusion = trace.m->shader_tree == NULL ? true : false;
|
||||
|
||||
// Evaluate material alpha.
|
||||
float TempAlphaOcclusion = 0.0f;
|
||||
|
||||
if (use_fixed_functionOcclusion)
|
||||
TempAlphaOcclusion = SampleMaterialOpacity(traceOcclusion);
|
||||
else TempAlphaOcclusion = SampleMaterialSink(traceOcclusion, nShaderTree::SinkOpacity).x;
|
||||
alphaOcclusion += TempAlphaOcclusion*traceOcclusion.o->opacity;
|
||||
|
||||
if(alphaOcclusion < 1.0f && current_length < lengthmax)
|
||||
scene_tree.RaytraceScene(traceOcclusion, traceOcclusion.pi + DirVect* Mm(1), DirVect, lengthmax - current_length);
|
||||
}
|
||||
|
||||
if(alphaOcclusion > 1.0f)
|
||||
alphaOcclusion = 1.0f;
|
||||
|
||||
if (alphaOcclusion > 0)
|
||||
countouch += (1.0f - Types::Clamp(current_length * divlengthmaxsq, 0.0f, 1.0f))* alphaOcclusion;
|
||||
*/
|
||||
scene_tree.RaytraceScene(traceOcclusion, start, mc.spread[n] * nm, lengthmax);
|
||||
|
||||
if (traceOcclusion.has_i && (traceOcclusion.i_t > 0.0f))
|
||||
countouch += 1.0f - Types::Clamp(traceOcclusion.i_t * divlengthmaxsq, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
if (countouch > 0.0f)
|
||||
ambient_occlusion = 1.0f - countouch / mc.spread.GetCount();
|
||||
ambient_occlusion = Types::Clamp(ambient_occlusion);
|
||||
}
|
||||
|
||||
// Sample attributes.
|
||||
Color diffuse, specular, self;
|
||||
|
||||
if (use_fixed_function)
|
||||
{
|
||||
// Gather attributes.
|
||||
diffuse = SampleMaterialAttribute(trace, Channel_Diffuse);
|
||||
specular = SampleMaterialAttribute(trace, Channel_Specular);
|
||||
self = SampleMaterialAttribute(trace, Channel_SelfIllum);
|
||||
|
||||
// Vertex color.
|
||||
if (trace.m->GetChannelStage(Channel_Light))
|
||||
{
|
||||
Color color = SampleMaterialAttribute(trace, Channel_Light);
|
||||
diffuse *= color;
|
||||
specular *= color;
|
||||
}
|
||||
else if (trace.m->renderword & Material::Render_VertexColor)
|
||||
{
|
||||
Color color = SampleGeometryAttribute(trace, GeometryVertexColor);
|
||||
diffuse *= color;
|
||||
specular *= color;
|
||||
}
|
||||
|
||||
// Environment mapping.
|
||||
if (trace.m->GetChannelStage(Channel_Reflection))
|
||||
{
|
||||
Color color = SampleMaterialAttribute(trace, Channel_Reflection);
|
||||
switch (trace.m->GetChannelStage(Channel_Reflection)->op)
|
||||
{
|
||||
case Material::Operator_Multiply:
|
||||
diffuse *= color;
|
||||
break;
|
||||
|
||||
case Material::Operator_Default:
|
||||
case Material::Operator_Add:
|
||||
diffuse += color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
diffuse = SampleMaterialSink(trace, ShaderTree::SinkDiffuse);
|
||||
specular = SampleMaterialSink(trace, ShaderTree::SinkSpecular);
|
||||
self = SampleMaterialSink(trace, ShaderTree::SinkConstant);
|
||||
}
|
||||
|
||||
// Final color.
|
||||
o = ((diffuse * (l_diff + l_indirect + ambient* ambient_occlusion)) + specular * l_spec + self) /** alpha*/; // Don't multiply the alpha, because there is real raytracing for the refraction after.
|
||||
}
|
||||
else
|
||||
{
|
||||
alpha = 0;
|
||||
o.Set(0, 0, 0);
|
||||
}
|
||||
|
||||
// Apply fog.
|
||||
if (scene->fog_far > 0)
|
||||
{
|
||||
float kfog = Types::Clamp((trace.td - scene->fog_near) / (scene->fog_far - scene->fog_near));
|
||||
o = o * (1.f - kfog) + scene->fog_color * kfog;
|
||||
}
|
||||
|
||||
// Trace reflected and transmitted rays as required.
|
||||
float krefl = alpha;
|
||||
|
||||
float eta = trace.m->irefraction;
|
||||
if (trace.ir == trace.m->irefraction)
|
||||
eta = 1.0f;
|
||||
|
||||
if (((alpha < 1) || blend_additive) && bounce.refraction)
|
||||
{
|
||||
float n = trace.ir / eta;
|
||||
|
||||
if (configuration.fresnel_activate)
|
||||
krefl = Fresnel(trace.d, trace.n.FaceForward(trace.d), n);
|
||||
|
||||
float c1 = -trace.n.FaceForward(trace.d).Dot(trace.d);
|
||||
float w = n * Types::Abs(c1);
|
||||
float c2 = Math::Sqrt(1 + (w - n) * (w + n));
|
||||
|
||||
Vector4 rtransmit = (trace.d * n) + trace.n.FaceForward(trace.d) * (w - c2);
|
||||
rtransmit = rtransmit.Normalized();
|
||||
Vector4 offset_pi = trace.pi + rtransmit * Units::Mm(1.f);
|
||||
|
||||
if (c2 < 0)
|
||||
krefl = 1.0f; // Full reflection, we are inside the matter and by an angle where it is physically impossible (as Snell-Descartes law) to have refraction.
|
||||
|
||||
if ((1.0f - krefl) > 0.0f)
|
||||
{
|
||||
bounce.refraction--;
|
||||
|
||||
Color b;
|
||||
float save_ir = trace.ir;
|
||||
trace.ir = eta;
|
||||
Raytrace(RayGrid(offset_pi, rtransmit), b, bounce, &trace);
|
||||
trace.ir = save_ir;
|
||||
|
||||
if (blend_additive)
|
||||
o += b;
|
||||
else o = o * krefl + b * (1 - krefl);
|
||||
|
||||
bounce.refraction++;
|
||||
}
|
||||
}
|
||||
|
||||
// Reflection.
|
||||
float material_reflection = SampleMaterialSink(trace, ShaderTree::SinkReflection).x;
|
||||
if (configuration.trace_reflection && material_reflection && bounce.reflection)
|
||||
{
|
||||
if (krefl > 0.0f)
|
||||
{
|
||||
bounce.reflection--;
|
||||
|
||||
Vector4 nf = trace.n.FaceForward(trace.d).Normalized();
|
||||
float c1 = -nf.Dot(trace.d);
|
||||
Vector4 rreflect = trace.d + (nf * 2.f * Types::Abs(c1));
|
||||
|
||||
Vector4 offset_pi = trace.pi + rreflect * Units::Mm(1.f) ;
|
||||
|
||||
Color b;
|
||||
float save_ir = trace.ir;
|
||||
trace.ir = eta;
|
||||
Raytrace(RayGrid(offset_pi, rreflect), b, bounce, &trace);
|
||||
trace.ir = save_ir;
|
||||
|
||||
o += b * (krefl * material_reflection);
|
||||
|
||||
bounce.reflection++;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Isn't doing this here getting rid of HDR informations?
|
||||
o = o.Clamped(Vector4(0, 0, 0), Vector4(1, 1, 1));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Raytracer::PrimaryRay(const RayGrid &ray, Color &o)
|
||||
{
|
||||
Bounce bounce;
|
||||
bounce.indirect = configuration.indirect_gi_bounce;
|
||||
bounce.reflection = configuration.trace_reflection_max_recursion;
|
||||
bounce.refraction = configuration.trace_refraction_max_recursion;
|
||||
Raytrace(ray, o, bounce);
|
||||
}
|
||||
void Raytracer::Raytrace(const RayGrid &ray, Color &o, Bounce &bounce, Trace *previous_trace)
|
||||
{
|
||||
Trace trace;
|
||||
|
||||
if (previous_trace)
|
||||
{
|
||||
trace.ir = previous_trace->ir;
|
||||
trace.td = previous_trace->td;
|
||||
}
|
||||
|
||||
scene_tree.RaytraceScene(trace, ray.p[0], ray.d[0]);
|
||||
statistics.ray_count++;
|
||||
statistics.tri_test += trace.tri_test;
|
||||
|
||||
// Shade result.
|
||||
if (trace.has_i)
|
||||
{
|
||||
// Compute intersection point.
|
||||
trace.pi = trace.s + trace.d * trace.i_t;
|
||||
|
||||
// Compute intersection normal.
|
||||
Vector4 normal_sink = SampleMaterialSink(trace, ShaderTree::SinkNormal);
|
||||
trace.o->GetMatrix().ApplyRotation(&trace.n, &normal_sink);
|
||||
trace.n.Normalize();
|
||||
if (trace.backface)
|
||||
trace.n = trace.n.Reversed();
|
||||
|
||||
// Integrate the newly traveled distance.
|
||||
trace.td += trace.i_t;
|
||||
|
||||
// Gather radiance.
|
||||
ComputeRadiance(trace, o, bounce);
|
||||
}
|
||||
else
|
||||
o = scene->background_color;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Raytracer::Render(Picture &output, uint w, uint h)
|
||||
{
|
||||
if (!w || !h)
|
||||
return false;
|
||||
|
||||
uint logical_h = h;
|
||||
viewport.Set((float)w, (float)h);
|
||||
|
||||
if (configuration.interlaced)
|
||||
{
|
||||
if (h & 1)
|
||||
__ERR__(__LOG_E__ << "Interlaced frame height must be a multiple of 2.", false)
|
||||
if (configuration.interlaced_trace_half_frame)
|
||||
h /= 2;
|
||||
}
|
||||
|
||||
Camera *camera = scene->current_camera;
|
||||
if (!camera)
|
||||
return false;
|
||||
|
||||
// Create destination picture.
|
||||
output.AllocAs(w, h);
|
||||
|
||||
// Allocate output hdr buffer.
|
||||
Array <Color> hdr(w * h);
|
||||
if (!hdr)
|
||||
__ERR__(__LOG_E__<< "Failed to allocate floating point frame buffer.\n", false)
|
||||
|
||||
// Reset statistics.
|
||||
render_clock = scene->GetClock()->Getf();
|
||||
statistics.Reset();
|
||||
|
||||
// Progress structure.
|
||||
Progress progress;
|
||||
|
||||
progress.start_clock = Platform::Get().GetClock();
|
||||
progress.instance = this;
|
||||
progress.progress = 0;
|
||||
progress.buffer = hdr;
|
||||
progress.w = 0;
|
||||
progress.h = 0;
|
||||
progress.done = false;
|
||||
|
||||
// Create virtual screen.
|
||||
Benchmark bench(true);
|
||||
scene_tree.ResetStats();
|
||||
|
||||
Vector4 screen[4], wscreen[4];
|
||||
|
||||
float hw, hh, ar = ((camera->aspect_ratio == -1.f) ? 1.f : camera->aspect_ratio);
|
||||
|
||||
if (camera->aspect_ratio_ref_yaxis)
|
||||
{
|
||||
hw = ((float)w / (float)logical_h) / ar;
|
||||
hh = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hw = 1;
|
||||
hh = ((float)logical_h / ar) / (float)w;
|
||||
}
|
||||
|
||||
screen[0].Set(-hw, hh, camera->zoom_factor);
|
||||
screen[1].Set(hw, hh, camera->zoom_factor);
|
||||
screen[2].Set(hw, -hh, camera->zoom_factor);
|
||||
screen[3].Set(-hw, -hh, camera->zoom_factor);
|
||||
|
||||
camera->GetMatrix().Apply(wscreen, screen, 4);
|
||||
|
||||
// Interpolate across world screen and trace.
|
||||
Vector4 dt_l, pt_l, dt_r, pt_r;
|
||||
|
||||
dt_l = (wscreen[3] - wscreen[0]) / (float)logical_h;
|
||||
pt_l = wscreen[0];
|
||||
dt_r = (wscreen[2] - wscreen[1]) / (float)logical_h;
|
||||
pt_r = wscreen[1];
|
||||
|
||||
// Interlace.
|
||||
if (configuration.interlaced && configuration.interlaced_trace_half_frame)
|
||||
{
|
||||
if (!interlace_even)
|
||||
{
|
||||
pt_l += dt_l;
|
||||
pt_r += dt_r;
|
||||
}
|
||||
dt_l *= 2.f;
|
||||
dt_r *= 2.f;
|
||||
}
|
||||
|
||||
const Vector4 &s = camera->GetMatrix().GetRow(3);
|
||||
|
||||
// Rendering.
|
||||
abort = false;
|
||||
progress.description = "Rendering (1/2)";
|
||||
|
||||
#define __JobTileSize 32
|
||||
|
||||
// Split rendering in tiles.
|
||||
AutoList <ASync::Job *> job_list;
|
||||
ASync::JobGroup group;
|
||||
|
||||
for (uint y = 0; y < h; y += __JobTileSize)
|
||||
for (uint x = 0; x < w; x += __JobTileSize)
|
||||
{
|
||||
RaytraceJob *job = new RaytraceJob;
|
||||
job_list.Add(job);
|
||||
|
||||
job->core = this;
|
||||
|
||||
job->start_height = y;
|
||||
job->end_height = y + __JobTileSize < h ? y + __JobTileSize : h;
|
||||
job->start_width = x;
|
||||
job->end_width = x + __JobTileSize < w ? x + __JobTileSize : w;
|
||||
|
||||
job->s = s;
|
||||
job->dt_l = dt_l; job->pt_l = pt_l;
|
||||
job->dt_r = dt_r; job->pt_r = pt_r;
|
||||
|
||||
job->hdr = hdr;
|
||||
job->pitch = w;
|
||||
|
||||
Platform::Get().job_manager->EnqueueJob(job, &group);
|
||||
}
|
||||
|
||||
while (!Platform::Get().job_manager->JoinGroup(&group, false))
|
||||
if (hook)
|
||||
{
|
||||
// progress.progress = 1.f - (float)group.GetJobCount() / job_list.GetCount();
|
||||
hook->RaytracerProgress(progress);
|
||||
}
|
||||
|
||||
job_list.Clear();
|
||||
/*
|
||||
// Split anti-aliasing in tiles.
|
||||
progress.description = "Anti-aliasing (2/2)";
|
||||
|
||||
for (uint y = 1; y < (h - 1); y += __JobTileSize)
|
||||
for (uint x = 1; x < (w - 1); x += __JobTileSize)
|
||||
{
|
||||
nAntialiasJob *job = new nAntialiasJob;
|
||||
job_list.Add(job);
|
||||
|
||||
job->core = this;
|
||||
|
||||
job->start_height = y;
|
||||
job->end_height = y + __JobTileSize < (h - 1) ? y + __JobTileSize : (h - 1);
|
||||
job->start_width = x;
|
||||
job->end_width = x + __JobTileSize < (w - 1) ? x + __JobTileSize : (w - 1);
|
||||
|
||||
job->s = s;
|
||||
job->dt_l = dt_l; job->pt_l = pt_l;
|
||||
job->dt_r = dt_r; job->pt_r = pt_r;
|
||||
|
||||
job->hdr = hdr;
|
||||
job->pitch = w;
|
||||
|
||||
Platform::Get().job_manager->EnqueueJob(job, &group);
|
||||
}
|
||||
|
||||
// Join anti-aliasing job group.
|
||||
while (!Platform::Get().job_manager->JoinGroup(&group, false))
|
||||
if (hook)
|
||||
{
|
||||
// progress.progress = 1.f - (float)group.GetJobCount() / job_list.GetCount();
|
||||
hook->RaytracerProgress(progress);
|
||||
}
|
||||
|
||||
job_list.Clear();
|
||||
*/
|
||||
bench.Stop();
|
||||
__LOG__ << "Raytracing done. Took " << bench.GetMs() << " ms. Ray/s = " << (scene_tree.ray_count * 1000) / bench.GetMs() << "\n";
|
||||
|
||||
// HDR conversion to standard 32 bit RGBA.
|
||||
#pragma omp parallel
|
||||
{
|
||||
#pragma omp for schedule(dynamic) nowait
|
||||
for (uint v = 0; v < h; ++v)
|
||||
{
|
||||
uint *o_rgb = ((uint *)output.GetData()) + w * v;
|
||||
Color *o_hdr = hdr + w * v;
|
||||
|
||||
for (uint u = 0; u < w; ++u)
|
||||
o_rgb[u] =
|
||||
((uint)(Types::Clamp(o_hdr[u].w) * 255) << 24) +
|
||||
((uint)(Types::Clamp(o_hdr[u].x) * 255) << 16) +
|
||||
((uint)(Types::Clamp(o_hdr[u].y) * 255) << 8) +
|
||||
((uint)(Types::Clamp(o_hdr[u].z) * 255));
|
||||
}
|
||||
}
|
||||
// ...
|
||||
|
||||
// Backup current frame if interlaced and wait for the next half-frame.
|
||||
if (configuration.interlaced)
|
||||
{
|
||||
if (interlace_half_frame.isValid())
|
||||
{
|
||||
// If the frame is valid compose to output.
|
||||
if ((interlace_half_frame.GetWidth() != w) || (interlace_half_frame.GetHeight() != h))
|
||||
__LOG_E__ << "Unexpected frame dimension change during interlaced sequence rendering.\n";
|
||||
|
||||
else
|
||||
{
|
||||
Picture half_frame(output);
|
||||
|
||||
if (output.AllocAs(w, logical_h))
|
||||
{
|
||||
// Select even and odd frames based on current parity.
|
||||
Picture *even = interlace_even ? &half_frame : &interlace_half_frame,
|
||||
*odd = interlace_even ? &interlace_half_frame : &half_frame;
|
||||
|
||||
// Compose.
|
||||
uint *p_even = (uint *)even->GetData(),
|
||||
*p_odd = (uint *)odd->GetData(),
|
||||
*p_output = (uint *)output.GetData();
|
||||
|
||||
if (configuration.interlaced_trace_half_frame)
|
||||
for (uint v = 0; v < h; ++v)
|
||||
{
|
||||
Memory::Copy(p_output, p_even, w * 4);
|
||||
p_even += w;
|
||||
p_output += w;
|
||||
|
||||
Memory::Copy(p_output, p_odd, w * 4);
|
||||
p_odd += w;
|
||||
p_output += w;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (interlace_even)
|
||||
p_even += w;
|
||||
else p_odd += w;
|
||||
|
||||
for (uint v = 0; v < h; ++v)
|
||||
{
|
||||
Memory::Copy(p_output, p_even, w * 4);
|
||||
p_even += w * 2;
|
||||
p_output += w;
|
||||
|
||||
Memory::Copy(p_output, p_odd, w * 4);
|
||||
p_odd += w * 2;
|
||||
p_output += w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drop buffer, it has been committed to output.
|
||||
interlace_half_frame.Free();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Buffer the current output and drop it. No save is to be done yet.
|
||||
interlace_half_frame.Clone(output);
|
||||
output.Free();
|
||||
}
|
||||
}
|
||||
|
||||
// Done, switch interlace parity.
|
||||
interlace_even = !interlace_even;
|
||||
viewport.Set(1, 1);
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Raytracer::StartInterlacedSequence()
|
||||
{
|
||||
interlace_even = configuration.interlace_even;
|
||||
interlace_half_frame.Free();
|
||||
}
|
||||
void Raytracer::Abort()
|
||||
{ abort = true; }
|
||||
void Raytracer::SetConfiguration(const Configuration &config)
|
||||
{
|
||||
configuration = config;
|
||||
for (int n = 0; n < 32; ++n)
|
||||
monte_carlo[n].Initialize(configuration.gi_sample, configuration.gi_sample, Units::Deg(configuration.ao_angle)); // 64 evaluations per ray.
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Raytracer::SetScene(const GS::S3D::Scene *s)
|
||||
{
|
||||
if (!gf)
|
||||
__ERR__(__LOG_E__ << "No graphic resource factory to set raytracer scene.\n", false)
|
||||
|
||||
Free();
|
||||
|
||||
// Grab scene and shadow scene.
|
||||
scene = s;
|
||||
if (!scene_tree.SetScene(*gf, s) || !scene_shadow_tree.SetScene(*gf, s, true))
|
||||
return false;
|
||||
|
||||
// Grab lights, reset caches.
|
||||
SharedList <S3D::MLight *> lights;
|
||||
s->GetItemListByType(lights);
|
||||
|
||||
if (!lgt.Allocate(lights.GetCount()))
|
||||
__ERR__(__LOG_E__ << "Failed to allocate raytracer light array.\n", false)
|
||||
|
||||
uint lgt_count = 0;
|
||||
ListForeachPtr(S3D::MLight *, l, lights)
|
||||
{
|
||||
lgt[lgt_count].l = l->isActive() ? l : NULL;
|
||||
lgt[lgt_count].g = NULL;
|
||||
lgt_count++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void Raytracer::Free()
|
||||
{
|
||||
scene_tree.Free();
|
||||
scene_shadow_tree.Free();
|
||||
|
||||
lgt.Free();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Raytracer::Raytracer(ResourceFactory *f) : gf(f)
|
||||
{
|
||||
SetConfiguration(configuration);
|
||||
viewport.Set(1, 1);
|
||||
hook = NULL;
|
||||
}
|
||||
89
include/modules/raytracer/raytracer_geometry.cpp
Normal file
89
include/modules/raytracer/raytracer_geometry.cpp
Normal file
@ -0,0 +1,89 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "raytracer/raytracer_core.h"
|
||||
#include "core/geometry.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::Core;
|
||||
using namespace GS::Raytrace;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Vector4 Raytracer::SampleGeometryAttribute(const Trace &trace, GeometryAttribute attr)
|
||||
{
|
||||
Vector4 sample;
|
||||
|
||||
switch (attr)
|
||||
{
|
||||
case GeometryVertexColor:
|
||||
if (trace.g->rgb)
|
||||
sample = ( trace.g->rgb[trace.bi + 0] * trace.w +
|
||||
trace.g->rgb[trace.bi + trace.it + 1] * trace.u +
|
||||
trace.g->rgb[trace.bi + trace.it + 2] * trace.v );
|
||||
else
|
||||
sample.Set(0.25f, 0.f, 0.f);
|
||||
break;
|
||||
|
||||
case GeometryNormal:
|
||||
{
|
||||
if (
|
||||
(trace.m->renderword & Material::Render_Smooth) ||
|
||||
(trace.m->renderword & Material::Render_NormalTangent)
|
||||
)
|
||||
{
|
||||
// Interpolated vertex normal.
|
||||
sample = ( trace.g->vtx_normal[trace.bi + 0] * 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();
|
||||
|
||||
// Normal map support.
|
||||
if (trace.m->GetChannelStage(Channel_Normal))
|
||||
{
|
||||
if (trace.m->renderword & Material::Render_NormalTangent)
|
||||
{
|
||||
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);
|
||||
Vector4 normal_sample(SampleMaterialAttribute(trace, Channel_Normal)),
|
||||
tangent_normal(normal_sample.x * 2 - 1, normal_sample.y * 2 - 1, normal_sample.z * 2 - 1);
|
||||
|
||||
sample = tangent_normal * tangent_matrix;
|
||||
}
|
||||
else
|
||||
{
|
||||
// World space.
|
||||
Vector4 normal_sample(SampleMaterialAttribute(trace, Channel_Normal)),
|
||||
tangent_normal(normal_sample.x * 2 - 1, normal_sample.z * 2 - 1, normal_sample.y * 2 - 1);
|
||||
sample = tangent_normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
sample = trace.g->pol_normal[trace.ip];
|
||||
}
|
||||
break;
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
79
include/modules/raytracer/raytracer_job.cpp
Normal file
79
include/modules/raytracer/raytracer_job.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "raytracer/raytracer_job.h"
|
||||
#include "core/geometry.h"
|
||||
#include "rand/rand.h"
|
||||
|
||||
using namespace GS::Raytrace;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void RaytraceJob::Execute(uint)
|
||||
{
|
||||
Vector4 pt_s = pt_l + dt_l * (float)start_height;
|
||||
|
||||
for (int v = start_height; v < end_height; ++v)
|
||||
{
|
||||
Vector4 dt_s = ((pt_r + dt_r * (float)start_height) - (pt_l + dt_l * (float)start_height)) / (float)pitch;
|
||||
for (int u = start_width; u < end_width; ++u)
|
||||
{
|
||||
Vector4 d = (pt_s + dt_s * (float)u - s).Normalized();
|
||||
core->PrimaryRay(RayGrid(s, d), hdr[v * pitch + u]);
|
||||
}
|
||||
pt_s += dt_l;
|
||||
}
|
||||
}
|
||||
void AntialiasJob::Execute(uint)
|
||||
{
|
||||
Configuration &config = core->GetConfiguration();
|
||||
|
||||
float aa_v_k = config.interlaced_trace_half_frame ? 0.5f : 1.f,
|
||||
aa_threshold = config.aa_threshold,
|
||||
aa_jitter = config.aa_jitter;
|
||||
|
||||
int aa_sample = config.aa_sample;
|
||||
|
||||
// When rendering half frame halve the AA kernel vertically.
|
||||
for (int v = start_height; v < end_height; ++v)
|
||||
for (int u = start_width; u < end_width; ++u)
|
||||
{
|
||||
Color *o_hdr = &hdr[v * pitch + u];
|
||||
|
||||
// Check threshold.
|
||||
if (
|
||||
(Vector4::Dist2(o_hdr[0], o_hdr[-1]) < aa_threshold) &&
|
||||
(Vector4::Dist2(o_hdr[0], o_hdr[-pitch]) < aa_threshold) &&
|
||||
(Vector4::Dist2(o_hdr[0], o_hdr[1]) < aa_threshold) &&
|
||||
(Vector4::Dist2(o_hdr[0], o_hdr[pitch]) < aa_threshold)
|
||||
)
|
||||
continue;
|
||||
|
||||
// Multi-sample.
|
||||
o_hdr[0].Set(0, 0, 0);
|
||||
|
||||
for (int ms_v = 0; ms_v < aa_sample; ++ms_v)
|
||||
{
|
||||
// TODO pre-calculate jittered/non-jittered grids.
|
||||
float ms_v_o = v + ((float)ms_v * aa_v_k) / aa_sample + (aa_jitter ? Random::FRand(0.125f / aa_sample) : 0);
|
||||
|
||||
Vector4 dt_s = ((pt_r + dt_r * ms_v_o) - (pt_l + dt_l * ms_v_o)) / (float)pitch,
|
||||
pt_s = pt_l + dt_l * ms_v_o;
|
||||
|
||||
for (int ms_u = 0; ms_u < aa_sample; ++ms_u)
|
||||
{
|
||||
float ms_u_o = u + (float)ms_u / aa_sample + (aa_jitter ? Random::FRand(0.125f / aa_sample) : 0);
|
||||
Vector4 d = (pt_s + dt_s * ms_u_o - s).Normalized();
|
||||
|
||||
Color out;
|
||||
core->PrimaryRay(RayGrid(s, d), out);
|
||||
o_hdr[0] += out.Clamped(0, 1);
|
||||
}
|
||||
}
|
||||
o_hdr[0] /= (float)(aa_sample * aa_sample);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
181
include/modules/raytracer/raytracer_material.cpp
Normal file
181
include/modules/raytracer/raytracer_material.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
275
include/modules/raytracer/raytracer_scene.cpp
Normal file
275
include/modules/raytracer/raytracer_scene.cpp
Normal file
@ -0,0 +1,275 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include "raytracer/raytracer_scene.h"
|
||||
#include "scene3d/mobject.h"
|
||||
#include "scene3d/mlight.h"
|
||||
#include "scene3d/scene.h"
|
||||
#include "scene3d/instance.h"
|
||||
#include "scene3d/group.h"
|
||||
#include "core/geometry_bih.h"
|
||||
#include "metafile/nml_object.h"
|
||||
|
||||
using namespace GS;
|
||||
using namespace GS::Core;
|
||||
using namespace GS::Raytrace;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void SceneBIH::ResetStats()
|
||||
{
|
||||
ray_count = 0;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void SceneBIH::TraceLeaf(BIH::Node *leaf, float tmin, float tmax, BIH::Trace &trace, void *parm)
|
||||
{
|
||||
Vector4 &s = trace.s, &d = trace.d;
|
||||
Trace *s_trace = (Trace *)parm;
|
||||
uint *leaf_indice = (uint *)leaf->p;
|
||||
|
||||
for (uint n = 0; n < leaf->count; ++n)
|
||||
{
|
||||
Core::Object *o = obj[leaf_indice[n]].o;
|
||||
IGeometryTree *tree = obj[leaf_indice[n]].tree;
|
||||
|
||||
// Raytrace object in local space.
|
||||
Vector4 local_s = s * o->GetInverseMatrix(), local_d;
|
||||
o->GetInverseMatrix().ApplyRotation(&local_d, &d);
|
||||
|
||||
GeometryTrace geo_trace;
|
||||
tree->RaytraceGeometry(geo_trace, local_s, local_d, tmax);
|
||||
|
||||
if (!geo_trace.has_i)
|
||||
continue;
|
||||
|
||||
// Integrate result.
|
||||
if (!s_trace->has_i || (geo_trace.i_t < s_trace->i_t))
|
||||
{
|
||||
/*
|
||||
Note: Do not copy the complete geo_trace, we do not want
|
||||
to duplicate trace stacks.
|
||||
*/
|
||||
*((GeometryTraceBase *)s_trace) = ((GeometryTraceBase &)geo_trace);
|
||||
|
||||
s_trace->has_i = true;
|
||||
|
||||
s_trace->o = o;
|
||||
s_trace->tri_test += geo_trace.tri_test;
|
||||
}
|
||||
}
|
||||
}
|
||||
void SceneBIH::RaytraceScene(Trace &trace, const Vector4 &s, const Vector4 &d, float l)
|
||||
{
|
||||
ray_count++;
|
||||
|
||||
trace.s = s;
|
||||
trace.d = d;
|
||||
|
||||
BIH::Trace bih_trace;
|
||||
Tree::Raytrace(bih_trace, s, d, l, (void *)&trace);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Geometry *SceneBIH::TranslateGeometry(Geometry *g) const
|
||||
{
|
||||
if (obj && g)
|
||||
for (uint n = 0; n < obj.GetCount(); ++n)
|
||||
if (obj[n].g == g)
|
||||
return obj[n].og;
|
||||
return g;
|
||||
}
|
||||
void SceneBIH::AddObject(ResourceFactory &gf, S3D::MObject *o, uint &obj_count, MinMax *varray, bool shadow)
|
||||
{
|
||||
if (!o->isActive())
|
||||
return;
|
||||
if (o->geometry.IsEmpty() || !o->GetBaseItem()->opacity)
|
||||
return;
|
||||
if (o->mitem_flags.IsSet(S3D::MItem::Flag_IsHelper | S3D::MItem::Flag_EditorHidden | S3D::MItem::Flag_EditorLocked))
|
||||
return;
|
||||
|
||||
// Grab object geometry.
|
||||
Geometry *g = gf.LoadGeometry(o->geometry);
|
||||
if (!g)
|
||||
return;
|
||||
|
||||
obj[obj_count].og = g; // Store original geometry to map back from skinned geometry.
|
||||
if (!g->material_table.GetCount() || !g->pol.GetCount())
|
||||
return;
|
||||
|
||||
if (shadow)
|
||||
{
|
||||
if (g->flag.IsSet(Geometry::FlagNullShadowProxy))
|
||||
return;
|
||||
if (!g->shadow_proxy.IsEmpty())
|
||||
g = gf.LoadGeometry(g->shadow_proxy);
|
||||
}
|
||||
|
||||
// Perform skinning.
|
||||
if (o->HasSkin() && g->skin)
|
||||
{
|
||||
Skin *skin = o->GetSkin();
|
||||
|
||||
// Serialize geometry.
|
||||
using namespace NML;
|
||||
|
||||
File file;
|
||||
file.AddRoot(g->AsMetaTag());
|
||||
|
||||
Geometry *sg = new Geometry;
|
||||
LoadFromFile(*sg, file);
|
||||
|
||||
// Build required structures upfront.
|
||||
sg->ComputeVertexNormal();
|
||||
sg->ComputeVertexTangent();
|
||||
|
||||
// Vertex skinning.
|
||||
for (uint n = 0; n < sg->vtx.GetCount(); ++n)
|
||||
{
|
||||
Vector4 v(0, 0, 0);
|
||||
for (int b = 0; b < 4; ++b)
|
||||
{
|
||||
if (!sg->skin[n].w[b])
|
||||
break;
|
||||
v += (sg->vtx[n] * skin->bones_mtx[sg->skin[n].bone_index[b]]) * sg->skin[n].w[b];
|
||||
}
|
||||
sg->vtx[n] = v;
|
||||
}
|
||||
|
||||
// Normal skinning.
|
||||
Vector4 s, w;
|
||||
int tt = 0;
|
||||
for (uint p = 0; p < sg->pol.GetCount(); ++p)
|
||||
for (uint n = 0; n < sg->pol[p].vtx_count; ++n)
|
||||
{
|
||||
s.Set(0, 0, 0);
|
||||
for (int b = 0; b < 4; ++b)
|
||||
{
|
||||
int i = sg->pol[p].binding[n];
|
||||
if (!sg->skin[i].w[b])
|
||||
break;
|
||||
skin->bones_mtx[sg->skin[i].bone_index[b]].ApplyRotation(&w, &sg->vtx_normal[tt]);
|
||||
s += w * sg->skin[i].w[b];
|
||||
}
|
||||
sg->vtx_normal[tt++] = s;
|
||||
}
|
||||
|
||||
// Tangent base skinning.
|
||||
Vector4 _b, _t;
|
||||
tt = 0;
|
||||
for (uint p = 0; p < sg->pol.GetCount(); ++p)
|
||||
for (uint n = 0; n < sg->pol[p].vtx_count; ++n)
|
||||
{
|
||||
_b.Set(0, 0, 0);
|
||||
_t.Set(0, 0, 0);
|
||||
for (int b = 0; b < 4; ++b)
|
||||
{
|
||||
int i = sg->pol[p].binding[n];
|
||||
if (!sg->skin[i].w[b])
|
||||
break;
|
||||
|
||||
skin->bones_mtx[sg->skin[i].bone_index[b]].ApplyRotation(&w, &sg->vtx_tangent[tt].B);
|
||||
_b += w * sg->skin[i].w[b];
|
||||
skin->bones_mtx[sg->skin[i].bone_index[b]].ApplyRotation(&w, &sg->vtx_tangent[tt].T);
|
||||
_t += w * sg->skin[i].w[b];
|
||||
}
|
||||
sg->vtx_tangent[tt].B = _b;
|
||||
sg->vtx_tangent[tt].T = _t;
|
||||
tt++;
|
||||
}
|
||||
|
||||
// Use as the base geometry.
|
||||
// but first copy the material from the base material
|
||||
sg->material_table.Allocate(g->material_table.GetCount());
|
||||
for (uint k = 0; k < g->material_table.GetCount(); ++k)
|
||||
sg->material_table[k] = g->material_table[k];
|
||||
|
||||
g = sg;
|
||||
}
|
||||
|
||||
// Prepare geometry.
|
||||
IGeometryTree *tree = new GeometryBIHTree;
|
||||
tree->BuildFromGeometry(gf, g);
|
||||
|
||||
// Build minmax for the transformed geometry.
|
||||
varray[obj_count] = g->ComputeMinMax(&o->GetMatrix());
|
||||
|
||||
obj[obj_count].g = g;
|
||||
obj[obj_count].tree = tree;
|
||||
obj[obj_count++].o = o;
|
||||
}
|
||||
bool SceneBIH::SetScene(ResourceFactory &gf, const S3D::Scene *s, bool shadow)
|
||||
{
|
||||
Free();
|
||||
|
||||
using namespace S3D;
|
||||
|
||||
SharedList <MObject *> objects;
|
||||
s->GetItemListByType(objects);
|
||||
SharedList <Instance *> instances;
|
||||
s->GetItemListByType(instances);
|
||||
|
||||
// Grab the scene content.
|
||||
uint obj_count = 0;
|
||||
ListForeachPtr(MObject *, o, objects)
|
||||
if (!o->geometry.IsEmpty())
|
||||
obj_count++;
|
||||
|
||||
// Count the instance objects.
|
||||
ListForeachPtr(Instance *, i, instances)
|
||||
{
|
||||
if (!i->instance_scene)
|
||||
{
|
||||
if (!(i->instance_scene = new Scene(s->GetVM())))
|
||||
continue;
|
||||
|
||||
i->instance_scene->FromMetaFileStoreGroup(i->template_path, &i->instance_group, SceneIOObject | SceneIOLight);
|
||||
if (i->instance_group != NULL)
|
||||
i->instance_group->SetRootItem(i);
|
||||
}
|
||||
|
||||
if (i->instance_group)
|
||||
ListForeachPtr(MItem *, ig, i->instance_group->GetItemList())
|
||||
if (ig->GetItemType() == Type_Object && !((MObject *)ig)->geometry.IsEmpty())
|
||||
obj_count++;
|
||||
}
|
||||
|
||||
if (!obj_count)
|
||||
return true;
|
||||
|
||||
if (!obj.Allocate(obj_count))
|
||||
__ERR__(__LOG_E__ << "Failed to grab scene to raytracer.\n", false)
|
||||
|
||||
// Build scene tree and object trees.
|
||||
Array <MinMax> varray(obj_count);
|
||||
if (!varray)
|
||||
__ERR__(__LOG_E__ << "Failed to allocate volume array to build scene tree.\n", false)
|
||||
|
||||
obj_count = 0;
|
||||
|
||||
ListForeachPtr(MObject *, o, objects)
|
||||
AddObject(gf, o, obj_count, varray, shadow);
|
||||
|
||||
// Add the instance objects.
|
||||
ListForeachPtr(Instance *, i, instances)
|
||||
if (i->instance_group)
|
||||
ListForeachPtr(MItem *, ig, i->instance_group->GetItemList())
|
||||
if (ig->GetItemType() == Type_Object && !((MObject *)ig)->geometry.IsEmpty())
|
||||
AddObject(gf, ((MObject *)ig), obj_count, varray, shadow);
|
||||
|
||||
// Build tree.
|
||||
if (!Build(obj_count, varray))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
void SceneBIH::Free()
|
||||
{
|
||||
obj.Free();
|
||||
Tree::Free();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
51
include/modules/raytracer/raytracer_spread.cpp
Normal file
51
include/modules/raytracer/raytracer_spread.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include "raytracer/raytracer_spread.h"
|
||||
#include "math/matrix3.h"
|
||||
#include "rand/rand.h"
|
||||
#include "memory/memory.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS::Raytrace;
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Spread::Initialize(uint u_count, uint v_count, float max_spread)
|
||||
{
|
||||
Free();
|
||||
|
||||
if (!spread.Allocate(u_count * v_count))
|
||||
__ERR__(__LOG_E__ << "failed to allocate vector spread.\n", false)
|
||||
|
||||
float s_v = max_spread / (v_count + 2), a_v = s_v;
|
||||
|
||||
uint count = 0;
|
||||
for (uint v = 0; v < v_count; ++v)
|
||||
{
|
||||
float strat_v = a_v + Random::FRand(s_v); // Stratified sampling.
|
||||
|
||||
float s_u = Units::Deg(360.f) / u_count, a_u = Units::Deg(0.f);
|
||||
for (uint u = 0; u < u_count; ++u)
|
||||
{
|
||||
float strat_u = a_u + Random::FRand(s_u); // Stratified sampling.
|
||||
|
||||
Vector4 tmp(sin(strat_v), 0, cos(strat_v));
|
||||
Matrix3 rtz(Matrix3::RotationMatrixZAxis(strat_u));
|
||||
rtz.Apply(&spread[count++], &tmp);
|
||||
|
||||
a_u += s_u;
|
||||
}
|
||||
a_v += s_v;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void Spread::Free()
|
||||
{
|
||||
spread.Free();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
296
include/modules/raytracer/shader_tree_cpu.cpp
Normal file
296
include/modules/raytracer/shader_tree_cpu.cpp
Normal file
@ -0,0 +1,296 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
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;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user