commit a3fc7537eee74c31bbecd3e63c227709b7142c18
parent 2d3e9fefb5f0680562b61050152539e3bcea5081
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 13 Jul 2016 16:43:12 +0200
Implement the internal material_shade function
Fill a BRDF composite with respect to the given material properties.
Diffstat:
7 files changed, 216 insertions(+), 21 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -71,6 +71,7 @@ set(SSOL_FILES_INC
ssol_brdf.h
ssol_brdf_composite.h
ssol_brdf_reflection.h
+ ssol_c.h
ssol_device_c.h
ssol_image_c.h
ssol_material_c.h
diff --git a/src/ssol.h b/src/ssol.h
@@ -178,13 +178,14 @@ typedef void
const double wavelength, /* In nanometer */
const double P[3], /* World space position */
const double Ng[3], /* World space geometry normal */
- const double uv[2], /* Parametric coordinates */
- const double wo[3], /* Incident direction */
+ const double Ns[3], /* World space shading normal */
+ const double uv[2], /* Texture coordinates */
+ const double w[3], /* Incoming direction. Point toward the surface */
double* val); /* Returned value */
/* Material descriptors */
struct ssol_mirror_shader {
- ssol_shader_getter_T shading_normal;
+ ssol_shader_getter_T normal;
ssol_shader_getter_T reflectivity;
ssol_shader_getter_T diffuse_specular_ratio;
ssol_shader_getter_T roughness;
diff --git a/src/ssol_c.h b/src/ssol_c.h
@@ -0,0 +1,38 @@
+/* Copyright (C) CNRS 2016
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef SSOL_C_H
+#define SSOL_C_H
+
+#include "ssol.h"
+#include <star/s3d.h>
+
+#define SSOL_TO_S3D_POSITION S3D_POSITION
+#define SSOL_TO_S3D_NORMAL S3D_ATTRIB_0
+#define SSOL_TO_S3D_TEXCOORD S3D_ATTRIB_1
+
+static FINLINE enum s3d_attrib_usage
+ssol_to_s3d_attrib_usage(const enum ssol_attrib_usage usage)
+{
+ switch(usage) {
+ case SSOL_POSITION: return SSOL_TO_S3D_POSITION;
+ case SSOL_NORMAL: return SSOL_TO_S3D_NORMAL;
+ case SSOL_TEXCOORD: return SSOL_TO_S3D_TEXCOORD;
+ default: FATAL("Unreachable code\n"); break;
+ }
+}
+
+#endif /* SSOL_C_H */
+
diff --git a/src/ssol_material.c b/src/ssol_material.c
@@ -14,16 +14,61 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "ssol.h"
+#include "ssol_brdf_composite.h"
+#include "ssol_brdf_reflection.h"
+#include "ssol_c.h"
#include "ssol_material_c.h"
#include "ssol_device_c.h"
+#include <rsys/double3.h>
+#include <rsys/float3.h>
+#include <rsys/float33.h>
+#include <rsys/ref_count.h>
#include <rsys/rsys.h>
#include <rsys/mem_allocator.h>
-#include <rsys/ref_count.h>
+
+#include <math.h>
/*******************************************************************************
* Helper functions
******************************************************************************/
+static res_T
+mirror_shade
+ (const struct ssol_material* mtl,
+ const double wavelength, /* In nanometer */
+ const double P[3], /* World space position */
+ const double Ng[3], /* World space geometry normal */
+ const double Ns[3], /* World space shading normal */
+ const double uv[2], /* Texture coordinates */
+ const double w[3], /* Incoming direction. Point toward the surface */
+ struct brdf_composite* brdfs)
+{
+ struct brdf* reflect = NULL;
+ const struct ssol_mirror_shader* shader;
+ double normal[3];
+ double R; /* Reflectivity */
+ res_T res;
+ ASSERT(mtl && P && Ng && Ns && uv && w && mtl->type == MATERIAL_MIRROR);
+
+ shader = &mtl->data.mirror;
+
+ /* FIXME currently the mirror material is a purely reflective BRDF. Discard
+ * the diffuse_specular_ration & the rougness parameters */
+ shader->normal(mtl->dev, wavelength, P, Ng, Ns, uv, w, normal);
+ shader->reflectivity(mtl->dev, wavelength, P, Ng, Ns, uv, w, &R);
+
+ if(RES_OK != (res = brdf_reflection_create(mtl->dev, &reflect))) goto error;
+ if(RES_OK != (res = brdf_reflection_setup(reflect, R))) goto error;
+ if(RES_OK != (res = brdf_composite_add(brdfs, reflect))) goto error;
+ brdf_ref_put(reflect);
+
+exit:
+ if(reflect) brdf_ref_put(reflect);
+ return res;
+error:
+ goto exit;
+}
+
static void
material_release(ref_T* ref)
{
@@ -40,7 +85,7 @@ static INLINE res_T
shader_ok(const struct ssol_mirror_shader* shader)
{
if(!shader
- || !shader->shading_normal
+ || !shader->normal
|| !shader->reflectivity
|| !shader->diffuse_specular_ratio
|| !shader->roughness)
@@ -142,3 +187,96 @@ ssol_material_create_virtual
return ssol_material_create(dev, out_material, MATERIAL_VIRTUAL);
}
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+material_shade
+ (const struct ssol_material* mtl,
+ const double wavelength, /* In nanometer */
+ const struct s3d_hit* hit, /* Hit point to shade */
+ const float dir[3], /* Incoming direction */
+ struct brdf_composite* brdfs) /* Container of BRDFs */
+{
+ struct s3d_attrib attr;
+ double w[3]; /* Incoming direction */
+ double P[3]; /* World space hit position */
+ double Ng[3]; /* World space normalized geometry normal */
+ double Ns[3]; /* World space normalized shading normal */
+ double uv[2]; /* Texture coordinates */
+ double len;
+ char has_texcoord, has_normal;
+ res_T res = RES_OK;
+ ASSERT(mtl && dir && hit && brdfs);
+
+ /* Convert the incoming direction in double */
+ w[0] = (double)dir[0];
+ w[1] = (double)dir[1];
+ w[2] = (double)dir[2];
+
+ /* Retrieve the hit position */
+ S3D(primitive_get_attrib(&hit->prim, S3D_POSITION, hit->uv, &attr));
+ ASSERT(attr.type == S3D_FLOAT3);
+ P[0] = (double)attr.value[0];
+ P[1] = (double)attr.value[1];
+ P[2] = (double)attr.value[2];
+
+ /* Normalize the geometry normal */
+ len = sqrt(f3_len(hit->normal));
+ Ng[0] = (double)hit->normal[0] / len;
+ Ng[1] = (double)hit->normal[1] / len;
+ Ng[2] = (double)hit->normal[2] / len;
+
+ /* Retrieve the tex coord */
+ S3D(primitive_has_attrib(&hit->prim, SSOL_TO_S3D_TEXCOORD, &has_texcoord));
+ if(!has_texcoord) {
+ uv[0] = (double)hit->uv[0];
+ uv[1] = (double)hit->uv[1];
+ } else {
+ S3D(primitive_get_attrib(&hit->prim, SSOL_TO_S3D_TEXCOORD, hit->uv, &attr));
+ ASSERT(attr.type == S3D_FLOAT2);
+ uv[0] = (double)attr.value[0];
+ uv[1] = (double)attr.value[1];
+ }
+
+ /* Retrieve and normalize the shading normal in world space */
+ S3D(primitive_has_attrib(&hit->prim, SSOL_TO_S3D_NORMAL, &has_normal));
+ if(!has_normal) {
+ d3_set(Ns, Ng);
+ } else {
+ float transform[12];
+ float vec[3];
+
+ S3D(primitive_get_attrib(&hit->prim, SSOL_TO_S3D_NORMAL, hit->uv, &attr));
+ ASSERT(attr.type == S3D_FLOAT3);
+
+ S3D(primitive_get_transform(&hit->prim, transform));
+ /* Check that transform is not "identity" */
+ if(!f3_eq(transform + 0, f3(vec, 1.f, 0.f, 0.f))
+ && !f3_eq(transform + 3, f3(vec, 0.f, 1.f, 0.f))
+ && !f3_eq(transform + 6, f3(vec, 0.f, 0.f, 1.f))) {
+ /* Transform the normal in world space, i.e. multiply it by the inverse
+ * transpose of the "object to world" primitive matrix. Since the affine
+ * part of the 3x4 transformation matrix does not influence the normal
+ * transformation, use the linear part only. */
+ f33_invtrans(transform, transform);
+ f33_mulf3(attr.value, transform, attr.value);
+ }
+
+ len = sqrt(f3_len(attr.value));
+ Ns[0] = (double)attr.value[0] / len;
+ Ns[1] = (double)attr.value[1] / len;
+ Ns[2] = (double)attr.value[2] / len;
+ }
+
+ /* Specific material shading */
+ switch(mtl->type) {
+ case MATERIAL_MIRROR:
+ res = mirror_shade(mtl, wavelength, P, Ng, Ns, uv, w, brdfs);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+
+ return res;
+}
+
diff --git a/src/ssol_material_c.h b/src/ssol_material_c.h
@@ -18,6 +18,9 @@
#include <rsys/ref_count.h>
+struct brdf_composite;
+struct s3d_hit;
+
enum material_type {
MATERIAL_VIRTUAL,
MATERIAL_MIRROR,
@@ -37,4 +40,13 @@ struct ssol_material {
ref_T ref;
};
+extern LOCAL_SYM res_T
+material_shade
+ (const struct ssol_material* mtl,
+ const double wavelength, /* In nanometer */
+ const struct s3d_hit* hit, /* Hit point to shade */
+ const float w[3], /* Incoming direction */
+ struct brdf_composite* brdfs); /* Container of BRDFs */
+
#endif /* SSOL_MATERIAL_C_H */
+
diff --git a/src/ssol_shape.c b/src/ssol_shape.c
@@ -14,6 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "ssol.h"
+#include "ssol_c.h"
#include "ssol_shape_c.h"
#include "ssol_device_c.h"
@@ -305,15 +306,15 @@ ssol_mesh_setup
attrib3[i].get = attribs[i].get;
switch (attribs[i].usage) {
case SSOL_POSITION:
- attrib3[i].usage = S3D_POSITION;
+ attrib3[i].usage = SSOL_TO_S3D_POSITION;
attrib3[i].type = S3D_FLOAT3;
break;
case SSOL_NORMAL:
- attrib3[i].usage = S3D_ATTRIB_0;
+ attrib3[i].usage = SSOL_TO_S3D_NORMAL;
attrib3[i].type = S3D_FLOAT3;
break;
case SSOL_TEXCOORD:
- attrib3[i].usage = S3D_ATTRIB_1;
+ attrib3[i].usage = SSOL_TO_S3D_TEXCOORD;
attrib3[i].type = S3D_FLOAT2;
break;
default:
diff --git a/src/test_ssol_material.c b/src/test_ssol_material.c
@@ -19,18 +19,19 @@
#include <rsys/logger.h>
static void
-get_shading_normal
+get_normal
(struct ssol_device* dev,
const double wavelength,
const double P[3],
const double Ng[3],
+ const double Ns[3],
const double uv[2],
- const double wo[3],
+ const double w[3],
double* val)
{
int i;
- (void) dev; (void) wavelength; (void) P; (void) uv; (void) wo;
- for (i = 0; i < 3; i++) val[i] = Ng[i];
+ (void)dev, (void)wavelength, (void)P, (void)Ng, (void)uv, (void)w;
+ FOR_EACH(i, 0, 3) val[i] = Ns[i];
}
static void
@@ -39,11 +40,12 @@ get_reflectivity
const double wavelength,
const double P[3],
const double Ng[3],
+ const double Ns[3],
const double uv[2],
- const double wo[3],
+ const double w[3],
double* val)
{
- (void) dev; (void) wavelength; (void) P; (void) Ng; (void) uv; (void) wo;
+ (void)dev, (void)wavelength, (void)P, (void)Ng, (void)Ns, (void)uv, (void)w;
*val = 1;
}
@@ -53,11 +55,12 @@ get_diffuse_specular_ratio
const double wavelength,
const double P[3],
const double Ng[3],
+ const double Ns[3],
const double uv[2],
- const double wo[3],
+ const double w[3],
double* val)
{
- (void) dev; (void) wavelength; (void) P; (void) Ng; (void) uv; (void) wo;
+ (void)dev, (void)wavelength, (void)P, (void)Ng, (void)Ns, (void)uv, (void)w;
*val = 0;
}
@@ -67,11 +70,12 @@ get_roughness
const double wavelength,
const double P[3],
const double Ng[3],
+ const double Ns[3],
const double uv[2],
- const double wo[3],
+ const double w[3],
double* val)
{
- (void) dev; (void) wavelength; (void) P; (void) Ng; (void) uv; (void) wo;
+ (void)dev, (void)wavelength, (void)P, (void)Ng, (void)Ns, (void)uv, (void)w;
*val = 0;
}
@@ -107,7 +111,7 @@ main(int argc, char** argv)
CHECK(ssol_material_ref_put(NULL), RES_BAD_ARG);
CHECK(ssol_material_ref_put(material), RES_OK);
- shader.shading_normal = get_shading_normal;
+ shader.normal = get_normal;
shader.reflectivity = get_reflectivity;
shader.diffuse_specular_ratio = get_diffuse_specular_ratio;
shader.roughness = get_roughness;
@@ -116,9 +120,9 @@ main(int argc, char** argv)
CHECK(ssol_mirror_set_shader(material, NULL), RES_BAD_ARG);
CHECK(ssol_mirror_set_shader(material, &shader), RES_OK);
- shader.shading_normal = NULL;
+ shader.normal = NULL;
CHECK(ssol_mirror_set_shader(material, &shader), RES_BAD_ARG);
- shader.shading_normal = get_shading_normal;
+ shader.normal = get_normal;
shader.reflectivity = NULL;
CHECK(ssol_mirror_set_shader(material, &shader), RES_BAD_ARG);