예제 #1
0
  protected Color4f phongShade(
      Vector3f position,
      Vector3f viewpoint,
      Vector3f normal,
      Color4f diffuseColor,
      Color4f specularColor,
      Material material,
      Light[] lightsArray) {
    shadedColor.set(diffuseColor);
    shadedColor.scale(material.ambientIntensity);

    for (int i = 0; i < lightsArray.length; i++) {
      Light light = lightsArray[i];
      n.set(normal);
      l.set(light.position);
      if (light.type != DISTANT) l.sub(position);
      l.normalize();
      float nDotL = n.dot(l);
      if (nDotL >= 0.0) {
        float dDotL = 0;

        v.set(viewpoint);
        v.sub(position);
        v.normalize();

        // Spotlight
        if (light.type == SPOT) {
          dDotL = light.direction.dot(l);
          if (dDotL < light.cosConeAngle) continue;
        }

        n.scale(2.0f * nDotL);
        n.sub(l);
        float rDotV = n.dot(v);

        float rv;
        if (rDotV < 0.0) rv = 0.0f;
        else
          //					rv = (float)Math.pow(rDotV, material.highlight);
          rv =
              rDotV
                  / (material.highlight
                      - material.highlight * rDotV
                      + rDotV); // Fast approximation to pow

        // Spotlight
        if (light.type == SPOT) {
          dDotL = light.cosConeAngle / dDotL;
          float e = dDotL;
          e *= e;
          e *= e;
          e *= e;
          e = (float) Math.pow(dDotL, light.focus * 10) * (1 - e);
          rv *= e;
          nDotL *= e;
        }

        diffuse_color.set(diffuseColor);
        diffuse_color.scale(material.diffuseReflectivity);
        diffuse_color.x *= light.realColor.x * nDotL;
        diffuse_color.y *= light.realColor.y * nDotL;
        diffuse_color.z *= light.realColor.z * nDotL;
        specular_color.set(specularColor);
        specular_color.scale(material.specularReflectivity);
        specular_color.x *= light.realColor.x * rv;
        specular_color.y *= light.realColor.y * rv;
        specular_color.z *= light.realColor.z * rv;
        diffuse_color.add(specular_color);
        diffuse_color.clamp(0, 1);
        shadedColor.add(diffuse_color);
      }
    }
    shadedColor.clamp(0, 1);
    return shadedColor;
  }
예제 #2
0
  protected int[] filterPixels(int width, int height, int[] inPixels, Rectangle transformedSpace) {
    int index = 0;
    int[] outPixels = new int[width * height];
    float width45 = Math.abs(6.0f * bumpHeight);
    boolean invertBumps = bumpHeight < 0;
    Vector3f position = new Vector3f(0.0f, 0.0f, 0.0f);
    Vector3f viewpoint = new Vector3f((float) width / 2.0f, (float) height / 2.0f, viewDistance);
    Vector3f normal = new Vector3f();
    Color4f c = new Color4f();
    Function2D bump = bumpFunction;

    if (bumpSource == BUMPS_FROM_IMAGE
        || bumpSource == BUMPS_FROM_IMAGE_ALPHA
        || bumpSource == BUMPS_FROM_MAP
        || bump == null) {
      if (bumpSoftness != 0) {
        int bumpWidth = width;
        int bumpHeight = height;
        int[] bumpPixels = inPixels;
        if (bumpSource == BUMPS_FROM_MAP && bumpFunction instanceof ImageFunction2D) {
          ImageFunction2D if2d = (ImageFunction2D) bumpFunction;
          bumpWidth = if2d.getWidth();
          bumpHeight = if2d.getHeight();
          bumpPixels = if2d.getPixels();
        }
        Kernel kernel = GaussianFilter.makeKernel(bumpSoftness);
        int[] tmpPixels = new int[bumpWidth * bumpHeight];
        int[] softPixels = new int[bumpWidth * bumpHeight];
        GaussianFilter.convolveAndTranspose(
            kernel,
            bumpPixels,
            tmpPixels,
            bumpWidth,
            bumpHeight,
            true,
            false,
            false,
            ConvolveFilter.CLAMP_EDGES);
        GaussianFilter.convolveAndTranspose(
            kernel,
            tmpPixels,
            softPixels,
            bumpHeight,
            bumpWidth,
            true,
            false,
            false,
            ConvolveFilter.CLAMP_EDGES);
        bump =
            new ImageFunction2D(
                softPixels,
                bumpWidth,
                bumpHeight,
                ImageFunction2D.CLAMP,
                bumpSource == BUMPS_FROM_IMAGE_ALPHA);
      } else
        bump =
            new ImageFunction2D(
                inPixels,
                width,
                height,
                ImageFunction2D.CLAMP,
                bumpSource == BUMPS_FROM_IMAGE_ALPHA);
    }

    Vector3f v1 = new Vector3f();
    Vector3f v2 = new Vector3f();
    Vector3f n = new Vector3f();

    // Loop through each source pixel
    for (int y = 0; y < height; y++) {
      float ny = y;
      position.y = y;
      for (int x = 0; x < width; x++) {
        float nx = x;

        // Calculate the normal at this point
        if (bumpSource != BUMPS_FROM_BEVEL) {
          // Complicated and slower method
          // Calculate four normals using the gradients in +/- X/Y directions
          int count = 0;
          normal.x = normal.y = normal.z = 0;
          float m0 = width45 * bump.evaluate(nx, ny);
          float m1 = x > 0 ? width45 * bump.evaluate(nx - 1.0f, ny) - m0 : -2;
          float m2 = y > 0 ? width45 * bump.evaluate(nx, ny - 1.0f) - m0 : -2;
          float m3 = x < width - 1 ? width45 * bump.evaluate(nx + 1.0f, ny) - m0 : -2;
          float m4 = y < height - 1 ? width45 * bump.evaluate(nx, ny + 1.0f) - m0 : -2;

          if (m1 != -2 && m4 != -2) {
            v1.x = -1.0f;
            v1.y = 0.0f;
            v1.z = m1;
            v2.x = 0.0f;
            v2.y = 1.0f;
            v2.z = m4;
            n.cross(v1, v2);
            n.normalize();
            if (n.z < 0.0) n.z = -n.z;
            normal.add(n);
            count++;
          }

          if (m1 != -2 && m2 != -2) {
            v1.x = -1.0f;
            v1.y = 0.0f;
            v1.z = m1;
            v2.x = 0.0f;
            v2.y = -1.0f;
            v2.z = m2;
            n.cross(v1, v2);
            n.normalize();
            if (n.z < 0.0) n.z = -n.z;
            normal.add(n);
            count++;
          }

          if (m2 != -2 && m3 != -2) {
            v1.x = 0.0f;
            v1.y = -1.0f;
            v1.z = m2;
            v2.x = 1.0f;
            v2.y = 0.0f;
            v2.z = m3;
            n.cross(v1, v2);
            n.normalize();
            if (n.z < 0.0) n.z = -n.z;
            normal.add(n);
            count++;
          }

          if (m3 != -2 && m4 != -2) {
            v1.x = 1.0f;
            v1.y = 0.0f;
            v1.z = m3;
            v2.x = 0.0f;
            v2.y = 1.0f;
            v2.z = m4;
            n.cross(v1, v2);
            n.normalize();
            if (n.z < 0.0) n.z = -n.z;
            normal.add(n);
            count++;
          }

          // Average the four normals
          normal.x /= count;
          normal.y /= count;
          normal.z /= count;
        }

        /* For testing - generate a sphere bump map
        				double dx = x-120;
        				double dy = y-80;
        				double r2 = dx*dx+dy*dy;
        //				double r = Math.sqrt( r2 );
        //				double t = Math.atan2( dy, dx );
        				if ( r2 < 80*80 ) {
        					double z = Math.sqrt( 80*80 - r2 );
        					normal.x = (float)dx;
        					normal.y = (float)dy;
        					normal.z = (float)z;
        					normal.normalize();
        				} else {
        					normal.x = 0;
        					normal.y = 0;
        					normal.z = 1;
        				}
        */

        if (invertBumps) {
          normal.x = -normal.x;
          normal.y = -normal.y;
        }
        position.x = x;

        if (normal.z >= 0) {
          // Get the material colour at this point
          if (environmentMap != null) {
            // FIXME-too much normalizing going on here
            tmpv2.set(viewpoint);
            tmpv2.sub(position);
            tmpv2.normalize();
            tmpv.set(normal);
            tmpv.normalize();

            // Reflect
            tmpv.scale(2.0f * tmpv.dot(tmpv2));
            tmpv.sub(v);

            tmpv.normalize();
            setFromRGB(
                c, getEnvironmentMapP(normal, inPixels, width, height)); // FIXME-interpolate()
            int alpha = inPixels[index] & 0xff000000;
            int rgb = ((int) (c.x * 255) << 16) | ((int) (c.y * 255) << 8) | (int) (c.z * 255);
            outPixels[index++] = alpha | rgb;
          } else outPixels[index++] = 0;
        } else outPixels[index++] = 0;
      }
    }
    return outPixels;
  }
예제 #3
0
  protected int[] filterPixels(int width, int height, int[] inPixels, Rectangle transformedSpace) {
    int index = 0;
    int[] outPixels = new int[width * height];
    float width45 = Math.abs(6.0f * bumpHeight);
    boolean invertBumps = bumpHeight < 0;
    Vector3f position = new Vector3f(0.0f, 0.0f, 0.0f);
    Vector3f viewpoint = new Vector3f((float) width / 2.0f, (float) height / 2.0f, viewDistance);
    Vector3f normal = new Vector3f();
    Color4f envColor = new Color4f();
    Color4f diffuseColor = new Color4f(new Color(material.diffuseColor));
    Color4f specularColor = new Color4f(new Color(material.specularColor));
    Function2D bump = bumpFunction;

    // Apply the bump softness
    if (bumpSource == BUMPS_FROM_IMAGE
        || bumpSource == BUMPS_FROM_IMAGE_ALPHA
        || bumpSource == BUMPS_FROM_MAP
        || bump == null) {
      if (bumpSoftness != 0) {
        int bumpWidth = width;
        int bumpHeight = height;
        int[] bumpPixels = inPixels;
        if (bumpSource == BUMPS_FROM_MAP && bumpFunction instanceof ImageFunction2D) {
          ImageFunction2D if2d = (ImageFunction2D) bumpFunction;
          bumpWidth = if2d.getWidth();
          bumpHeight = if2d.getHeight();
          bumpPixels = if2d.getPixels();
        }
        int[] tmpPixels = new int[bumpWidth * bumpHeight];
        int[] softPixels = new int[bumpWidth * bumpHeight];
        /*
        				for (int i = 0; i < 3; i++ ) {
        					BoxBlurFilter.blur( bumpPixels, tmpPixels, bumpWidth, bumpHeight, (int)bumpSoftness );
        					BoxBlurFilter.blur( tmpPixels, softPixels, bumpHeight, bumpWidth, (int)bumpSoftness );
        				}
        */
        Kernel kernel = GaussianFilter.makeKernel(bumpSoftness);
        GaussianFilter.convolveAndTranspose(
            kernel,
            bumpPixels,
            tmpPixels,
            bumpWidth,
            bumpHeight,
            true,
            false,
            false,
            GaussianFilter.WRAP_EDGES);
        GaussianFilter.convolveAndTranspose(
            kernel,
            tmpPixels,
            softPixels,
            bumpHeight,
            bumpWidth,
            true,
            false,
            false,
            GaussianFilter.WRAP_EDGES);
        bump =
            new ImageFunction2D(
                softPixels,
                bumpWidth,
                bumpHeight,
                ImageFunction2D.CLAMP,
                bumpSource == BUMPS_FROM_IMAGE_ALPHA);
        final Function2D bbump = bump;
        if (bumpShape != 0) {
          bump =
              new Function2D() {
                private Function2D original = bbump;

                public float evaluate(float x, float y) {
                  float v = original.evaluate(x, y);
                  switch (bumpShape) {
                    case 1:
                      //				v = v > 0.5f ? 0.5f : v;
                      v *= ImageMath.smoothStep(0.45f, 0.55f, v);
                      break;
                    case 2:
                      v = v < 0.5f ? 0.5f : v;
                      break;
                    case 3:
                      v = ImageMath.triangle(v);
                      break;
                    case 4:
                      v = ImageMath.circleDown(v);
                      break;
                    case 5:
                      v = ImageMath.gain(v, 0.75f);
                      break;
                  }
                  return v;
                }
              };
        }
      } else if (bumpSource != BUMPS_FROM_MAP)
        bump =
            new ImageFunction2D(
                inPixels,
                width,
                height,
                ImageFunction2D.CLAMP,
                bumpSource == BUMPS_FROM_IMAGE_ALPHA);
    }

    float reflectivity = material.reflectivity;
    float areflectivity = (1 - reflectivity);
    Vector3f v1 = new Vector3f();
    Vector3f v2 = new Vector3f();
    Vector3f n = new Vector3f();
    Light[] lightsArray = new Light[lights.size()];
    lights.copyInto(lightsArray);
    for (int i = 0; i < lightsArray.length; i++) lightsArray[i].prepare(width, height);

    float[][] heightWindow = new float[3][width];
    for (int x = 0; x < width; x++) heightWindow[1][x] = width45 * bump.evaluate(x, 0);

    // Loop through each source pixel
    for (int y = 0; y < height; y++) {
      boolean y0 = y > 0;
      boolean y1 = y < height - 1;
      position.y = y;
      for (int x = 0; x < width; x++) heightWindow[2][x] = width45 * bump.evaluate(x, y + 1);
      for (int x = 0; x < width; x++) {
        boolean x0 = x > 0;
        boolean x1 = x < width - 1;

        // Calculate the normal at this point
        if (bumpSource != BUMPS_FROM_BEVEL) {
          // Complicated and slower method
          // Calculate four normals using the gradients in +/- X/Y directions
          int count = 0;
          normal.x = normal.y = normal.z = 0;
          float m0 = heightWindow[1][x];
          float m1 = x0 ? heightWindow[1][x - 1] - m0 : 0;
          float m2 = y0 ? heightWindow[0][x] - m0 : 0;
          float m3 = x1 ? heightWindow[1][x + 1] - m0 : 0;
          float m4 = y1 ? heightWindow[2][x] - m0 : 0;

          if (x0 && y1) {
            v1.x = -1.0f;
            v1.y = 0.0f;
            v1.z = m1;
            v2.x = 0.0f;
            v2.y = 1.0f;
            v2.z = m4;
            n.cross(v1, v2);
            n.normalize();
            if (n.z < 0.0) n.z = -n.z;
            normal.add(n);
            count++;
          }

          if (x0 && y0) {
            v1.x = -1.0f;
            v1.y = 0.0f;
            v1.z = m1;
            v2.x = 0.0f;
            v2.y = -1.0f;
            v2.z = m2;
            n.cross(v1, v2);
            n.normalize();
            if (n.z < 0.0) n.z = -n.z;
            normal.add(n);
            count++;
          }

          if (y0 && x1) {
            v1.x = 0.0f;
            v1.y = -1.0f;
            v1.z = m2;
            v2.x = 1.0f;
            v2.y = 0.0f;
            v2.z = m3;
            n.cross(v1, v2);
            n.normalize();
            if (n.z < 0.0) n.z = -n.z;
            normal.add(n);
            count++;
          }

          if (x1 && y1) {
            v1.x = 1.0f;
            v1.y = 0.0f;
            v1.z = m3;
            v2.x = 0.0f;
            v2.y = 1.0f;
            v2.z = m4;
            n.cross(v1, v2);
            n.normalize();
            if (n.z < 0.0) n.z = -n.z;
            normal.add(n);
            count++;
          }

          // Average the four normals
          normal.x /= count;
          normal.y /= count;
          normal.z /= count;
        }
        if (invertBumps) {
          normal.x = -normal.x;
          normal.y = -normal.y;
        }
        position.x = x;

        if (normal.z >= 0) {
          // Get the material colour at this point
          if (colorSource == COLORS_FROM_IMAGE) setFromRGB(diffuseColor, inPixels[index]);
          else setFromRGB(diffuseColor, material.diffuseColor);
          if (reflectivity != 0 && environmentMap != null) {
            // FIXME-too much normalizing going on here
            tmpv2.set(viewpoint);
            tmpv2.sub(position);
            tmpv2.normalize();
            tmpv.set(normal);
            tmpv.normalize();

            // Reflect
            tmpv.scale(2.0f * tmpv.dot(tmpv2));
            tmpv.sub(v);

            tmpv.normalize();
            setFromRGB(
                envColor, getEnvironmentMap(tmpv, inPixels, width, height)); // FIXME-interpolate()
            diffuseColor.x = reflectivity * envColor.x + areflectivity * diffuseColor.x;
            diffuseColor.y = reflectivity * envColor.y + areflectivity * diffuseColor.y;
            diffuseColor.z = reflectivity * envColor.z + areflectivity * diffuseColor.z;
          }
          // Shade the pixel
          Color4f c =
              phongShade(
                  position, viewpoint, normal, diffuseColor, specularColor, material, lightsArray);
          int alpha = inPixels[index] & 0xff000000;
          int rgb = ((int) (c.x * 255) << 16) | ((int) (c.y * 255) << 8) | (int) (c.z * 255);
          outPixels[index++] = alpha | rgb;
        } else outPixels[index++] = 0;
      }
      float[] t = heightWindow[0];
      heightWindow[0] = heightWindow[1];
      heightWindow[1] = heightWindow[2];
      heightWindow[2] = t;
    }
    return outPixels;
  }