commit 36e65c04e19ddd59120cae8eb1c727d423531e32
parent d0769c99b95f72271fbd28809e376f3e8213f23c
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 6 Apr 2017 16:01:39 +0200
Add partial derivative of the surface fragment position in U and V
Diffstat:
2 files changed, 56 insertions(+), 12 deletions(-)
diff --git a/src/ssol.h b/src/ssol.h
@@ -240,13 +240,17 @@ struct ssol_medium {
static const struct ssol_medium SSOL_MEDIUM_VACUUM = SSOL_MEDIUM_VACUUM__;
struct ssol_surface_fragment {
- double dir[3]; /* World space incoming direction. Point outward the surface */
- double pos[3]; /* World space position */
+ double dir[3]; /* World space incoming direction. Point forward the surface */
+ double P[3]; /* World space position */
double Ng[3]; /* Normalized world space geometry normal */
double Ns[3]; /* Normalized world space shading normal */
double uv[2]; /* Texture coordinates */
+ double dPdu[3]; /* Partial derivative of the position in u */
+ double dPdv[3]; /* Partial derivative of the position in v */
+
};
-#define SSOL_SURFACE_FRAGMENT_NULL__ {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0}}
+#define SSOL_SURFACE_FRAGMENT_NULL__ \
+ {{0,0,0}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0}, {0,0,0}, {0,0,0}}
static const struct ssol_surface_fragment SSOL_SURFACE_FRAGMENT_NULL =
SSOL_SURFACE_FRAGMENT_NULL__;
diff --git a/src/ssol_material.c b/src/ssol_material.c
@@ -18,8 +18,10 @@
#include "ssol_material_c.h"
#include "ssol_device_c.h"
-#include <rsys/double3.h>
#include <rsys/double2.h>
+#include <rsys/double3.h>
+#include <rsys/double33.h>
+#include <rsys/float2.h>
#include <rsys/float3.h>
#include <rsys/float33.h>
#include <rsys/ref_count.h>
@@ -495,31 +497,69 @@ surface_fragment_setup
{
struct s3d_attrib attr;
char has_texcoord, has_normal;
+ struct s3d_attrib uvs[3];
+ struct s3d_attrib P[3];
+ double duv1[2], duv2[2];
+ double dP1[3], dP2[3];
+ double det;
ASSERT(fragment && pos && dir && primitive && uv);
/* Assume that the submitted normal look forward the incoming dir */
ASSERT(d3_dot(normal, dir) <= 0);
- /* Setup the incoming direction */
- d3_set(fragment->dir, dir);
-
- /* Setup the surface position */
- d3_set(fragment->pos, pos);
+ d3_set(fragment->dir, dir); /* Setup the incoming direction */
+ d3_set(fragment->P, pos); /* Setup the surface position */
+ d3_normalize(fragment->Ng, normal); /* Normalize the geometry normal */
- /* Normalize the geometry normal */
- d3_set(fragment->Ng, normal);
- d3_normalize(fragment->Ng, fragment->Ng);
+ /* Retrieve the position of the triangle vertices */
+ S3D(triangle_get_vertex_attrib(primitive, 0, S3D_POSITION, &P[0]));
+ S3D(triangle_get_vertex_attrib(primitive, 1, S3D_POSITION, &P[1]));
+ S3D(triangle_get_vertex_attrib(primitive, 2, S3D_POSITION, &P[2]));
/* Retrieve the tex coord */
S3D(primitive_has_attrib(primitive, SSOL_TO_S3D_TEXCOORD, &has_texcoord));
if (!has_texcoord) {
d2_set_f2(fragment->uv, uv);
+ uvs[0].type = uvs[1].type = uvs[2].type = S3D_FLOAT2;
+ uvs[0].usage = uvs[1].usage = uvs[2].usage = SSOL_TO_S3D_TEXCOORD;
+ f2(uvs[0].value, 1, 0);
+ f2(uvs[1].value, 0, 1);
+ f2(uvs[2].value, 0, 0);
} else {
S3D(primitive_get_attrib(primitive, SSOL_TO_S3D_TEXCOORD, uv, &attr));
+ S3D(triangle_get_vertex_attrib(primitive, 0, SSOL_TO_S3D_TEXCOORD, &uvs[0]));
+ S3D(triangle_get_vertex_attrib(primitive, 1, SSOL_TO_S3D_TEXCOORD, &uvs[1]));
+ S3D(triangle_get_vertex_attrib(primitive, 2, SSOL_TO_S3D_TEXCOORD, &uvs[2]));
ASSERT(attr.type == S3D_FLOAT2);
d2_set_f2(fragment->uv, attr.value);
}
+ /* Compute the partial derivatives. */
+ duv1[0] = uvs[1].value[0] - uvs[0].value[0];
+ duv1[1] = uvs[1].value[1] - uvs[0].value[1];
+ duv2[0] = uvs[2].value[0] - uvs[0].value[0];
+ duv2[1] = uvs[2].value[1] - uvs[0].value[1];
+ dP1[0] = P[1].value[0] - P[0].value[0];
+ dP1[1] = P[1].value[1] - P[0].value[1];
+ dP1[2] = P[1].value[2] - P[0].value[2];
+ dP2[0] = P[2].value[0] - P[0].value[0];
+ dP2[1] = P[2].value[1] - P[0].value[1];
+ dP2[2] = P[2].value[2] - P[0].value[2];
+
+ det = duv1[0]*duv2[1] - duv1[1]*duv2[0];
+ if(det <= 0) { /* Handle zero determinant */
+ double basis[9];
+ d33_basis(basis, fragment->Ng);
+ d3_set(fragment->dPdu, basis + 0);
+ d3_set(fragment->dPdv, basis + 3);
+ } else {
+ double a[3], b[3];
+ d3_sub(fragment->dPdu, d3_muld(a, dP1, duv2[1]), d3_muld(b, dP2, duv1[1]));
+ d3_sub(fragment->dPdv, d3_muld(a, dP2, duv1[0]), d3_muld(b, dP1, duv2[0]));
+ d3_divd(fragment->dPdu, fragment->dPdu, det);
+ d3_divd(fragment->dPdv, fragment->dPdv, det);
+ }
+
/* Retrieve and normalize the shading normal in world space */
S3D(primitive_has_attrib(primitive, SSOL_TO_S3D_NORMAL, &has_normal));
if (!has_normal) {