📄 compressionstreamnormal.java
字号:
/* * $RCSfile: CompressionStreamNormal.java,v $ * * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or * intended for use in the design, construction, operation or * maintenance of any nuclear facility. * * $Revision: 1.5 $ * $Date: 2007/02/09 17:20:16 $ * $State: Exp $ */package com.sun.j3d.utils.compression;import javax.vecmath.Vector3f;/** * This class represents a normal in a compression stream. It maintains both * floating-point and quantized representations. This normal may be bundled * with a vertex or exist separately as a global normal. */class CompressionStreamNormal extends CompressionStreamElement { private int u, v ; private int specialOctant, specialSextant ; private float normalX, normalY, normalZ ; int octant, sextant ; boolean specialNormal ; int uAbsolute, vAbsolute ; /** * Create a CompressionStreamNormal. * * @param stream CompressionStream associated with this element * @param normal floating-point representation to be encoded */ CompressionStreamNormal(CompressionStream stream, Vector3f normal) { this.normalX = normal.x ; this.normalY = normal.y ; this.normalZ = normal.z ; stream.byteCount += 12 ; } // // Normal Encoding Parameterization // // A floating point normal is quantized to a desired number of bits by // comparing it to candidate entries in a table of every possible normal // at that quantization and finding the closest match. This table of // normals is indexed by the following encoding: // // First, points on a unit radius sphere are parameterized by two angles, // th and psi, using usual spherical coordinates. th is the angle about // the y axis, psi is the inclination to the plane containing the point. // The mapping between rectangular and spherical coordinates is: // // x = cos(th)*cos(psi) // y = sin(psi) // z = sin(th)*cos(psi) // // Points on sphere are folded first by octant, and then by sort order // of xyz into one of six sextants. All the table encoding takes place in // the positive octant, in the region bounded by the half spaces: // // x >= z // z >= y // y >= 0 // // This triangular shaped patch runs from 0 to 45 degrees in th, and // from 0 to as much as 0.615479709 (MAX_Y_ANG) in psi. The xyz bounds // of the patch is: // // (1, 0, 0) (1/sqrt(2), 0, 1/sqrt(2)) (1/sqrt(3), 1/sqrt(3), 1/sqrt(3)) // // When dicing this space up into discrete points, the choice for y is // linear quantization in psi. This means that if the y range is to be // divided up into n segments, the angle of segment j is: // // psi(j) = MAX_Y_ANG*(j/n) // // The y height of the patch (in arc length) is *not* the same as the xz // dimension. However, the subdivision quantization needs to treat xz and // y equally. To achieve this, the th angles are re-parameterized as // reflected psi angles. That is, the i-th point's th is: // // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*(i/n))) // // To go the other direction, the angle th corresponds to the real index r // (in the same 0-n range as i): // // r(th) = n*atan(sin(th))/MAX_Y_ANG // // Rounded to the nearest integer, this gives the closest integer index i // to the xz angle th. Because the triangle has a straight edge on the // line x=z, it is more intuitive to index the xz angles in reverse // order. Thus the two equations above are replaced by: // // th(i) = asin(tan(psi(i))) = asin(tan(MAX_Y_ANG*((n-i)/n))) // // r(th) = n*(1 - atan(sin(th))/MAX_Y_ANG) // // Each level of quantization subdivides the triangular patch twice as // densely. The case in which only the three vertices of the triangle are // present is the first logical stage of representation, but because of // how the table is encoded the first usable case starts one level of // sub-division later. This three point level has an n of 2 by the above // conventions. // private static final int MAX_UV_BITS = 6 ; private static final int MAX_UV_ENTRIES = 64 ; private static final double cgNormals[][][][] = new double[MAX_UV_BITS+1][MAX_UV_ENTRIES+1][MAX_UV_ENTRIES+1][3] ; private static final double MAX_Y_ANG = 0.615479709 ; private static final double UNITY_14 = 16384.0 ; private static void computeNormals() { int inx, iny, inz, n ; double th, psi, qnx, qny, qnz ; for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) { n = 1 << quant ; for (int j = 0 ; j <= n ; j++) { for (int i = 0 ; i <= n ; i++) { if (i+j > n) continue ; psi = MAX_Y_ANG*(j/((double) n)) ; th = Math.asin(Math.tan(MAX_Y_ANG*((n-i)/((double) n)))) ; qnx = Math.cos(th)*Math.cos(psi) ; qny = Math.sin(psi) ; qnz = Math.sin(th)*Math.cos(psi) ; // The normal table uses 16-bit components and must be // able to represent both +1.0 and -1.0, so convert the // floating point normal components to fixed point with 14 // fractional bits, a unity bit, and a sign bit (s1.14). // Set them back to get the float equivalent. qnx = qnx*UNITY_14 ; inx = (int)qnx ; qnx = inx ; qnx = qnx/UNITY_14 ; qny = qny*UNITY_14 ; iny = (int)qny ; qny = iny ; qny = qny/UNITY_14 ; qnz = qnz*UNITY_14 ; inz = (int)qnz ; qnz = inz ; qnz = qnz/UNITY_14 ; cgNormals[quant][j][i][0] = qnx ; cgNormals[quant][j][i][1] = qny ; cgNormals[quant][j][i][2] = qnz ; } } } } // // An inverse sine table is used for each quantization level to take the Y // component of a normal (which is the sine of the inclination angle) and // obtain the closest quantized Y angle. // // At any level of compression, there are a fixed number of different Y // angles (between 0 and MAX_Y_ANG). The inverse table is built to have // slightly more than twice as many entries as y angles at any particular // level; this ensures that the inverse look-up will get within one angle // of the right one. The size of the table should be as small as // possible, but with its delta sine still smaller than the delta sine // between the last two angles to be encoded. // // Example: the inverse sine table has a maximum angle of 0.615479709. At // the maximum resolution of 6 bits there are 65 discrete angles used, // but twice as many are needed for thresholding between angles, so the // delta angle is 0.615479709/128. The difference then between the last // two angles to be encoded is: // sin(0.615479709*128.0/128.0) - sin(0.615479709*127.0/128.0) = 0.003932730 // // Using 8 significent bits below the binary point, fixed point can // represent sines in increments of 0.003906250, just slightly smaller. // However, because the maximum Y angle sine is 0.577350269, only 148 // instead of 256 table entries are needed. // private static final short inverseSine[][] = new short[MAX_UV_BITS+1][] ; // UNITY_14 * sin(MAX_Y_ANGLE) private static final short MAX_SIN_14BIT = 9459 ; private static void computeInverseSineTables() { int intSin, deltaSin, intAngle ; double floatSin, floatAngle ; short sin14[] = new short[MAX_UV_ENTRIES+1] ; // Build table of sines in s1.14 fixed point for each of the // discrete angles used at maximum resolution. for (int i = 0 ; i <= MAX_UV_ENTRIES ; i++) { sin14[i] = (short)(UNITY_14*Math.sin(i*MAX_Y_ANG/MAX_UV_ENTRIES)) ; } for (int quant = 0 ; quant <= MAX_UV_BITS ; quant++) { switch (quant) { default: case 6: // Delta angle: MAX_Y_ANGLE/128.0 // Bits below binary point for fixed point delta sine: 8 // Integer delta sine: 64 // Inverse sine table size: 148 entries deltaSin = 1 << (14 - 8) ; break ; case 5: // Delta angle: MAX_Y_ANGLE/64.0 // Bits below binary point for fixed point delta sine: 7 // Integer delta sine: 128 // Inverse sine table size: 74 entries deltaSin = 1 << (14 - 7) ; break ; case 4: // Delta angle: MAX_Y_ANGLE/32.0 // Bits below binary point for fixed point delta sine: 6 // Integer delta sine: 256 // Inverse sine table size: 37 entries deltaSin = 1 << (14 - 6) ; break ; case 3: // Delta angle: MAX_Y_ANGLE/16.0 // Bits below binary point for fixed point delta sine: 5 // Integer delta sine: 512 // Inverse sine table size: 19 entries deltaSin = 1 << (14 - 5) ; break ; case 2: // Delta angle: MAX_Y_ANGLE/8.0 // Bits below binary point for fixed point delta sine: 4 // Integer delta sine: 1024 // Inverse sine table size: 10 entries deltaSin = 1 << (14 - 4) ; break ; case 1: // Delta angle: MAX_Y_ANGLE/4.0 // Bits below binary point for fixed point delta sine: 3 // Integer delta sine: 2048 // Inverse sine table size: 5 entries deltaSin = 1 << (14 - 3) ; break ; case 0: // Delta angle: MAX_Y_ANGLE/2.0 // Bits below binary point for fixed point delta sine: 2 // Integer delta sine: 4096 // Inverse sine table size: 3 entries deltaSin = 1 << (14 - 2) ; break ; } inverseSine[quant] = new short[(MAX_SIN_14BIT/deltaSin) + 1] ; intSin = 0 ; for (int i = 0 ; i < inverseSine[quant].length ; i++) { // Compute float representation of integer sine with desired // number of fractional bits by effectively right shifting 14. floatSin = intSin/UNITY_14 ; // Compute the angle with this sine value and quantize it. floatAngle = Math.asin(floatSin) ; intAngle = (int)((floatAngle/MAX_Y_ANG) * (1 << quant)) ; // Choose the closest of the three nearest quantized values // intAngle-1, intAngle, and intAngle+1. if (intAngle > 0) { if (Math.abs(sin14[intAngle << (6-quant)] - intSin) > Math.abs(sin14[(intAngle-1) << (6-quant)] - intSin)) intAngle = intAngle-1 ; } if (intAngle < (1 << quant)) { if (Math.abs(sin14[intAngle << (6-quant)] - intSin) > Math.abs(sin14[(intAngle+1) << (6-quant)] - intSin)) intAngle = intAngle+1 ; } inverseSine[quant][i] = (short)intAngle ; intSin += deltaSin ; } } } /** * Compute static tables needed for normal quantization. */ static { computeNormals() ; computeInverseSineTables() ; } /** * Quantize the floating point normal to a 6-bit octant/sextant plus u,v * components of [0..6] bits. Full resolution is 18 bits and the minimum * is 6 bits. * * @param stream CompressionStream associated with this element * @param table HuffmanTable for collecting data about the quantized * representation of this element */ void quantize(CompressionStream stream, HuffmanTable huffmanTable) { double nx, ny, nz, t ; // Clamp UV quantization. int quant =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -