(Code)
 
(9 intermediate revisions by the same user not shown)
Line 3: Line 3:
 
Demo in blender.
 
Demo in blender.
  
<html><iframe src="https://player.vimeo.com/video/249526108?title=0&byline=0&portrait=0" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></html>
+
<html><iframe src="https://player.vimeo.com/video/249526108?title=0&byline=0&portrait=0" width="960" height="540" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe></html>
  
First generated file.
+
[[File:Normal-map-generation desktop.png|500px]]
  
[[File:Normal map generated with processing.png|200px]]
+
== Principles ==
 
+
== Code ==
+
  
 
To achieve the "engravement" effect, rectangles must be drawn using the following rule:
 
To achieve the "engravement" effect, rectangles must be drawn using the following rule:
Line 16: Line 14:
 
* angles in X and Y are limited to the range [-90°, 90°], represented as the color range [0, 255].
 
* angles in X and Y are limited to the range [-90°, 90°], represented as the color range [0, 255].
 
* therefore, an angle of -45° on X is represented by the red value 64, by making 127 - 63
 
* therefore, an angle of -45° on X is represented by the red value 64, by making 127 - 63
* to draw an engraved line, you need to take into account the direction of the line, as it will influence the X and Y slopes.
+
* to draw an engraved line, you need to process the line direction, as it will influence the X and Y slopes.
 +
 
  
 
[[File:Normalhow01.jpg|300px]]
 
[[File:Normalhow01.jpg|300px]]
  
 
thanks to [http://online.ts2009.com/mediaWiki/index.php/Normal_map Trainz Wiki] for this very usefull schema!
 
thanks to [http://online.ts2009.com/mediaWiki/index.php/Normal_map Trainz Wiki] for this very usefull schema!
 +
 +
== Code ==
 +
 +
This code comes from processing (java). But it can be easily adapted to other languages. Please take into account that this code '''is not optimised''' for realtime use! This part will come next time I'll work on this topic.
 +
 +
The 3 static int at the beginning of the code correspond to these effects, demonstrated in 5 and 50 pixels width.
 +
 +
[[File:Normal map tuto.png]]
 +
 +
See blender sculpture tools for naming convention:
 +
[[File:Blender scult tool.png|200px]]
 +
 +
static final int COLOR_PINCH = 0;
 +
static final int COLOR_DEEPEN = 1;
 +
static final int COLOR_STRAIGHT = 2;
 +
 +
public void pinch( PVector dir, float depth, float percent ) {
 +
    float sm = pow( 1 - ( 1 + sin( -HALF_PI + percent * PI ) ) * 0.5, 2 );
 +
    float m = pow( percent, 2 );
 +
    float red = 127 - dir.y * depth * sm;
 +
    float green = 127 - dir.x * depth * sm;
 +
    fill( red, green, 255, 255 - m * 255 );
 +
}
 +
 +
public void deepen( PVector dir, float depth, float percent ) {
 +
    float sm = ( 1 + sin( -HALF_PI + percent * PI ) ) * 0.5;
 +
    float m = pow( percent, 2 );
 +
    float red = 127 - dir.y * depth * sm;
 +
    float green = 127 - dir.x * depth * sm;
 +
    fill( red, green, 255, 255 - m * 255 );
 +
}
 +
 +
public void straight( PVector dir, float depth, float percent ) {
 +
    float sm = 1;
 +
    float m = pow( percent, 10 );
 +
    float red = 127 - dir.y * depth * sm;
 +
    float green = 127 - dir.x * depth * sm;
 +
    fill( red, green, 255, 255 - m * 255 );
 +
}
 +
 +
public void drawBevel( float x1, float y1, float x2, float y2, float thickness, float depth, int type ) {
 +
  PVector dir = new PVector( x2 - x1, y2 - y1 );
 +
  dir.normalize();
 +
  PVector diri = new PVector( dir.x, dir.y );
 +
  diri.mult( -1 );
 +
  PVector perp = new PVector( dir.x, dir.y );
 +
  perp.rotate(HALF_PI);
 +
  noStroke();
 +
  float thalf = thickness * 0.5;
 +
  float tgap = thickness * 0.01;
 +
  for( float t = thalf; t > tgap; t -= tgap ) {
 +
    float nextt = t - tgap;
 +
   
 +
    switch( type ) {
 +
      case COLOR_PINCH:
 +
        pinch( dir, depth, (t / thalf) );
 +
        break;
 +
      case COLOR_DEEPEN:
 +
        deepen( dir, depth, (t / thalf) );
 +
        break;
 +
      case COLOR_STRAIGHT:
 +
        straight( dir, depth, (t / thalf) );
 +
        break;
 +
      default:
 +
        fill( 0, 0, 255, 255 );
 +
        break;
 +
    }
 +
    beginShape();
 +
      vertex( x1 - perp.x * t, y1 - perp.y * t );
 +
      vertex( x1 - perp.x * nextt, y1 - perp.y * nextt );
 +
      vertex( x2 - perp.x * nextt, y2 - perp.y * nextt );
 +
      vertex( x2 - perp.x * t, y2 - perp.y * t );
 +
    endShape();
 +
   
 +
    switch( type ) {
 +
      case COLOR_PINCH:
 +
        pinch( diri, depth, (t / thalf) );
 +
        break;
 +
      case COLOR_DEEPEN:
 +
        deepen( diri, depth, (t / thalf) );
 +
        break;
 +
      case COLOR_STRAIGHT:
 +
        straight( diri, depth, (t / thalf) );
 +
        break;
 +
      default:
 +
        fill( 0, 0, 255, 255 );
 +
        break;
 +
    }
 +
    beginShape();
 +
      vertex( x1 + perp.x * t, y1 + perp.y * t );
 +
      vertex( x1 + perp.x * nextt, y1 + perp.y * nextt );
 +
      vertex( x2 + perp.x * nextt, y2 + perp.y * nextt );
 +
      vertex( x2 + perp.x * t, y2 + perp.y * t );
 +
    endShape();
 +
   
 +
  }
 +
}
  
 
== References ==
 
== References ==
 
* http://online.ts2009.com/mediaWiki/index.php/Normal_map
 
* http://online.ts2009.com/mediaWiki/index.php/Normal_map
 
* https://www.katsbits.com/tutorials/textures/making-normal-maps-from-photographs.php
 
* https://www.katsbits.com/tutorials/textures/making-normal-maps-from-photographs.php
 +
 +
[[category:generative]]
 +
[[category:Code snippet‏‎]]
 +
[[category:blender‏‎]]
 +
[[category:3D]]
 +
[[category:processing.org]]
 +
[[category:notes]]
 +
[[category:algorithm]]

Latest revision as of 16:59, 3 January 2018

Generation of animated normal maps using processing, experimentation phase.

Demo in blender.

Normal-map-generation desktop.png

Principles

To achieve the "engravement" effect, rectangles must be drawn using the following rule:

  • a straight surface has no X or Y slope of 0°, its color is thus RGB( 127, 127, 255 )
  • angles in X and Y are limited to the range [-90°, 90°], represented as the color range [0, 255].
  • therefore, an angle of -45° on X is represented by the red value 64, by making 127 - 63
  • to draw an engraved line, you need to process the line direction, as it will influence the X and Y slopes.


Normalhow01.jpg

thanks to Trainz Wiki for this very usefull schema!

Code

This code comes from processing (java). But it can be easily adapted to other languages. Please take into account that this code is not optimised for realtime use! This part will come next time I'll work on this topic.

The 3 static int at the beginning of the code correspond to these effects, demonstrated in 5 and 50 pixels width.

Normal map tuto.png

See blender sculpture tools for naming convention: Blender scult tool.png

static final int COLOR_PINCH = 0;
static final int COLOR_DEEPEN = 1;
static final int COLOR_STRAIGHT = 2;

public void pinch( PVector dir, float depth, float percent ) {
   float sm = pow( 1 - ( 1 + sin( -HALF_PI + percent * PI ) ) * 0.5, 2 );
   float m = pow( percent, 2 );
   float red = 127 - dir.y * depth * sm;
   float green = 127 - dir.x * depth * sm;
   fill( red, green, 255, 255 - m * 255 );
}

public void deepen( PVector dir, float depth, float percent ) {
   float sm = ( 1 + sin( -HALF_PI + percent * PI ) ) * 0.5;
   float m = pow( percent, 2 );
   float red = 127 - dir.y * depth * sm;
   float green = 127 - dir.x * depth * sm;
   fill( red, green, 255, 255 - m * 255 );
}

public void straight( PVector dir, float depth, float percent ) {
   float sm = 1;
   float m = pow( percent, 10 );
   float red = 127 - dir.y * depth * sm;
   float green = 127 - dir.x * depth * sm;
   fill( red, green, 255, 255 - m * 255 );
}

public void drawBevel( float x1, float y1, float x2, float y2, float thickness, float depth, int type ) {
 PVector dir = new PVector( x2 - x1, y2 - y1 );
 dir.normalize();
 PVector diri = new PVector( dir.x, dir.y );
 diri.mult( -1 );
 PVector perp = new PVector( dir.x, dir.y );
 perp.rotate(HALF_PI);
 noStroke();
 float thalf = thickness * 0.5;
 float tgap = thickness * 0.01;
 for( float t = thalf; t > tgap; t -= tgap ) {
   float nextt = t - tgap;
   
   switch( type ) {
     case COLOR_PINCH:
       pinch( dir, depth, (t / thalf) );
       break;
     case COLOR_DEEPEN:
       deepen( dir, depth, (t / thalf) );
       break;
     case COLOR_STRAIGHT:
       straight( dir, depth, (t / thalf) );
       break;
     default:
       fill( 0, 0, 255, 255 );
       break;
   }
   beginShape();
     vertex( x1 - perp.x * t, y1 - perp.y * t );
     vertex( x1 - perp.x * nextt, y1 - perp.y * nextt );
     vertex( x2 - perp.x * nextt, y2 - perp.y * nextt );
     vertex( x2 - perp.x * t, y2 - perp.y * t );
   endShape();
   
   switch( type ) {
     case COLOR_PINCH:
       pinch( diri, depth, (t / thalf) );
       break;
     case COLOR_DEEPEN:
       deepen( diri, depth, (t / thalf) );
       break;
     case COLOR_STRAIGHT:
       straight( diri, depth, (t / thalf) );
       break;
     default:
       fill( 0, 0, 255, 255 );
       break;
   }
   beginShape();
     vertex( x1 + perp.x * t, y1 + perp.y * t );
     vertex( x1 + perp.x * nextt, y1 + perp.y * nextt );
     vertex( x2 + perp.x * nextt, y2 + perp.y * nextt );
     vertex( x2 + perp.x * t, y2 + perp.y * t );
   endShape();
   
 }
}

References

online identity ∋ [ social ∋ [mastodon♥, twitter®, facebook®, diaspora, linkedin®] ∥ repos ∋ [github®, gitlab♥, bitbucket®, sourceforge] ∥ media ∋ [itch.io®, vimeo®, peertube♥, twitch.tv®, tumblr®] ∥ communities ∋ [godotengine♥, openprocessing, stackoverflow, threejs]]