📄 shadedsurface.java
字号:
/**
Gets the surface bounds for this ShadedSurface.
*/
public Rectangle3D getSurfaceBounds() {
return surfaceBounds;
}
/**
Builds the surface. First, this method calls
retrieveSurface() to see if the surface needs to be
rebuilt. If not, the surface is built by tiling the
source texture and apply the shade map.
*/
public void buildSurface() {
if (retrieveSurface()) {
return;
}
int width = (int)surfaceBounds.getWidth();
int height = (int)surfaceBounds.getHeight();
// create a new surface (buffer)
newSurface(width, height);
// builds the surface.
// assume surface bounds and texture bounds are aligned
// (possibly with different origins)
Vector3D origin = sourceTextureBounds.getOrigin();
Vector3D directionU = sourceTextureBounds.getDirectionU();
Vector3D directionV = sourceTextureBounds.getDirectionV();
Vector3D d = new Vector3D(surfaceBounds.getOrigin());
d.subtract(origin);
int startU = (int)((d.getDotProduct(directionU) -
SURFACE_BORDER_SIZE));
int startV = (int)((d.getDotProduct(directionV) -
SURFACE_BORDER_SIZE));
int offset = 0;
int shadeMapOffsetU = SHADE_RES - SURFACE_BORDER_SIZE -
startU;
int shadeMapOffsetV = SHADE_RES - SURFACE_BORDER_SIZE -
startV;
for (int v=startV; v<startV + height; v++) {
sourceTexture.setCurrRow(v);
int u = startU;
int amount = SURFACE_BORDER_SIZE;
while (u < startU + width) {
getInterpolatedShade(u + shadeMapOffsetU,
v + shadeMapOffsetV);
// keep drawing until we need to recalculate
// the interpolated shade. (every SHADE_RES pixels)
int endU = Math.min(startU + width, u + amount);
while (u < endU) {
buffer[offset++] =
sourceTexture.getColorCurrRow(u,
shadeValue >> SHADE_RES_SQ_BITS);
shadeValue+=shadeValueInc;
u++;
}
amount = SHADE_RES;
}
}
// if the surface bounds is not aligned with the texture
// bounds, use this (slower) code.
/*Vector3D origin = sourceTextureBounds.getOrigin();
Vector3D directionU = sourceTextureBounds.getDirectionU();
Vector3D directionV = sourceTextureBounds.getDirectionV();
Vector3D d = new Vector3D(surfaceBounds.getOrigin());
d.subtract(origin);
int initTextureU = (int)(SCALE *
(d.getDotProduct(directionU) - SURFACE_BORDER_SIZE));
int initTextureV = (int)(SCALE *
(d.getDotProduct(directionV) - SURFACE_BORDER_SIZE));
int textureDu1 = (int)(SCALE * directionU.getDotProduct(
surfaceBounds.getDirectionV()));
int textureDv1 = (int)(SCALE * directionV.getDotProduct(
surfaceBounds.getDirectionV()));
int textureDu2 = (int)(SCALE * directionU.getDotProduct(
surfaceBounds.getDirectionU()));
int textureDv2 = (int)(SCALE * directionV.getDotProduct(
surfaceBounds.getDirectionU()));
int shadeMapOffset = SHADE_RES - SURFACE_BORDER_SIZE;
for (int v=0; v<height; v++) {
int textureU = initTextureU;
int textureV = initTextureV;
for (int u=0; u<width; u++) {
if (((u + shadeMapOffset) & SHADE_RES_MASK) == 0) {
getInterpolatedShade(u + shadeMapOffset,
v + shadeMapOffset);
}
buffer[offset++] = sourceTexture.getColor(
textureU >> SCALE_BITS,
textureV >> SCALE_BITS,
shadeValue >> SHADE_RES_SQ_BITS);
textureU+=textureDu2;
textureV+=textureDv2;
shadeValue+=shadeValueInc;
}
initTextureU+=textureDu1;
initTextureV+=textureDv1;
}*/
}
/**
Gets the shade (from the shade map) for the specified
(u,v) location. The u and v values should be
left-shifted by SHADE_RES_BITS, and the extra bits are
used to interpolate between values. For an interpolation
example, a location halfway between shade values 1 and 3
would return 2.
*/
public int getInterpolatedShade(int u, int v) {
int fracU = u & SHADE_RES_MASK;
int fracV = v & SHADE_RES_MASK;
int offset = (u >> SHADE_RES_BITS) +
((v >> SHADE_RES_BITS) * shadeMapWidth);
int shade00 = (SHADE_RES-fracV) * shadeMap[offset];
int shade01 = fracV * shadeMap[offset + shadeMapWidth];
int shade10 = (SHADE_RES-fracV) * shadeMap[offset + 1];
int shade11 = fracV * shadeMap[offset + shadeMapWidth + 1];
shadeValue = SHADE_RES_SQ/2 +
(SHADE_RES-fracU) * shade00 +
(SHADE_RES-fracU) * shade01 +
fracU * shade10 +
fracU * shade11;
// the value to increment as u increments
shadeValueInc = -shade00 - shade01 + shade10 + shade11;
return shadeValue >> SHADE_RES_SQ_BITS;
}
/**
Gets the shade (from the built shade map) for the
specified (u,v) location.
*/
public int getShade(int u, int v) {
return shadeMap[u + v * shadeMapWidth];
}
/**
Builds the shade map for this surface from the specified
list of point lights and the ambiant light intensity.
*/
public void buildShadeMap(List pointLights,
float ambientLightIntensity)
{
Vector3D surfaceNormal = surfaceBounds.getNormal();
int polyWidth = (int)surfaceBounds.getWidth() -
SURFACE_BORDER_SIZE*2;
int polyHeight = (int)surfaceBounds.getHeight() -
SURFACE_BORDER_SIZE*2;
// assume SURFACE_BORDER_SIZE is <= SHADE_RES
shadeMapWidth = polyWidth / SHADE_RES + 4;
shadeMapHeight = polyHeight / SHADE_RES + 4;
shadeMap = new byte[shadeMapWidth * shadeMapHeight];
// calculate the shade map origin
Vector3D origin = new Vector3D(surfaceBounds.getOrigin());
Vector3D du = new Vector3D(surfaceBounds.getDirectionU());
Vector3D dv = new Vector3D(surfaceBounds.getDirectionV());
du.multiply(SHADE_RES - SURFACE_BORDER_SIZE);
dv.multiply(SHADE_RES - SURFACE_BORDER_SIZE);
origin.subtract(du);
origin.subtract(dv);
// calculate the shade for each sample point.
Vector3D point = new Vector3D();
du.setTo(surfaceBounds.getDirectionU());
dv.setTo(surfaceBounds.getDirectionV());
du.multiply(SHADE_RES);
dv.multiply(SHADE_RES);
for (int v=0; v<shadeMapHeight; v++) {
point.setTo(origin);
for (int u=0; u<shadeMapWidth; u++) {
shadeMap[u + v * shadeMapWidth] =
calcShade(surfaceNormal, point,
pointLights, ambientLightIntensity);
point.add(du);
}
origin.add(dv);
}
}
/**
Determine the shade of a point on the polygon.
This computes the Lambertian reflection for a point on
the plane. Each point light has an intensity and a
distance falloff value, but no specular reflection or
shadows from other polygons are computed. The value
returned is from 0 to ShadedTexture.MAX_LEVEL.
*/
protected byte calcShade(Vector3D normal, Vector3D point,
List pointLights, float ambientLightIntensity)
{
float intensity = 0;
Vector3D directionToLight = new Vector3D();
for (int i=0; i<pointLights.size(); i++) {
PointLight3D light = (PointLight3D)pointLights.get(i);
directionToLight.setTo(light);
directionToLight.subtract(point);
float distance = directionToLight.length();
directionToLight.normalize();
float lightIntensity = light.getIntensity(distance)
* directionToLight.getDotProduct(normal);
lightIntensity = Math.min(lightIntensity, 1);
lightIntensity = Math.max(lightIntensity, 0);
intensity += lightIntensity;
}
intensity = Math.min(intensity, 1);
intensity = Math.max(intensity, 0);
intensity+=ambientLightIntensity;
intensity = Math.min(intensity, 1);
intensity = Math.max(intensity, 0);
int level = Math.round(intensity*ShadedTexture.MAX_LEVEL);
return (byte)level;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -