public override string getFunctionBody(BaseNode.NodeInput nodeInput) { var node = nodeInput.inputNode; RecolorNode recolor = (RecolorNode)node; string shaderStr = " float3 inC = input1.rgb;\n" + " float numSlices = 62.0;\n" + " float slicePixels = 64.0;\n" + " float sliceSize = 1.0 / numSlices; // space of 1 slice\n" + " float slicePixelSize = sliceSize / slicePixels; // space of 1 pixel\n" + " float sliceInnerSize = slicePixelSize * (slicePixels - 1.0); //space of size pixels\n" + " float zSlice0 = min(floor(inC.b * numSlices), numSlices - 1.0);\n" + " float xOffset = slicePixelSize * 0.5 + inC.r * sliceInnerSize;\n" + " float s0 = xOffset + (zSlice0 * sliceSize);\n" + " float2 mapUV;\n" + " mapUV.x = s0;\n" + " mapUV.y = inC.g;// (inC.g * (62.0/64.0)) + (1.0/64.0);\n" + " float4 col1 = tex2D(mapTexture" + node.getNodeID() + ", mapUV);\n"; if (recolor.InterpolateSliceSamples) { shaderStr += " float zSlice1 = min(zSlice0 + 1.0, numSlices - 1.0);\n" + " float s1 = xOffset + (zSlice1 * sliceSize);\n" + " float fr = frac(inC.b * numSlices);\n" + " mapUV.x = s1;\n" + " float4 col2 = tex2D(mapTexture" + node.getNodeID() + ", mapUV);\n" + " float4 c = lerp(col1, col2, fr);\n" + " return c;\n"; } else { shaderStr += " return col1;\n"; } return(shaderStr); }
public override List <string> generateAssets(BaseNode node) { RecolorNode recolor = (RecolorNode)node; int dim3D = 62; int dim2D = dim3D + 2; float oneOverDim = 1.0f / (float)(dim3D - 1); //when unrolling to the 2d array we will pad 1 pixel around each 3d dim3D*dim3D "layer" // .. so the 2d texture is (dim3D+2)*((dim3D+2)*(dim3D+2)) var colorArray3D = new Color[dim3D, dim3D, dim3D]; //precalculate the x,y,z position of each input color List <Vector3> mapColorPositions = new List <Vector3>(); foreach (var mapping in recolor.colorRemapping) { var inC = mapping.InColor; var pos = new Vector3(); pos.x = inC.r / oneOverDim; pos.y = inC.g / oneOverDim; pos.z = inC.b / oneOverDim; mapColorPositions.Add(pos); } for (int x = 0; x < dim3D; x++) { for (int y = 0; y < dim3D; y++) { for (int z = 0; z < dim3D; z++) { Vector3 pixelPos = new Vector3(x, y, z); //calculate RGB at this position //use Vector3 so we can interpolate without Color clamping us to 0..255 or anything Vector3 cVec = new Vector3( x * oneOverDim, y * oneOverDim, z * oneOverDim ); //calculate alpha value at this position for each color mapping for (int mapIndex = 0; mapIndex < recolor.colorRemapping.Count; mapIndex++) { var mapping = recolor.colorRemapping[mapIndex]; var mapColor = mapping.OutColor; var mapColorVec = new Vector3(mapColor.r, mapColor.g, mapColor.b); var colorPos = mapColorPositions[mapIndex]; //"alpha" in the mapping is a measure of how wide an effect this mapping has //0 - replace this exact mapping and nothing else //1 - has an influence over the entire color cube //at each pixel calculate an offset Vector3 colorOffset = colorPos - pixelPos; //multiply offset by alpha float alphaT = Mathf.Clamp01(colorOffset.magnitude * oneOverDim); float alpha = mapping.AlphaCurve.Evaluate(alphaT); if (alpha > 0.0f) { //use to lerp the colors cVec = Vector3.Lerp(cVec, mapColorVec, alpha); } } //write out to 3d array Color c = new Color(cVec.x, cVec.y, cVec.z, 1.0f); colorArray3D[x, y, z] = c; } //z } //y } //x //make sure even for mappings with alpha of 0 we at least poke a single value in at full strength at the closest position for (int mapIndex = 0; mapIndex < recolor.colorRemapping.Count; mapIndex++) { var mapping = recolor.colorRemapping[mapIndex]; var mapColor = mapping.OutColor; var mapColorPos = mapColorPositions[mapIndex]; colorArray3D[Mathf.FloorToInt(mapColorPos.x), Mathf.FloorToInt(mapColorPos.y), Mathf.FloorToInt(mapColorPos.z)] = mapColor; } int width2D = dim3D * dim2D; int height2D = dim2D; var colorArray2D = new Color[width2D * height2D]; //flattened 2D array, where pixels are laid out left to right, bottom to top for (int x = 0; x < dim3D; x++) { for (int y = 0; y < dim3D; y++) { for (int z = 0; z < dim3D; z++) { var c = colorArray3D[x, y, z]; int index2D = (x + 1) + ((y + 1) * width2D) + (z * dim2D); colorArray2D[index2D] = c; } } } for (int slice = 0; slice < dim3D; slice++) { //copy 1st column { int x = 0; for (int y = 0; y < dim3D; y++) { int dstIndex2D = (x) + ((y + 1) * width2D) + (slice * dim2D); int srcIndex2D = (x + 1) + ((y + 1) * width2D) + (slice * dim2D); colorArray2D[dstIndex2D] = colorArray2D[srcIndex2D]; } } //copy 2nd column { int x = dim2D - 1; for (int y = 0; y < dim3D; y++) { int dstIndex2D = (x) + ((y + 1) * width2D) + (slice * dim2D); int srcIndex2D = (x - 1) + ((y + 1) * width2D) + (slice * dim2D); colorArray2D[dstIndex2D] = colorArray2D[srcIndex2D]; } } //copy 1st row { int y = 0; for (int x = 0; x < dim3D; x++) { int dstIndex2D = (x + 1) + ((y) * width2D) + (slice * dim2D); int srcIndex2D = (x + 1) + ((y + 1) * width2D) + (slice * dim2D); colorArray2D[dstIndex2D] = colorArray2D[srcIndex2D]; } } //copy 1st row { int y = dim2D - 1; for (int x = 0; x < dim3D; x++) { int dstIndex2D = (x + 1) + ((y) * width2D) + (slice * dim2D); int srcIndex2D = (x + 1) + ((y - 1) * width2D) + (slice * dim2D); colorArray2D[dstIndex2D] = colorArray2D[srcIndex2D]; } } //4 corners { int x = 0; int y = 0; int dstIndex2D = (x) + ((y) * width2D) + (slice * dim2D); int srcIndex2D = (x + 1) + ((y) * width2D) + (slice * dim2D); colorArray2D[dstIndex2D] = colorArray2D[srcIndex2D]; y = dim2D - 1; dstIndex2D = (x) + ((y) * width2D) + (slice * dim2D); srcIndex2D = (x + 1) + ((y) * width2D) + (slice * dim2D); colorArray2D[dstIndex2D] = colorArray2D[srcIndex2D]; x = dim2D - 1; y = dim2D - 1; dstIndex2D = (x) + ((y) * width2D) + (slice * dim2D); srcIndex2D = (x - 1) + ((y) * width2D) + (slice * dim2D); colorArray2D[dstIndex2D] = colorArray2D[srcIndex2D]; y = 0; dstIndex2D = (x) + ((y) * width2D) + (slice * dim2D); srcIndex2D = (x - 1) + ((y) * width2D) + (slice * dim2D); colorArray2D[dstIndex2D] = colorArray2D[srcIndex2D]; } } var tex2D = new Texture2D(width2D, dim2D, TextureFormat.ARGB32, false); tex2D.SetPixels(colorArray2D); tex2D.Apply(); string assetPathAndName = "/test.png"; byte[] bytes = tex2D.EncodeToPNG(); File.WriteAllBytes("Assets" + assetPathAndName, bytes); // set the texture reference in the RecolorNode AssetDatabase.ImportAsset("Assets" + assetPathAndName); Texture2D mapTexture = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets" + assetPathAndName, typeof(Texture2D)); recolor.mapColorTexture = mapTexture; List <string> textureAssetPaths = new List <string>(); return(textureAssetPaths); }