├── voronoi.cl ├── pixelize.cl ├── glow.cl ├── README.md ├── split_gaussian_blur.cl ├── normal_to_height.cl ├── weave.cl └── edge_detect.cl /voronoi.cl: -------------------------------------------------------------------------------- 1 | /* 2 | @title: voronoi_v01 3 | @author: melmass 4 | */ 5 | 6 | #import "random.h" 7 | 8 | #bind layer !&dst float 9 | #bind parm num_points int 10 | 11 | @KERNEL 12 | { 13 | const int2 pos = (int2)(get_global_id(0), get_global_id(1)); 14 | const int2 size = (int2)(@dst.xres, @dst.yres); 15 | 16 | if (pos.x >= size.x || pos.y >= size.y) return; 17 | 18 | float minDist = FLT_MAX; 19 | for (int i = 0; i < @num_points; i++) { 20 | float r1 = VEXrandom_1_1(i) * size.x; 21 | float r2 = VEXrandom_1_1(i + 1) * size.y; 22 | 23 | float2 point = (float2)((int)r1 % size.x, (int)r2 % size.y); 24 | float dist = distance((float2)(pos.x, pos.y), point); 25 | if (dist < minDist) { 26 | minDist = dist; 27 | 28 | } 29 | 30 | } 31 | 32 | @dst.setIndex(pos, minDist / size.x); 33 | } 34 | -------------------------------------------------------------------------------- /pixelize.cl: -------------------------------------------------------------------------------- 1 | /* 2 | @title: pixelize_v01 3 | @author: melmass 4 | */ 5 | 6 | #bind layer !&outColor float4 7 | #bind layer src float4 8 | 9 | #bind parm PixelSize int val=10 10 | 11 | // 0 average | 1 nearest neighbor 12 | #bind parm Mode int val=0 13 | 14 | 15 | @KERNEL 16 | { 17 | const int2 pos = (int2)(get_global_id(0), get_global_id(1)); 18 | const int2 size = (int2)(@outColor.xres, @outColor.yres); 19 | 20 | if (pos.x >= size.x || pos.y >= size.y) return; 21 | 22 | int blockX = pos.x / @PixelSize; 23 | int blockY = pos.y / @PixelSize; 24 | 25 | int originX = blockX * @PixelSize; 26 | int originY = blockY * @PixelSize; 27 | 28 | 29 | float4 outputColor; 30 | 31 | // average 32 | if (@Mode == 0) { 33 | float4 accumulatedColor = (float4)(0.0f, 0.0f, 0.0f, 0.0f); 34 | int count = 0; 35 | for (int y = 0; y < @PixelSize; y++) { 36 | for (int x = 0; x < @PixelSize; x++) { 37 | int2 blockPos = (int2)(originX + x, originY + y); 38 | if (blockPos.x < size.x && blockPos.y < size.y) { 39 | accumulatedColor += @src.bufferIndex(blockPos); 40 | count++; 41 | } 42 | } 43 | } 44 | outputColor = accumulatedColor / (float)count; 45 | 46 | // nearest neighbor 47 | } else { 48 | int2 nearestPos = (int2)(originX, originY); 49 | if (nearestPos.x >= size.x || nearestPos.y >= size.y) return; 50 | outputColor = @src.bufferIndex(nearestPos); 51 | } 52 | 53 | @outColor.setIndex(pos, outputColor); 54 | } 55 | -------------------------------------------------------------------------------- /glow.cl: -------------------------------------------------------------------------------- 1 | /* 2 | @title: gaussian_glow_v01 3 | @author: melmass 4 | */ 5 | 6 | #bind layer src float4 7 | #bind layer !&dst float4 8 | 9 | #bind parm intensity float 10 | #bind parm threshold float 11 | #bind parm radius float 12 | 13 | float gaussian(float x, float sigma) { 14 | return exp(-(x*x) / (2.0f * sigma*sigma)) / (sqrt(2.0f * M_PI) * sigma); 15 | } 16 | 17 | @KERNEL 18 | { 19 | const int2 pos = (int2)(get_global_id(0), get_global_id(1)); 20 | const int2 size = (int2)(@src.xres, @src.yres); 21 | 22 | if (pos.x >= size.x || pos.y >= size.y) return; 23 | 24 | float4 original = @src.bufferIndex(pos); 25 | float brightness = dot(original.rgb, (float3)(0.299f, 0.587f, 0.114f)); 26 | float4 glowPixel = (brightness > @threshold) ? original : (float4)(0.0f); 27 | 28 | float4 blurred = (float4)(0.0f); 29 | float weightSum = 0.0f; 30 | int blurRadius = (int)@radius; 31 | 32 | for (int dy = -blurRadius; dy <= blurRadius; dy++) { 33 | for (int dx = -blurRadius; dx <= blurRadius; dx++) { 34 | int2 samplePos = pos + (int2)(dx, dy); 35 | if (samplePos.x >= 0 && samplePos.x < size.x && samplePos.y >= 0 && samplePos.y < size.y) { 36 | float4 sample = @src.bufferIndex(samplePos); 37 | float sampleBrightness = dot(sample.rgb, (float3)(0.299f, 0.587f, 0.114f)); 38 | float4 sampleGlow = (sampleBrightness > @threshold) ? sample : (float4)(0.0f); 39 | 40 | float weight = gaussian(length((float2)(dx, dy)), @radius / 3.0f); 41 | blurred += sampleGlow * weight; 42 | weightSum += weight; 43 | } 44 | } 45 | } 46 | blurred /= weightSum; 47 | float4 result = original + blurred * @intensity; 48 | result = clamp(result, 0.0f, 1.0f); 49 | @dst.setIndex(pos, result); 50 | } 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # COP OpenCL 2 | 3 | Experimenting with copernicus, the long-awaited GPU texture/shader context of Houdini. 4 | The main purpose of this repo is to show various approaches for learning purposes. 5 | 6 | Do not hesitate to reach or PR nodes that others could learn from. 7 | 8 | ## Nodes 9 | 10 | ### Weave 11 | 12 | This is an almost 1/1 copy of the OSL version for 3DSMax by Zap Anderson ([osl source code](https://github.com/ADN-DevTech/3dsMax-OSL-Shaders/blob/master/3ds%20Max%20Shipping%20Shaders/Weave.osl)), 13 | it outputs color, bump, ID and opacity 14 | 15 | 16 | 17 | ### Split Gaussian Blur 18 | 19 | This is very slow for now compared to the built-in gaussian blur. 20 | The main idea is to use a `float4` as `sigma`, allowing to blur each channels (supports RGBA) independently. 21 | For convenience, it also has a global `float` sigma multiplier. 22 | 23 | 24 | 25 | ### Glow 26 | 27 | Naive glow, like the edge detection this should yield better results if done in multiple kernels (for instance extract highlights, blur,pasteback). 28 | Keeping it for reference too. 29 | 30 | 31 | 32 | ### Pixelize 33 | 34 | 35 | 36 | 37 | 38 | ### Normal to Height 39 | 40 | An (approximative) openCL implementation of this [blog post](https://stannum.io/blog/0IwyJ-) 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /split_gaussian_blur.cl: -------------------------------------------------------------------------------- 1 | /* 2 | @title: split_gaussian_blur_v01 3 | @author: melmass 4 | */ 5 | 6 | #bind layer src float4 7 | #bind layer !&blurred float4 8 | 9 | #bind parm sigma float4 10 | #bind parm sigmaMultiplier float 11 | 12 | 13 | float gaussian(float x, float sigma) { 14 | return exp(-(x*x) / (2.0f * sigma*sigma)) / (sqrt(2.0f * M_PI) * sigma); 15 | } 16 | 17 | @KERNEL 18 | { 19 | @sigma = max(0.00001f, @sigma) * @sigmaMultiplier; 20 | const int2 pos = (int2)(get_global_id(0), get_global_id(1)); 21 | const int2 size = (int2)(@src.xres, @src.yres); 22 | 23 | if (pos.x >= size.x || pos.y >= size.y) return; 24 | 25 | float4 blurredColor = 0.0f; 26 | float sumR = 0.0f; 27 | float sumG = 0.0f; 28 | float sumB = 0.0f; 29 | 30 | float alpha = 0.0f; 31 | float sumAlpha = 0.0f; 32 | 33 | const int radius = (int)(3.0f * max(max(@sigma.x, @sigma.y), max(@sigma.z, @sigma.w))); 34 | 35 | for (int dy = -radius; dy <= radius; dy++) { 36 | for (int dx = -radius; dx <= radius; dx++) { 37 | int2 samplePos = pos + (int2)(dx, dy); 38 | if (samplePos.x >= 0 && samplePos.x < size.x && samplePos.y >= 0 && samplePos.y < size.y) { 39 | float4 sample = @src.bufferIndex(samplePos); 40 | 41 | float weightR = gaussian(length((float2)(dx, dy)), @sigma.x); 42 | float weightG = gaussian(length((float2)(dx, dy)), @sigma.y); 43 | float weightB = gaussian(length((float2)(dx, dy)), @sigma.z); 44 | float weightA = gaussian(length((float2)(dx, dy)), @sigma.w); 45 | 46 | blurredColor.x += sample.x * weightR; 47 | blurredColor.y += sample.y * weightG; 48 | blurredColor.z += sample.z * weightB; 49 | alpha += sample.w * weightA; 50 | 51 | sumR += weightR; 52 | sumG += weightG; 53 | sumB += weightB; 54 | sumAlpha += weightA; 55 | } 56 | } 57 | } 58 | 59 | if (sumR > 0.0f) blurredColor.x /= sumR; 60 | if (sumG > 0.0f) blurredColor.y /= sumG; 61 | if (sumB > 0.0f) blurredColor.z /= sumB; 62 | if (sumAlpha > 0.0f) alpha /= sumAlpha; 63 | 64 | blurredColor.w = alpha; 65 | 66 | @blurred.setIndex(pos, blurredColor); 67 | } 68 | -------------------------------------------------------------------------------- /normal_to_height.cl: -------------------------------------------------------------------------------- 1 | /* 2 | @title: NormalToHeightMap_v01 3 | @author: melmass 4 | */ 5 | 6 | // inspired by https://stannum.io/blog/data/debump.c 7 | 8 | #bind layer src float4 9 | #bind layer !&dst float 10 | 11 | #bind parm kernelSize float val=10.0 12 | #bind parm highPassThreshold float val=0.6 13 | #bind parm normalizeOutput float val=1.0 14 | 15 | #bind parm gradientScale float val=2.0 16 | #bind parm gradientBias float val=50.0 17 | 18 | float ctldisf(float x, float y) { return sqrt(x * x + y * y); } 19 | 20 | @KERNEL 21 | void normalToHeightMap() { 22 | 23 | const int2 pos = (int2)(get_global_id(0), get_global_id(1)); 24 | const int2 size = (int2)(@src.xres, @src.yres); 25 | 26 | if (pos.x >= size.x || pos.y >= size.y) return; 27 | 28 | float4 _N = @src.bufferIndex(pos); 29 | 30 | float3 N = _N.rgb; 31 | N = (float3)(2.0,2.0,2.0) * N - (float3)(1.0,1.0,1.0); 32 | if (length(N) < 1e-3) { 33 | @dst.setIndex(pos, 0.0f); 34 | return; 35 | } 36 | 37 | float Gy = 0.0; 38 | float Gx = 0.0; 39 | const int halfKernelSize = @kernelSize / 2; 40 | 41 | for (int y = -halfKernelSize; y <= halfKernelSize; ++y) { 42 | for (int x = -halfKernelSize; x <= halfKernelSize; ++x) { 43 | const int2 neighborPos = pos + (int2)(x, y); 44 | 45 | if (neighborPos.x < 0 || neighborPos.x >= size.x || 46 | neighborPos.y < 0 || neighborPos.y >= size.y) { 47 | continue; 48 | } 49 | 50 | float4 _Nn = @src.bufferIndex(neighborPos); 51 | float3 Nn = _Nn.rgb; 52 | Nn = (float3)(2.0,2.0,2.0) * Nn - (float3)(1.0,1.0,1.0); 53 | 54 | const float distanceWeight = ctldisf((float)(x), (float)(y)) / 55 | ctldisf((float)halfKernelSize, (float)halfKernelSize); 56 | const float normalConsistency = dot(Nn, N); 57 | 58 | if (normalConsistency > @highPassThreshold) { 59 | Gy += distanceWeight * Nn.y * @gradientScale; 60 | Gx -= distanceWeight * Nn.x * @gradientScale; 61 | } 62 | } 63 | } 64 | 65 | const float gradientLength = sqrt(Gx*Gx + Gy*Gy) + @gradientBias; 66 | if (gradientLength > 1e-3) { 67 | Gy /= gradientLength; 68 | Gx /= gradientLength; 69 | } else { 70 | @dst.setIndex(pos, 0.5f); 71 | return; 72 | } 73 | 74 | float height = 0.5; 75 | for (int x = 0; x < pos.x + 1; ++x) { 76 | height -= Gx * 2.0f / size.x; 77 | } 78 | for (int y = 0; y < pos.y + 1; ++y) { 79 | height += Gy * 2.0f / size.y; 80 | } 81 | 82 | if (@normalizeOutput) { 83 | height = (height - 0.5) / 0.5; 84 | height = clamp(height, -1.0f, 1.0f); 85 | height = (height + 1.0f) * 0.5; 86 | } 87 | 88 | @dst.setIndex(pos, height); 89 | } 90 | -------------------------------------------------------------------------------- /weave.cl: -------------------------------------------------------------------------------- 1 | /* 2 | @title: weave_v02 3 | @author: melmass 4 | @description: adaptation of the OSL Weave shader by Zap Andersson 5 | */ 6 | 7 | 8 | // osl shader: 9 | // https://github.com/ADN-DevTech/3dsMax-OSL-Shaders/blob/master/3ds%20Max%20Shipping%20Shaders/Weave.osl 10 | 11 | #import "mtlx_noise_internal.h" 12 | #import "random.h" 13 | 14 | #bind layer !&outColor float4 15 | #bind layer !&outBump float val=0.5 16 | #bind layer !&outId float3 17 | #bind layer !&outOpacity float 18 | 19 | #bind parm scale float val=0.04 20 | #bind parm width float val=0.5 21 | #bind parm roundness float val=1.0 22 | #bind parm roundnessBump float val=1.0 23 | #bind parm roundShadow float val=0.5 24 | #bind parm weaveBump float val=0.5 25 | #bind parm weaveShadow float val=0.25 26 | #bind parm frizz float val=0.0 27 | #bind parm frizzBump float val=0.0 28 | #bind parm frizzScale float val=0.1 29 | #bind parm bendyness float val=0.2 30 | #bind parm bendynessScale float val=3.0 31 | #bind parm braidAmplitude float val=0.0 32 | #bind parm braidFrequency float val=0.5 33 | #bind parm opacityFade float val=0.0 34 | #bind parm seed int val=1 35 | #bind parm u_color float4 val={0.0, 0.5, 0.5, 1.0} 36 | #bind parm v_color float4 val={0.0, 0.25, 0.5, 1.0} 37 | 38 | @KERNEL 39 | { 40 | const int2 pos = (int2)(get_global_id(0), get_global_id(1)); 41 | const int2 size = (int2)(@outColor.xres, @outColor.yres); 42 | 43 | if (pos.x >= size.x || pos.y >= size.y) return; 44 | 45 | @scale = fit01(@scale,0.0f,0.1f); 46 | @frizzScale = max(0.0001f,@frizzScale); 47 | @bendynessScale = max(0.0001f,@bendynessScale); 48 | 49 | float2 uvw = (float2)(pos.x, pos.y) * @scale; 50 | 51 | // add frizz to the width 52 | float frizz = mx_perlin_noise_float_2(uvw / @frizzScale, (int2)(1, 1)); 53 | float w2 = @width + frizz * @frizz; 54 | float w = w2 * 0.5f; 55 | 56 | int uf = (int)floor(uvw.x); 57 | int vf = (int)floor(uvw.y); 58 | 59 | // compute bending 60 | float braidOffset = @braidAmplitude * sin(uvw.y * @braidFrequency * M_PI * 2.0f); 61 | float ubend = mx_perlin_noise_float_2(uvw.y / @bendynessScale + 13.0f * uf, (int2)(1, 1)) * @bendyness + braidOffset; 62 | float vbend = mx_perlin_noise_float_2(uvw.x / @bendynessScale + 23.0f * vf, (int2)(1, 1)) * @bendyness; 63 | 64 | // compute thread coordinates 65 | float sx = uvw.x - uf + ubend; 66 | float sy = uvw.y - vf + vbend; 67 | 68 | int onU = (sy > 0.5f - w && sy < 0.5f + w); 69 | int onV = (sx > 0.5f - w && sx < 0.5f + w); 70 | 71 | float uu = (sy - (0.5f - w)) / w2; 72 | float vv = (sx - (0.5f - w)) / w2; 73 | 74 | // odd or even U / V 75 | int oddU = uf % 2; 76 | int oddV = vf % 2; 77 | 78 | // Are we on neither thread? 79 | if (onU == 0 && onV == 0) 80 | { 81 | // set background color to black/transparent per layer 82 | @outColor.setIndex(pos, (float4)(0.0f, 0.0f, 0.0f, 0.0f)); 83 | @outBump.setIndex(pos, 0.0f); 84 | @outId.setIndex(pos, (float3)(0.0f, 0.0f, 0.0f)); 85 | @outOpacity.setIndex(pos, 0.0f); 86 | return; 87 | } 88 | 89 | int U_on_top = (oddU ^ oddV) == 0; 90 | 91 | int per = 1; 92 | 93 | // both - disambiguate 94 | if (onU && onV) 95 | { 96 | onU = U_on_top; 97 | onV = (onU == 0); 98 | } 99 | 100 | // random ID for thread 101 | int ThreadID = 1 + (int)((mx_cell_noise_float_1((float)uf + @seed + 45, per) * onV + mx_cell_noise_float_1((float)vf + @seed + 32, per) * onU) * 1024.0f) + onU; 102 | float3 IdColor = VEXrandom_1_3((float)ThreadID + @seed); 103 | 104 | // which color to return 105 | float4 Col; 106 | if (onU) 107 | Col = @u_color; 108 | else 109 | Col = @v_color; 110 | 111 | // compute bump and fake "shadowing" 112 | float r = @roundness; 113 | float weave = (onU) ? sin((uvw.x + oddV) * M_PI) : sin((uvw.y + oddU + 1.0f) * M_PI); 114 | 115 | float ubulge = sin(uu * M_PI); 116 | float vbulge = sin(vv * M_PI); 117 | 118 | float bulge = pow((onU ? ubulge : vbulge), r); 119 | 120 | float opacity = max(pow(ubulge, @opacityFade), pow(vbulge, @opacityFade)); 121 | 122 | float bump = 0.2f + weave * @weaveBump + bulge * @roundnessBump + frizz * @frizzBump; 123 | 124 | Col *= mix(1.0f, bulge, @roundShadow); 125 | Col *= mix(1.0f, weave, @weaveShadow); 126 | 127 | @outColor.setIndex(pos, Col); 128 | @outBump.setIndex(pos, bump); 129 | @outId.setIndex(pos, IdColor); 130 | @outOpacity.setIndex(pos, opacity); 131 | } 132 | 133 | -------------------------------------------------------------------------------- /edge_detect.cl: -------------------------------------------------------------------------------- 1 | /* 2 | @title: edge_detect_v01 3 | @author: melmass 4 | */ 5 | 6 | // INFO: kept for reference but it should be broke down into multiple kernels to work properly. 7 | // the builtin EdgeDetect COP is built like that and is a great reference. 8 | 9 | #bind layer src float 10 | #bind layer !&dst float 11 | 12 | #bind parm low_threshold float 13 | #bind parm high_threshold float 14 | #bind parm gaussian_sigma float 15 | 16 | float gaussian(float x, float sigma) { 17 | return exp(-(x*x) / (2.0f * sigma*sigma)) / (sqrt(2.0f * M_PI) * sigma); 18 | } 19 | 20 | @KERNEL 21 | { 22 | const int2 pos = (int2)(get_global_id(0), get_global_id(1)); 23 | const int2 size = (int2)(@src.xres, @src.yres); 24 | 25 | if (pos.x >= size.x || pos.y >= size.y) return; 26 | 27 | float blurred = 0.0f; 28 | const int radius = (int)(3.0f * @gaussian_sigma); 29 | float sum = 0.0f; 30 | 31 | for (int dy = -radius; dy <= radius; dy++) { 32 | for (int dx = -radius; dx <= radius; dx++) { 33 | int2 samplePos = pos + (int2)(dx, dy); 34 | if (samplePos.x >= 0 && samplePos.x < size.x && samplePos.y >= 0 && samplePos.y < size.y) { 35 | float sample = @src.bufferIndex(samplePos); 36 | float weight = gaussian(length((float2)(dx, dy)), @gaussian_sigma); 37 | blurred += sample * weight; 38 | sum += weight; 39 | } 40 | } 41 | } 42 | blurred /= sum; 43 | 44 | // compute gradient 45 | float gx = 0.0f, gy = 0.0f; 46 | float sobelX[3] = {-1.0f, 0.0f, 1.0f}; 47 | float sobelY[3] = {1.0f, 2.0f, 1.0f}; 48 | 49 | for (int i = -1; i <= 1; i++) { 50 | for (int j = -1; j <= 1; j++) { 51 | int2 samplePos = pos + (int2)(i, j); 52 | float sampleBlurred = 0.0f; 53 | float sampleSum = 0.0f; 54 | 55 | // hacky way to sample blurred pixel... 56 | for (int dy = -radius; dy <= radius; dy++) { 57 | for (int dx = -radius; dx <= radius; dx++) { 58 | int2 blurPos = samplePos + (int2)(dx, dy); 59 | if (blurPos.x >= 0 && blurPos.x < size.x && blurPos.y >= 0 && blurPos.y < size.y) { 60 | float sample = @src.bufferIndex(blurPos); 61 | float weight = gaussian(length((float2)(dx, dy)), @gaussian_sigma); 62 | sampleBlurred += sample * weight; 63 | sampleSum += weight; 64 | } 65 | } 66 | } 67 | sampleBlurred /= sampleSum; 68 | 69 | gx += sampleBlurred * sobelX[i+1] * sobelY[j+1]; 70 | gy += sampleBlurred * sobelY[i+1] * sobelX[j+1]; 71 | } 72 | } 73 | 74 | float gradientMagnitude = sqrt(gx*gx + gy*gy); 75 | float gradientDirection = atan2(gy, gx); 76 | 77 | float angle = (gradientDirection > 0 ? gradientDirection : (gradientDirection + M_PI)) * 180.0f / M_PI; 78 | int2 q = (int2)(0, 0), r = (int2)(0, 0); 79 | 80 | if ((angle >= 0 && angle < 22.5) || (angle >= 157.5 && angle <= 180)) { 81 | q = r = (int2)(1, 0); 82 | } else if (angle >= 22.5 && angle < 67.5) { 83 | q = (int2)(1, 1); r = (int2)(-1, -1); 84 | } else if (angle >= 67.5 && angle < 112.5) { 85 | q = r = (int2)(0, 1); 86 | } else if (angle >= 112.5 && angle < 157.5) { 87 | q = (int2)(-1, 1); r = (int2)(1, -1); 88 | } 89 | 90 | float magnitudeQ = 0.0f, magnitudeR = 0.0f; 91 | float sumQ = 0.0f, sumR = 0.0f; 92 | 93 | 94 | for (int dy = -radius; dy <= radius; dy++) { 95 | for (int dx = -radius; dx <= radius; dx++) { 96 | int2 qPos = pos + q + (int2)(dx, dy); 97 | int2 rPos = pos + r + (int2)(dx, dy); 98 | float weight = gaussian(length((float2)(dx, dy)), @gaussian_sigma); 99 | 100 | if (qPos.x >= 0 && qPos.x < size.x && qPos.y >= 0 && qPos.y < size.y) { 101 | magnitudeQ += @src.bufferIndex(qPos) * weight; 102 | sumQ += weight; 103 | } 104 | if (rPos.x >= 0 && rPos.x < size.x && rPos.y >= 0 && rPos.y < size.y) { 105 | magnitudeR += @src.bufferIndex(rPos) * weight; 106 | sumR += weight; 107 | } 108 | } 109 | } 110 | magnitudeQ /= sumQ; 111 | magnitudeR /= sumR; 112 | 113 | if (gradientMagnitude < magnitudeQ || gradientMagnitude < magnitudeR) { 114 | gradientMagnitude = 0.0f; 115 | } 116 | 117 | // edge 118 | float result; 119 | if (gradientMagnitude > @high_threshold) { 120 | result = 1.0f; 121 | } else if (gradientMagnitude > @low_threshold) { 122 | result = 0.5f; 123 | } else { 124 | result = 0.0f; 125 | } 126 | 127 | @dst.setIndex(pos, result); 128 | } 129 | --------------------------------------------------------------------------------