[Evas/evas-3d] Add shadow maps. Added two scene-API functions for enable and disable shadows on the scene. Added 6 light-API function for set and get the light projection.

Reviewers: raster, cedric, Hermet

Subscribers: raster, cedric

Differential Revision: https://phab.enlightenment.org/D1330
This commit is contained in:
Dmytro Dadyka 2014-09-03 21:06:03 +09:00 committed by ChunEon Park
parent d1dd349feb
commit 0d2f4dbc11
12 changed files with 713 additions and 15 deletions

View File

@ -0,0 +1,313 @@
/*
* This example illustrating use of shadows in the scene.
*
* @see evas_3d_scene_shadows_enable_set(Eina_Bool _shadows_enabled)
*
* Compile with "gcc -o evas-3d-shadows evas-3d-shadows.c `pkg-config --libs --cflags evas ecore ecore-evas eo` -lm"
*/
#define EFL_EO_API_SUPPORT
#define EFL_BETA_API_SUPPORT
#include <Eo.h>
#include <Evas.h>
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <math.h>
#define WIDTH 1024
#define HEIGHT 1024
Ecore_Evas *ecore_evas = NULL;
Evas *evas = NULL;
Eo *background = NULL;
Eo *image = NULL;
Eo *scene = NULL;
Eo *root_node = NULL;
Eo *camera_node = NULL;
Eo *light_node = NULL;
Eo *camera = NULL;
Eo *mesh_node = NULL;
Eo *mesh_node1 = NULL;
Eo *mesh = NULL;
Eo *mesh1 = NULL;
Eo *material = NULL;
Eo *material1 = NULL;
Eo *texture = NULL;
Eo *light = NULL;
Ecore_Animator *anim = NULL;
static Eina_Bool
_animate_scene(void *data)
{
static int frame = 0;
eo_do((Evas_3D_Node *)data, evas_3d_node_mesh_frame_set(mesh, frame));
frame += 32;
if (frame > 256 * 50) frame = 0;
return EINA_TRUE;
}
static void
_on_delete(Ecore_Evas *ee EINA_UNUSED)
{
ecore_main_loop_quit();
}
static void
_on_canvas_resize(Ecore_Evas *ee)
{
int w, h;
ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
eo_do(background, evas_obj_size_set(w, h));
eo_do(image, evas_obj_size_set(w, h));
}
static double pi = 3.14159265359;
typedef struct _vec3
{
float x;
float y;
float z;
} vec3;
typedef struct _vec4
{
float x;
float y;
float z;
float w;
} vec4;
static void
_set_ball(Eo *mesh, double r, double x, double y, double z, int p, Evas_3D_Material *material)
{
int vcount, icount, vccount, i, j;
double dtheta, dfi, sinth, costh, fi, theta, sinfi, cosfi;
unsigned short *indices, *index;
icount = p * p * 6;
vccount = p + 1;
vcount = vccount * vccount;
dtheta = pi / p;
dfi = 2 * pi / p;
vec3 *vertices = malloc(sizeof(vec3) * vcount);
vec3 *normals = malloc(sizeof(vec3) * vcount);
for (j = 0; j < vccount; j++)
{
theta = j * dtheta;
sinth = sin(theta);
costh = cos(theta);
for (i = 0; i < vccount; i++)
{
fi = i * dfi;
sinfi = sin(fi);
cosfi = cos(fi);
vertices[i + j * vccount].x = r * sinth * cosfi + x;
vertices[i + j * vccount].y = r * sinth * sinfi + y;
vertices[i + j * vccount].z = r * costh + z;
normals[i + j * vccount].x = sinth * cosfi;
normals[i + j * vccount].y = sinth * sinfi;
normals[i + j * vccount].z = costh;
}
}
indices = malloc(sizeof(short) * icount);
index = &indices[0];
for(j = 0; j < p; j++)
for(i = 0; i < p; i++)
{
*index++ = (unsigned short)(i + vccount * j);
*index++ = i + vccount * (j + 1);
*index++ = i + 1 + vccount * (j + 1);
*index++ = i + vccount * j;
*index++ = i + 1 + vccount * j;
*index++ = i + vccount * (j + 1) + 1;
}
eo_do(mesh, evas_3d_mesh_vertex_count_set(vcount),
evas_3d_mesh_frame_add(0);
evas_3d_mesh_frame_vertex_data_copy_set(0, EVAS_3D_VERTEX_POSITION,
sizeof(vec3), &vertices[0]);
evas_3d_mesh_frame_vertex_data_copy_set(0, EVAS_3D_VERTEX_NORMAL,
sizeof(vec3), &normals[0]);
evas_3d_mesh_index_data_copy_set(EVAS_3D_INDEX_FORMAT_UNSIGNED_SHORT,
icount , &indices[0]);
evas_3d_mesh_vertex_assembly_set(EVAS_3D_VERTEX_ASSEMBLY_TRIANGLES);
evas_3d_mesh_shade_mode_set(EVAS_3D_SHADE_MODE_PHONG);
evas_3d_mesh_frame_material_set(0, material));
free(vertices);
free(normals);
free(indices);
}
int
main(void)
{
//Unless Evas 3D supports Software renderer, we set gl backened forcely.
setenv("ECORE_EVAS_ENGINE", "opengl_x11", 1);
if (!ecore_evas_init()) return 0;
ecore_evas = ecore_evas_new(NULL, 10, 10, WIDTH, HEIGHT, NULL);
if (!ecore_evas) return 0;
ecore_evas_callback_delete_request_set(ecore_evas, _on_delete);
ecore_evas_callback_resize_set(ecore_evas, _on_canvas_resize);
ecore_evas_show(ecore_evas);
evas = ecore_evas_get(ecore_evas);
/* Add a scene object .*/
scene = eo_add(EVAS_3D_SCENE_CLASS, evas);
/* Add the root node for the scene. */
root_node = eo_add_custom(EVAS_3D_NODE_CLASS, evas,
evas_3d_node_constructor(EVAS_3D_NODE_TYPE_NODE));
/* Add the camera. */
camera = eo_add(EVAS_3D_CAMERA_CLASS, evas);
eo_do(camera,
evas_3d_camera_projection_perspective_set(60.0, 1.0, 1.0, 1000.0));
camera_node =
eo_add_custom(EVAS_3D_NODE_CLASS, evas,
evas_3d_node_constructor(EVAS_3D_NODE_TYPE_CAMERA));
eo_do(camera_node,
evas_3d_node_camera_set(camera));
eo_do(root_node,
evas_3d_node_member_add(camera_node));
eo_do(camera_node,
evas_3d_node_position_set(100.0, 0.0, 20.0),
evas_3d_node_look_at_set(EVAS_3D_SPACE_PARENT, 0.0, 0.0, 20.0,
EVAS_3D_SPACE_PARENT, 0.0, 0.0, 1.0));
/* Add the light. */
light = eo_add(EVAS_3D_LIGHT_CLASS, evas);
eo_do(light,
evas_3d_light_ambient_set(0.2, 0.2, 0.2, 1.0),
evas_3d_light_diffuse_set(1.0, 1.0, 1.0, 1.0),
evas_3d_light_specular_set(1.0, 1.0, 1.0, 1.0),
evas_3d_light_projection_perspective_set(45.0, 1.0, 2.0, 1000.0));
light_node =
eo_add_custom(EVAS_3D_NODE_CLASS, evas,
evas_3d_node_constructor(EVAS_3D_NODE_TYPE_LIGHT));
eo_do(light_node,
evas_3d_node_light_set(light),
evas_3d_node_position_set(100.0, 30.0, 20.0),
evas_3d_node_look_at_set(EVAS_3D_SPACE_PARENT, 0.0, 0.0, 20.0,
EVAS_3D_SPACE_PARENT, 0.0, 0.0, 1.0));
eo_do(root_node,
evas_3d_node_member_add(light_node));
/* Add the mesh. */
mesh = eo_add(EVAS_3D_MESH_CLASS, evas);
material = eo_add(EVAS_3D_MATERIAL_CLASS, evas);
eo_do(mesh,
evas_3d_mesh_file_set(EVAS_3D_MESH_FILE_TYPE_MD2, "sonic.md2", NULL),
evas_3d_mesh_frame_material_set(0, material),
evas_3d_mesh_shade_mode_set(EVAS_3D_SHADE_MODE_PHONG));
texture = eo_add(EVAS_3D_TEXTURE_CLASS, evas);
eo_do(texture,
evas_3d_texture_file_set("sonic.png", NULL),
evas_3d_texture_filter_set(EVAS_3D_TEXTURE_FILTER_NEAREST,
EVAS_3D_TEXTURE_FILTER_NEAREST),
evas_3d_texture_wrap_set(EVAS_3D_WRAP_MODE_REPEAT,
EVAS_3D_WRAP_MODE_REPEAT));
eo_do(material,
evas_3d_material_texture_set(EVAS_3D_MATERIAL_DIFFUSE, texture),
evas_3d_material_texture_set(EVAS_3D_MATERIAL_AMBIENT, texture),
evas_3d_material_enable_set(EVAS_3D_MATERIAL_AMBIENT, EINA_TRUE),
evas_3d_material_enable_set(EVAS_3D_MATERIAL_DIFFUSE, EINA_TRUE),
evas_3d_material_enable_set(EVAS_3D_MATERIAL_SPECULAR, EINA_TRUE),
evas_3d_material_enable_set(EVAS_3D_MATERIAL_NORMAL, EINA_TRUE),
evas_3d_material_color_set(EVAS_3D_MATERIAL_AMBIENT,
1.0, 1.0, 1.0, 1.0),
evas_3d_material_color_set(EVAS_3D_MATERIAL_DIFFUSE,
1.0, 1.0, 1.0, 1.0),
evas_3d_material_color_set(EVAS_3D_MATERIAL_SPECULAR,
1.0, 1.0, 1.0, 1.0),
evas_3d_material_shininess_set(50.0));
mesh_node = eo_add_custom(EVAS_3D_NODE_CLASS, evas,
evas_3d_node_constructor(EVAS_3D_NODE_TYPE_MESH));
eo_do(root_node,
evas_3d_node_member_add(mesh_node));
eo_do(mesh_node,
evas_3d_node_mesh_add(mesh));
material1 = eo_add(EVAS_3D_MATERIAL_CLASS, evas);
eo_do(material1,
evas_3d_material_enable_set(EVAS_3D_MATERIAL_AMBIENT, EINA_TRUE),
evas_3d_material_enable_set(EVAS_3D_MATERIAL_DIFFUSE, EINA_TRUE),
evas_3d_material_enable_set(EVAS_3D_MATERIAL_SPECULAR, EINA_TRUE),
evas_3d_material_color_set(EVAS_3D_MATERIAL_AMBIENT, 1.0, 1.0, 1.0, 1.0),
evas_3d_material_color_set(EVAS_3D_MATERIAL_DIFFUSE, 0.8, 0.8, 0.8, 1.0),
evas_3d_material_color_set(EVAS_3D_MATERIAL_SPECULAR, 1.0, 1.0, 1.0, 1.0),
evas_3d_material_shininess_set(100.0));
mesh1 = eo_add(EVAS_3D_MESH_CLASS, evas);
_set_ball(mesh1, 100, -200, 0, 0, 100, material1);
mesh_node1 =
eo_add_custom(EVAS_3D_NODE_CLASS, evas,
evas_3d_node_constructor(EVAS_3D_NODE_TYPE_MESH));
eo_do(root_node, evas_3d_node_member_add(mesh_node1));
eo_do(mesh_node1, evas_3d_node_mesh_add(mesh1));
/* Set up scene. */
eo_do(scene,
evas_3d_scene_root_node_set(root_node),
evas_3d_scene_camera_node_set(camera_node),
evas_3d_scene_size_set(WIDTH, HEIGHT),
evas_3d_scene_shadows_enable_set(EINA_TRUE));
/* Add a background rectangle objects. */
background = eo_add(EVAS_RECTANGLE_CLASS, evas);
eo_unref(background);
eo_do(background,
evas_obj_color_set(0, 0, 0, 255),
evas_obj_size_set(WIDTH, HEIGHT),
evas_obj_visibility_set(EINA_TRUE));
/* Add an image object for 3D scene rendering. */
image = evas_object_image_filled_add(evas);
eo_do(image,
evas_obj_size_set(WIDTH, HEIGHT),
evas_obj_visibility_set(EINA_TRUE));
/* Set the image object as render target for 3D scene. */
eo_do(image, evas_obj_image_scene_set(scene));
/* Add animator. */
ecore_animator_frametime_set(0.008);
anim = ecore_animator_add(_animate_scene, mesh_node);
/* Enter main loop. */
ecore_main_loop_begin();
ecore_evas_free(ecore_evas);
ecore_evas_shutdown();
return 0;
}

View File

@ -465,6 +465,7 @@ typedef enum _Evas_3D_State
EVAS_3D_STATE_SCENE_CAMERA_NODE,
EVAS_3D_STATE_SCENE_BACKGROUND_COLOR,
EVAS_3D_STATE_SCENE_SIZE,
EVAS_3D_STATE_SCENE_SHADOWS_ENABLED,
EVAS_3D_STATE_TEXTURE_DATA = 1,
EVAS_3D_STATE_TEXTURE_WRAP,
@ -493,6 +494,7 @@ typedef enum _Evas_3D_State
EVAS_3D_STATE_LIGHT_SPOT_EXP,
EVAS_3D_STATE_LIGHT_SPOT_CUTOFF,
EVAS_3D_STATE_LIGHT_ATTENUATION,
EVAS_3D_STATE_LIGHT_PROJECTION,
EVAS_3D_STATE_NODE_TRANSFORM = 1,
EVAS_3D_STATE_NODE_MESH_GEOMETRY,
@ -681,7 +683,10 @@ typedef enum _Evas_3D_Shade_Mode
/**< Per-pixel phong shading */
EVAS_3D_SHADE_MODE_PHONG,
/**< Per-pixel normal map shading */
EVAS_3D_SHADE_MODE_NORMAL_MAP
EVAS_3D_SHADE_MODE_NORMAL_MAP,
/**< fragment color is defined by its z-coord*/
EVAS_3D_SHADE_MODE_SHADOW_MAP_RENDER,
} Evas_3D_Shade_Mode;
/**

View File

@ -239,4 +239,56 @@ _evas_3d_light_attenuation_enable_get(Eo *obj EINA_UNUSED, Evas_3D_Light_Data *p
return pd->enable_attenuation;
}
EOLIAN static void
_evas_3d_light_projection_matrix_set(Eo *obj, Evas_3D_Light_Data *pd,
const Evas_Real *matrix)
{
evas_mat4_array_set(&pd->projection, matrix);
eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_LIGHT_PROJECTION, NULL));
}
EOLIAN static void
_evas_3d_light_projection_matrix_get(Eo *obj EINA_UNUSED,
Evas_3D_Light_Data *pd,
Evas_Real *matrix)
{
memcpy(matrix, &pd->projection.m[0], sizeof(Evas_Real) * 16);
}
EOLIAN static void
_evas_3d_light_projection_perspective_set(Eo *obj, Evas_3D_Light_Data *pd,
Evas_Real fovy, Evas_Real aspect,
Evas_Real dnear, Evas_Real dfar)
{
Evas_Real xmax;
Evas_Real ymax;
ymax = dnear * (Evas_Real)tan((double)fovy * M_PI / 360.0);
xmax = ymax * aspect;
evas_mat4_frustum_set(&pd->projection, -xmax, xmax, -ymax, ymax, dnear, dfar);
eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_LIGHT_PROJECTION, NULL));
}
EOLIAN static void
_evas_3d_light_projection_frustum_set(Eo *obj, Evas_3D_Light_Data *pd,
Evas_Real left, Evas_Real right,
Evas_Real bottom, Evas_Real top,
Evas_Real dnear, Evas_Real dfar)
{
evas_mat4_frustum_set(&pd->projection, left, right, bottom, top, dnear, dfar);
eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_LIGHT_PROJECTION, NULL));
}
EOLIAN static void
_evas_3d_light_projection_ortho_set(Eo *obj, Evas_3D_Light_Data *pd,
Evas_Real left, Evas_Real right,
Evas_Real bottom, Evas_Real top,
Evas_Real dnear, Evas_Real dfar)
{
evas_mat4_ortho_set(&pd->projection, left, right, bottom, top, dnear, dfar);
eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_LIGHT_PROJECTION, NULL));
}
#include "canvas/evas_3d_light.eo.c"

View File

@ -249,6 +249,100 @@ class Evas_3D_Light (Evas_3D_Object, Evas.Common_Interface)
@out Evas_Real quadratic; /*@ Quadratic attenuation term..*/
}
}
projection_matrix_set {
/*@
Set the projection matrix of the given light source.
@param light The given light source.
@param matrix Pointer to the array of 16 Evas_Real values in column major order.
Default projection matrix is identity matrix.
@see evas_3d_light_projection_perspective_set()
@see evas_3d_light_projection_ortho_set()
@see evas_3d_light_projection_frustum_set()
@ingroup Evas_3D_Light
*/
params {
@in const(Evas_Real) *matrix; /*@ Projection Matrix */
}
}
projection_matrix_get @const {
/*@
Get the projection matrix of the given light source.
@param light The given light source.
@param matrix Pointer to receive the 16 Evas_Real values in column major order.
@see evas_3d_light_projection_matrix_set()
@ingroup Evas_3D_Light
*/
params {
@out Evas_Real matrix; /*@ Projection Matrix */
}
}
projection_perspective_set {
/*@
Set the projection matrix of the given light source with perspective projection.
@param light The given light source.
@param fovy Field of view angle in Y direction.
@param aspect Aspect ratio.
@param dnear Distance to near clipping plane.
@param dfar Distance to far clipping plane.
@see evas_3d_light_projection_matrix_set()
@ingroup Evas_3D_Light
*/
params {
Evas_Real fovy; /*@ Field of view angle in Y direction. */
Evas_Real aspect; /*@ Aspect ratio.*/
Evas_Real dnear; /*@ Distance to near clipping plane. */
Evas_Real dfar; /*@ Distance to far clipping plane. */
}
}
projection_frustum_set {
/*@
Set the projection matrix of the given light source with frustum projection.
@see evas_3d_Light_projection_matrix_set()
@ingroup Evas_3D_Light
*/
params {
Evas_Real left; /*@ Left X coordinate of the near clipping plane. */
Evas_Real right; /*@ Right X coordinate of the near clipping plane..*/
Evas_Real bottom; /*@ Bottom Y coordinate of the near clipping plane. */
Evas_Real top; /*@ Top Y coordinate of the near clipping plane */
Evas_Real dnear; /*@ Distance to near clipping plane. */
Evas_Real dfar; /*@ Distance to far clipping plane. */
}
}
projection_ortho_set {
/*@
Set the projection matrix of the given light source with orthogonal projection.
@see evas_3d_light_projection_matrix_set()
@ingroup Evas_3D_Light
*/
params {
Evas_Real left; /*@ Left X coordinate of the near clipping plane. */
Evas_Real right; /*@ Right X coordinate of the near clipping plane..*/
Evas_Real bottom; /*@ Bottom Y coordinate of the near clipping plane. */
Evas_Real top; /*@ Top Y coordinate of the near clipping plane */
Evas_Real dnear; /*@ Distance to near clipping plane. */
Evas_Real dfar; /*@ Distance to far clipping plane. */
}
}
}
implements {

View File

@ -65,6 +65,7 @@ _evas_3d_scene_eo_base_constructor(Eo *obj, Evas_3D_Scene_Data *pd)
eo_do_super(obj, MY_CLASS, eo_constructor());
eo_do(obj, evas_3d_object_type_set(EVAS_3D_OBJECT_TYPE_SCENE));
evas_color_set(&pd->bg_color, 0.0, 0.0, 0.0, 0.0);
pd->shadows_enabled = EINA_FALSE;
}
EOLIAN static void
@ -710,4 +711,17 @@ _evas_3d_scene_pick_member_list_get(Eo *obj, Evas_3D_Scene_Data *pd, Evas_Real x
return picked_nodes;
}
EOLIAN static Eina_Bool
_evas_3d_scene_shadows_enable_get(Eo *obj EINA_UNUSED, Evas_3D_Scene_Data *pd)
{
return pd->shadows_enabled;
}
EOLIAN static void
_evas_3d_scene_shadows_enable_set(Eo *obj EINA_UNUSED, Evas_3D_Scene_Data *pd, Eina_Bool _shadows_enabled)
{
pd->shadows_enabled = _shadows_enabled;
eo_do(obj, evas_3d_object_change(EVAS_3D_STATE_SCENE_SHADOWS_ENABLED, NULL));
}
#include "canvas/evas_3d_scene.eo.c"

View File

@ -111,6 +111,31 @@ class Evas_3D_Scene (Evas_3D_Object, Evas.Common_Interface)
@in Evas_Real y; /*@ Y coordinate of the picking position. */
}
}
shadows_enable_set {
/*
Enable or disable shadows on given scene
If shadows_enabled @c EINA_TRUE, the objects in the scene can throw shadow to another objects located behind them.
The depth map used for shading. Directed and projective light sources are supported.
@ingroup Evas_3D_Scene
*/
params {
@in Eina_Bool shadows_enabled; /*@ shadows enabled status. */
}
}
shadows_enable_get @const {
/*
Get shadows enabled status for given scene.
@return The shadows enabled status.
@ingroup Evas_3D_Scene
*/
return: Eina_Bool;
params {
}
}
}
properties {

View File

@ -2582,6 +2582,7 @@ _3d_render(Evas *eo_e, Evas_Object *eo_obj EINA_UNUSED,
evas_3d_scene_data_init(&scene_data);
scene_data.bg_color = pd_scene->bg_color;
scene_data.shadows_enabled = pd_scene->shadows_enabled;
scene_data.camera_node = pd_scene->camera_node;
/* Phase 1 - Update scene graph tree. */

View File

@ -108,11 +108,12 @@ struct _Evas_3D_Scene
{
Evas_3D_Node *root_node;
Evas_3D_Node *camera_node;
Evas_Color bg_color;
Evas_Color bg_color;
void *surface;
int w, h;
Eina_List *images;
Eina_Bool shadows_enabled :1;
};
struct _Evas_3D_Node_Mesh
@ -191,6 +192,7 @@ struct _Evas_3D_Light
Evas_Real atten_const;
Evas_Real atten_linear;
Evas_Real atten_quad;
Evas_Mat4 projection;
Eina_Hash *nodes;
};
@ -247,6 +249,7 @@ struct _Evas_3D_Mesh
Evas_3D_Vertex_Assembly assembly;
Eina_Hash *nodes;
Eina_Bool shadowed;
Evas_Color fog_color;
Eina_Bool fog_enabled :1;
@ -285,6 +288,7 @@ struct _Evas_3D_Scene_Public_Data
Evas_3D_Node *camera_node;
Eina_List *light_nodes;
Eina_List *mesh_nodes;
Eina_Bool shadows_enabled :1;
};
struct _Evas_3D_Pick_Data

View File

@ -407,7 +407,7 @@ E3D_Drawable *
e3d_drawable_new(int w, int h, int alpha, GLenum depth_format, GLenum stencil_format)
{
E3D_Drawable *drawable = NULL;
GLuint tex, fbo;
GLuint tex, fbo, texDepth;
GLuint depth_stencil_buf = 0;
GLuint depth_buf = 0;
GLuint stencil_buf = 0;
@ -425,6 +425,14 @@ e3d_drawable_new(int w, int h, int alpha, GLenum depth_format, GLenum stencil_fo
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glGenTextures(1, &texDepth);
glBindTexture(GL_TEXTURE_2D, texDepth);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16, w, h, 0, GL_RGB, GL_UNSIGNED_SHORT, 0);
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
@ -503,6 +511,7 @@ e3d_drawable_new(int w, int h, int alpha, GLenum depth_format, GLenum stencil_fo
drawable->depth_stencil_buf = depth_stencil_buf;
drawable->depth_buf = depth_buf;
drawable->stencil_buf = stencil_buf;
drawable->texDepth = texDepth;
return drawable;
@ -1076,6 +1085,7 @@ _mesh_draw_data_build(E3D_Draw_Data *data,
const Evas_Mat4 *matrix_eye,
const Evas_Mat4 *matrix_mv,
const Evas_Mat4 *matrix_mvp,
const Evas_Mat4 *matrix_light,
const Evas_3D_Node *light)
{
Eina_List *l, *r;
@ -1089,6 +1099,10 @@ _mesh_draw_data_build(E3D_Draw_Data *data,
data->flags |= E3D_SHADER_FLAG_FOG_ENABLED;
data->fog_color = pdmesh->fog_color;
}
if (pdmesh->shadowed)
data->flags |= E3D_SHADER_FLAG_SHADOWED;
data->mode = pdmesh->shade_mode;
data->assembly = pdmesh->assembly;
data->vertex_count = pdmesh->vertex_count;
@ -1098,6 +1112,8 @@ _mesh_draw_data_build(E3D_Draw_Data *data,
evas_mat4_copy(&data->matrix_mvp, matrix_mvp);
evas_mat4_copy(&data->matrix_mv, matrix_mv);
if (matrix_light != NULL)
evas_mat4_copy(&data->matrix_light, matrix_light);
_mesh_frame_find(mesh, frame, &l, &r);
@ -1116,6 +1132,10 @@ _mesh_draw_data_build(E3D_Draw_Data *data,
BUILD(vertex_attrib, VERTEX_POSITION, EINA_TRUE);
BUILD(vertex_attrib, VERTEX_COLOR, EINA_TRUE);
}
else if (pdmesh->shade_mode == EVAS_3D_SHADE_MODE_SHADOW_MAP_RENDER)
{
BUILD(vertex_attrib, VERTEX_POSITION, EINA_TRUE);
}
else if (pdmesh->shade_mode == EVAS_3D_SHADE_MODE_DIFFUSE)
{
BUILD(vertex_attrib, VERTEX_POSITION, EINA_TRUE);
@ -1189,21 +1209,72 @@ _mesh_draw_data_build(E3D_Draw_Data *data,
evas_normal_matrix_get(&data->matrix_normal, matrix_mv);
}
// TODO Add correct numbering
int num;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &num);
data->smap_sampler = num - 1;
return EINA_TRUE;
}
static inline void
_mesh_draw(E3D_Renderer *renderer, Evas_3D_Mesh *mesh, int frame, Evas_3D_Node *light,
const Evas_Mat4 *matrix_eye, const Evas_Mat4 *matrix_mv, const Evas_Mat4 *matrix_mvp)
const Evas_Mat4 *matrix_eye, const Evas_Mat4 *matrix_mv, const Evas_Mat4 *matrix_mvp, const Evas_Mat4 *matrix_light)
{
E3D_Draw_Data data;
memset(&data, 0x00, sizeof(E3D_Draw_Data));
if (_mesh_draw_data_build(&data, mesh, frame, matrix_eye, matrix_mv, matrix_mvp, light))
if (_mesh_draw_data_build(&data, mesh, frame, matrix_eye, matrix_mv, matrix_mvp, matrix_light, light))
e3d_renderer_draw(renderer, &data);
}
void _shadowmap_render(E3D_Drawable *drawable, E3D_Renderer *renderer, Evas_3D_Scene_Public_Data *data, Evas_Mat4 *matrix_light_eye, Evas_3D_Node *light)
{
Eina_List *l;
Evas_3D_Node *n;
Evas_3D_Shade_Mode shade_mode;
Evas_Color c = {1.0, 1.0, 1.0};
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(4.0, 10000.0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawable->texDepth, 0);
e3d_renderer_target_set(renderer, drawable);
e3d_renderer_clear(renderer, &c);
Evas_3D_Node_Data *pd_light_node = eo_data_scope_get(light, EVAS_3D_NODE_CLASS);
Evas_3D_Light_Data *pd = eo_data_scope_get(pd_light_node->data.light.light, EVAS_3D_LIGHT_CLASS);
EINA_LIST_FOREACH(data->mesh_nodes, l, n)
{
Evas_Mat4 matrix_mv;
Evas_Mat4 matrix_mvp;
Eina_Iterator *it;
void *ptr;
Evas_3D_Node_Data *pd_mesh_node = eo_data_scope_get(n, EVAS_3D_NODE_CLASS);
evas_mat4_multiply(&matrix_mv, matrix_light_eye, &pd_mesh_node->data.mesh.matrix_local_to_world);
evas_mat4_multiply(&matrix_mvp, &pd->projection,
&matrix_mv);
it = eina_hash_iterator_data_new(pd_mesh_node->data.mesh.node_meshes);
while (eina_iterator_next(it, &ptr))
{
Evas_3D_Node_Mesh *nm = (Evas_3D_Node_Mesh *)ptr;
Evas_3D_Mesh_Data *pdmesh = eo_data_scope_get(nm->mesh, EVAS_3D_MESH_CLASS);
shade_mode = pdmesh->shade_mode;
pdmesh->shade_mode = EVAS_3D_SHADE_MODE_SHADOW_MAP_RENDER;
_mesh_draw(renderer, nm->mesh, nm->frame, light, matrix_light_eye, &matrix_mv, &matrix_mvp, &matrix_mvp);
pdmesh->shade_mode = shade_mode;
}
eina_iterator_free(it);
}
glDisable(GL_POLYGON_OFFSET_FILL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, drawable->tex, 0);
}
void
e3d_drawable_scene_render(E3D_Drawable *drawable, E3D_Renderer *renderer, Evas_3D_Scene_Public_Data *data)
{
@ -1211,10 +1282,9 @@ e3d_drawable_scene_render(E3D_Drawable *drawable, E3D_Renderer *renderer, Evas_3
Evas_3D_Node *n;
const Evas_Mat4 *matrix_eye;
Evas_3D_Node *light;
/* Set up render target. */
e3d_renderer_target_set(renderer, drawable);
e3d_renderer_clear(renderer, &data->bg_color);
Evas_Mat4 matrix_light_eye;
Evas_3D_Light_Data *ld;
Evas_3D_Node_Data *pd_light_node;
/* Get eye matrix. */
Evas_3D_Node_Data *pd_camera_node = eo_data_scope_get(data->camera_node, EVAS_3D_NODE_CLASS);
@ -1222,27 +1292,54 @@ e3d_drawable_scene_render(E3D_Drawable *drawable, E3D_Renderer *renderer, Evas_3
Evas_3D_Camera_Data *pd = eo_data_scope_get(pd_camera_node->data.camera.camera, EVAS_3D_CAMERA_CLASS);
light = eina_list_data_get(data->light_nodes);
if (data->shadows_enabled)
{
pd_light_node = eo_data_scope_get(light, EVAS_3D_NODE_CLASS);
evas_mat4_inverse_build(&matrix_light_eye,
&pd_light_node->position_world, &pd_light_node ->orientation_world, &pd_light_node->scale_world);
ld = eo_data_scope_get(pd_light_node->data.light.light, EVAS_3D_LIGHT_CLASS);
_shadowmap_render(drawable, renderer, data, &matrix_light_eye, light);
}
/* Set up render target. */
e3d_renderer_target_set(renderer, drawable);
e3d_renderer_clear(renderer, &data->bg_color);
EINA_LIST_FOREACH(data->mesh_nodes, l, n)
{
Evas_Mat4 matrix_mv;
Evas_Mat4 matrix_light;
Evas_Mat4 matrix_mvp;
Eina_Iterator *it;
void *ptr;
Evas_3D_Node_Data *pd_mesh_node = eo_data_scope_get(n, EVAS_3D_NODE_CLASS);
if (data->shadows_enabled)
{
evas_mat4_multiply(&matrix_mv, &matrix_light_eye,
&pd_mesh_node->data.mesh.matrix_local_to_world);
evas_mat4_multiply(&matrix_light, &ld->projection,
&matrix_mv);
}
evas_mat4_multiply(&matrix_mv, matrix_eye, &pd_mesh_node->data.mesh.matrix_local_to_world);
evas_mat4_multiply(&matrix_mvp, matrix_eye, &matrix_mv);
evas_mat4_multiply(&matrix_mvp, &pd->projection,
&matrix_mv);
/* TODO: Get most effective light node. */
light = eina_list_data_get(data->light_nodes);
it = eina_hash_iterator_data_new(pd_mesh_node->data.mesh.node_meshes);
while (eina_iterator_next(it, &ptr))
{
Evas_3D_Node_Mesh *nm = (Evas_3D_Node_Mesh *)ptr;
_mesh_draw(renderer, nm->mesh, nm->frame, light, matrix_eye, &matrix_mv, &matrix_mvp);
Evas_3D_Mesh_Data *pdmesh = eo_data_scope_get(nm->mesh, EVAS_3D_MESH_CLASS);
if (data->shadows_enabled)
{
pdmesh->shadowed = EINA_TRUE;
_mesh_draw(renderer, nm->mesh, nm->frame, light, matrix_eye, &matrix_mv, &matrix_mvp, &matrix_light);
pdmesh->shadowed = EINA_FALSE;
}
else _mesh_draw(renderer, nm->mesh, nm->frame, light, matrix_eye, &matrix_mv, &matrix_mvp, NULL);
}
eina_iterator_free(it);

View File

@ -36,6 +36,8 @@ typedef unsigned long E3D_Shader_Flag;
#define E3D_SHADER_FLAG_EMISSION_TEXTURE_BLEND (1 << 27)
#define E3D_SHADER_FLAG_NORMAL_TEXTURE_BLEND (1 << 28)
#define E3D_SHADER_FLAG_FOG_ENABLED (1 << 29)
#define E3D_SHADER_FLAG_SHADOWED (1 << 30)
static inline Eina_Bool
_flags_need_tex_coord(E3D_Shader_Flag flags)
@ -55,6 +57,7 @@ struct _E3D_Draw_Data
Evas_Mat4 matrix_mvp;
Evas_Mat4 matrix_mv;
Evas_Mat3 matrix_normal;
Evas_Mat4 matrix_light;
struct {
Evas_3D_Vertex_Buffer vertex0;
@ -81,6 +84,8 @@ struct _E3D_Draw_Data
Evas_Real shininess;
GLint smap_sampler;
struct {
Evas_Vec4 position;
Evas_Vec3 spot_dir;
@ -124,6 +129,7 @@ struct _E3D_Drawable
GLuint depth_stencil_buf;
GLuint depth_buf;
GLuint stencil_buf;
GLuint texDepth;
};
/* Texture internal functions. */

View File

@ -14,6 +14,7 @@ struct _E3D_Renderer
Eina_Bool vertex_attrib_enable[E3D_MAX_VERTEX_ATTRIB_COUNT];
Eina_Bool depth_test_enable;
GLuint texDepth;
};
static inline GLenum
@ -132,6 +133,8 @@ _renderer_texture_bind(E3D_Renderer *renderer, E3D_Draw_Data *data)
}
}
}
glActiveTexture(GL_TEXTURE0 + data->smap_sampler);
glBindTexture(GL_TEXTURE_2D, renderer->texDepth);
}
static inline void
@ -192,6 +195,7 @@ e3d_renderer_target_set(E3D_Renderer *renderer, E3D_Drawable *target)
glBindFramebuffer(GL_FRAMEBUFFER, target->fbo);
glViewport(0, 0, target->w, target->h);
renderer->fbo = target->fbo;
renderer->texDepth = target->texDepth;
}
void
@ -235,6 +239,7 @@ e3d_renderer_draw(E3D_Renderer *renderer, E3D_Draw_Data *data)
_renderer_program_use(renderer, program);
e3d_program_uniform_upload(program, data);
if (data->mode != EVAS_3D_SHADE_MODE_SHADOW_MAP_RENDER)
_renderer_texture_bind(renderer, data);
/* Set up vertex attrib pointers. */

View File

@ -5,6 +5,7 @@ typedef enum _E3D_Uniform
E3D_UNIFORM_MATRIX_MVP,
E3D_UNIFORM_MATRIX_MV,
E3D_UNIFORM_MATRIX_NORMAL,
E3D_UNIFORM_MATRIX_LIGHT,
E3D_UNIFORM_POSITION_WEIGHT,
E3D_UNIFORM_NORMAL_WEIGHT,
@ -30,6 +31,8 @@ typedef enum _E3D_Uniform
E3D_UNIFORM_TEXTURE_EMISSION1,
E3D_UNIFORM_TEXTURE_NORMAL1,
E3D_UNIFORM_SHADOWMAP,
E3D_UNIFORM_LIGHT_POSITION,
E3D_UNIFORM_LIGHT_SPOT_DIR,
E3D_UNIFORM_LIGHT_SPOT_EXP,
@ -121,6 +124,12 @@ _vertex_shader_string_variable_add(E3D_Shader_String *shader,
{
ADD_LINE("uniform mat4 uMatrixMvp;");
if (flags & E3D_SHADER_FLAG_SHADOWED)
{
ADD_LINE("uniform mat4 uMatrixLight;");
ADD_LINE("varying vec4 lpos;");
}
/* Vertex attributes. */
if (flags & E3D_SHADER_FLAG_VERTEX_POSITION)
ADD_LINE("attribute vec4 aPosition0;");
@ -131,6 +140,8 @@ _vertex_shader_string_variable_add(E3D_Shader_String *shader,
ADD_LINE("uniform float uPositionWeight;");
}
else if (mode == EVAS_3D_SHADE_MODE_SHADOW_MAP_RENDER) return;
if (flags & E3D_SHADER_FLAG_VERTEX_NORMAL)
ADD_LINE("attribute vec4 aNormal0;");
@ -488,6 +499,11 @@ _vertex_shader_string_get(E3D_Shader_String *shader,
ADD_LINE("vertexNormalMap(position, normal);");
}
if (flags & E3D_SHADER_FLAG_SHADOWED)
{
ADD_LINE("lpos = uMatrixLight * vec4(aPosition0.xyz, 1.0);");
}
ADD_LINE("}");
}
@ -504,6 +520,11 @@ _fragment_shader_string_variable_add(E3D_Shader_String *shader,
ADD_LINE("uniform float uFogFactor;");
ADD_LINE("uniform vec4 uFogColor;");
}
if (flags & E3D_SHADER_FLAG_SHADOWED)
{
ADD_LINE("varying vec4 lpos;");
ADD_LINE("uniform sampler2D uShadowMap;");
}
/* Materials. */
if (flags & E3D_SHADER_FLAG_DIFFUSE)
@ -689,6 +710,11 @@ _fragment_shader_string_func_flat_add(E3D_Shader_String *shader,
ADD_LINE("gl_FragColor += uLightSpecular * color * vFactor.y;");
}
if (flags & E3D_SHADER_FLAG_SHADOWED)
{
ADD_LINE("gl_FragColor *= shadow;");
}
if (flags & E3D_SHADER_FLAG_AMBIENT)
{
if (flags & E3D_SHADER_FLAG_AMBIENT_TEXTURE_BLEND)
@ -807,6 +833,11 @@ _fragment_shader_string_func_phong_add(E3D_Shader_String *shader,
ADD_LINE("gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);");
ADD_LINE("}");
if (flags & E3D_SHADER_FLAG_SHADOWED)
{
ADD_LINE("gl_FragColor *= shadow;");
}
/* Ambient term. */
if (flags & E3D_SHADER_FLAG_AMBIENT)
{
@ -971,6 +1002,11 @@ _fragment_shader_string_func_normal_map_add(E3D_Shader_String *shader,
ADD_LINE("}");
}
if (flags & E3D_SHADER_FLAG_SHADOWED)
{
ADD_LINE("gl_FragColor *= shadow;");
}
ADD_LINE("} else {");
ADD_LINE("gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);");
ADD_LINE("}");
@ -1023,13 +1059,35 @@ _fragment_shader_string_func_normal_map_add(E3D_Shader_String *shader,
ADD_LINE("}");
}
static void
_fragment_shader_string_pcf_even_func_add(E3D_Shader_String *shader,
Evas_3D_Shade_Mode mode EINA_UNUSED,
E3D_Shader_Flag flags EINA_UNUSED)
{
ADD_LINE("float pcf(vec4 lpos, float size)");
ADD_LINE("{");
ADD_LINE("vec3 smcoord = lpos.xyz / lpos.w * 0.5 + 0.5;");
ADD_LINE("float i, j, randx, randy, shadow;");
ADD_LINE("shadow = 0.0;");
ADD_LINE("for (i = -4.0; i < 4.0; i++)");
ADD_LINE("for (j = -4.0; j < 4.0; j++)");
ADD_LINE("{");
ADD_LINE("shadow += float(smcoord.z <= texture2D(uShadowMap, smcoord.xy +vec2(i / 8.0, j / 8.0)*size).x);");
ADD_LINE("}");
ADD_LINE("return shadow / 64.0;");
ADD_LINE("}");
}
static void
_fragment_shader_string_get(E3D_Shader_String *shader,
Evas_3D_Shade_Mode mode, E3D_Shader_Flag flags)
{
/* Add variables - vertex attributes. */
_fragment_shader_string_variable_add(shader, mode, flags);
if (flags & E3D_SHADER_FLAG_SHADOWED)
{
ADD_LINE("float shadow;");
}
/* Add functions. */
if (mode == EVAS_3D_SHADE_MODE_FLAT)
_fragment_shader_string_func_flat_add(shader, mode, flags);
@ -1038,8 +1096,16 @@ _fragment_shader_string_get(E3D_Shader_String *shader,
else if (mode == EVAS_3D_SHADE_MODE_NORMAL_MAP)
_fragment_shader_string_func_normal_map_add(shader, mode, flags);
// TODO Add flexible bluring algorithm of shadows boundaries.
if (flags & E3D_SHADER_FLAG_SHADOWED)
_fragment_shader_string_pcf_even_func_add(shader, mode, flags);
/* Add main function. */
ADD_LINE("void main() {");
if (flags & E3D_SHADER_FLAG_SHADOWED)
{
ADD_LINE("shadow = pcf(lpos, 1.0 / 200.0);");
}
if (mode == EVAS_3D_SHADE_MODE_VERTEX_COLOR)
{
@ -1062,6 +1128,10 @@ _fragment_shader_string_get(E3D_Shader_String *shader,
ADD_LINE("gl_FragColor = uMaterialDiffuse;");
}
}
else if(mode == EVAS_3D_SHADE_MODE_SHADOW_MAP_RENDER)
{
ADD_LINE("gl_FragColor = vec4(gl_FragCoord.z);");
}
else if (mode == EVAS_3D_SHADE_MODE_FLAT)
{
ADD_LINE("fragmentFlat();");
@ -1217,6 +1287,7 @@ static const char *uniform_names[] =
"uMatrixMvp",
"uMatrixModelview",
"uMatrixNormal",
"uMatrixLight",
"uPositionWeight",
"uNormalWeight",
"uTangentWeight",
@ -1237,6 +1308,7 @@ static const char *uniform_names[] =
"uTextureSpecular1",
"uTextureEmission1",
"uTextureNormal1",
"uShadowMap",
"uLightPosition",
"uLightSpotDir",
"uLightSpotExp",
@ -1290,6 +1362,13 @@ _uniform_upload(E3D_Uniform u, GLint loc, const E3D_Draw_Data *data)
glUniformMatrix3fv(loc, 1, EINA_FALSE, &m[0]);
break;
}
case E3D_UNIFORM_MATRIX_LIGHT: {
float m[16];
for(int i = 0 ; i <16 ; i++)
m[i] = data->matrix_light.m[i];
glUniformMatrix4fv(loc, 1, EINA_FALSE, &m[0]);
break;
}
case E3D_UNIFORM_POSITION_WEIGHT:
glUniform1f(loc, data->vertices[EVAS_3D_VERTEX_POSITION].weight);
break;
@ -1350,6 +1429,9 @@ _uniform_upload(E3D_Uniform u, GLint loc, const E3D_Draw_Data *data)
case E3D_UNIFORM_TEXTURE_NORMAL1:
glUniform1i(loc, data->materials[EVAS_3D_MATERIAL_NORMAL].sampler1);
break;
case E3D_UNIFORM_SHADOWMAP:
glUniform1i(loc, data->smap_sampler);
break;
case E3D_UNIFORM_LIGHT_POSITION:
glUniform4f(loc, data->light.position.x, data->light.position.y,
data->light.position.z, data->light.position.w);