I am trying to render Blinn Phong as a BRDF model on a surface plane. I assume that every normal in every pixel is perpendicular with the plane. I know that to do a rendering we have to use 3d programing API such as OpenGL or WebGL and so on.
My purpose is to render the surface plane without those APIs. The steps that I take are, I create 2 spaces:

  1. image space: (0,0) is at the top left of the image.
  2. camera space: (0,0) is at the middle of the image.

For vector computation, I convert every pixel position of image space to camera space then to world space.

double[] cam=((new double[]{0,0,1}));
double[] lum=((new double[]{0,0,1}));
double[] E=new double[3];
double[] L=new double[3];
double[] H=new double[3];
double D2;
Mat image=new Mat(rows,cols,CvType.CV_8UC3);
for(int i=0;i<tileHNumber;i++)
    for(int j=0;j<tileWNumber;j++)
        for(int s=0;s<192;s++)
            for(int t=0;t<192;t++)
                double[] pos=(Image2Cam(new double[]{originT,originS,0}));
                L=normalize(XY(lum, pos);
                double[] le=addXY(L,E);
                double blue=color(blueColor,pos,E,L,H,D2);
                double green=color(greenColor,pos,E,L,H,D2);
                double red=color(redColor,pos,E,L,H,D2);
                image.put(originS, originT, new byte[]{(byte)(blue),(byte)(green),(byte)(red)});
public static double color(double col,double[] pos,double[] E,double[] L,double[] H,double D2)
    double value=0;
    double[] N=normalize((new double[]{pos[0],pos[1],1}));
    double diffuse=Math.max(0, dot(N,L));
    double specular=Math.pow(Math.max(0, dot(N,H)),60);
    return value;

The 2 images below show my results: the first one shows diffuse image only. The second one shows specular image only represented by the white color.

My question is why the lobe specular is not surrounding the center of the image.

Diffuse image Specular image

  • $\begingroup$ To add, this is usually seen when the light direction is near parallel to the surface (like a sunset scene). When the light direction is perpendicular the specular highlight becomes much more circular. I would check your normal calculation in color(..), it looks like it is producing a normal that isn't perpendicular to your plane. Something like {0,0,-1} should be correct and facing towards your {0,0,1} light, not {pos.x,pos.y,1} like it currently is $\endgroup$
    – PaulHK
    Jul 20, 2016 at 7:01
  • $\begingroup$ It appears that the new images that have replaced the old ones show a new and unrelated problem. Would this be better posted as a new question, so that the old problem is still here for future readers? There is some discussion on meta about this general point. $\endgroup$ Jul 29, 2016 at 10:48
  • 1
    $\begingroup$ Yeah, my comments make no sense now the question has been updated. $\endgroup$
    – PaulHK
    Aug 29, 2016 at 2:53
  • $\begingroup$ I did not figure out how to resolve it. $\endgroup$
    – boykely
    Sep 2, 2016 at 19:59

1 Answer 1


If I'm guessing right, you are drawing a plane which is facing the camera, so your normals need to be 0,0,-1.


double[] N=normalize((new double[]{pos[0],pos[1],1}));


double[] N=normalize((new double[]{0,0,-1}));

  • $\begingroup$ Thanks for your reply. I try this but I only have the ambiant color $\endgroup$
    – boykely
    Jul 20, 2016 at 9:52
  • $\begingroup$ Maybe flip the sign. I'm not sure what your intention for the normals is, but for a plane every pixel should have the same normal. $\endgroup$
    – PaulHK
    Jul 20, 2016 at 9:55
  • $\begingroup$ Yes I try -1 and then 1. My purpose is to have a circular specular on the surface plane $\endgroup$
    – boykely
    Jul 20, 2016 at 9:57
  • $\begingroup$ The half-vector takes care of this normally, this will vary across your image. It looks like you are close to what you are intending, just something is on the wrong axis, at a guess. I encountered this problem and had similar results several times, was almost always down to incorrectly working out the eye-space/half-vector. $\endgroup$
    – PaulHK
    Jul 20, 2016 at 10:06
  • $\begingroup$ Looking a bit more at your code example, the L vector calculation looks wrong. Should that not just be the world-space light vector?(Lum). Your lambert calculation would be something like dot( N={0,0,-1}, L={0,0,1} ) for the whole surface, which should return an intensity of 1 for the diffuse component. $\endgroup$
    – PaulHK
    Jul 20, 2016 at 10:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.