unity地形之splatalpha研究 地形贴图导出更换与绘制

unity中的地图贴图的绘制常常使用的是paint texture里面的

但是这个方式往往费时很多,却只能做出很少的效果,这里要介绍的就是通过外部绘制splatalpha

来替换,达到unity中地形更强的效果

使用软件基本有worldmachine,ps,unity




地形一般的流程通常是创建了地形,先刷高度,然后再进行贴图的绘制,

可以看到保存文件之后,project中会生成一个terrain文件,并且可以点开

里面通常会至少有一个splatalpha,这个存储的就是你画贴图的位置

其实这个地形贴图相当于组合而成的四个mask,分别表示了4种贴图所占的位置以及混合程度

每4种会产生一个新的splatalpha,这其实一个texture格式,包含了4个通道,红绿蓝和alpha通道


然后大家可能发现这些图片是不能导出也不能在外部修改的,

如果是外部软件比如worldmachine生成的就只能当成一张大的texture贴上去,会造成很大的性能浪费,

而且不能当场mask使用新的更细致的纹理

所以这里给出一种新的方式,当然也是worldmachine官网的方式

可以替换splatalpha达到使用外部生成的地形纹理mask的目的

https://www.world-machine.com/learn.php?page=workflow&workflow=wfunity

下面是我组合好了官网的脚本ReplaceSplatmap.js

import System.IO;
//combine by shenmifangke  
class ReplaceSplatmap extends ScriptableWizard
{
var Splatmap: Texture2D;
var New : Texture2D;
var FlipVertical : boolean;

 function OnWizardUpdate(){
        helpString = "Replace the existing splatmap of your terrain with a new one.\nDrag the embedded splatmap texture of your terrain to the 'Splatmap box'.\nThen drag the replacement splatmap texture to the 'New' box\nThen hit 'Replace'.";
        isValid = (Splatmap != null) && (New != null);
    }
	
function OnWizardCreate () {
   
   	if (New.format != TextureFormat.ARGB32 && New.format != TextureFormat.RGB24) {
		EditorUtility.DisplayDialog("Wrong format", "Splatmap must be converted to ARGB 32 bit format.\nMake sure the type is Advanced and set the format!", "Cancel"); 
		return;
	}
	
	var w = New.width;
	if (Mathf.ClosestPowerOfTwo(w) != w) {
		EditorUtility.DisplayDialog("Wrong size", "Splatmap width and height must be a power of two!", "Cancel"); 
		return;	
	}  

    try {
    	var pixels = New.GetPixels();	
		if (FlipVertical) {
			var h = w; // always square in unity
			for (var y = 0; y < h/2; y++) {
				var otherY = h - y - 1;	
				for (var x  = 0; x < w; x++) {
					var swapval = pixels[y*w + x];					
					pixels[y*w + x] = pixels[otherY*w + x];
					pixels[otherY*w + x] = swapval;
				}		
			}
		}
		Splatmap.Resize (New.width, New.height, New.format, true);
		Splatmap.SetPixels (pixels);
		Splatmap.Apply();
    }
    catch (err) {
		EditorUtility.DisplayDialog("Not readable", "The 'New' splatmap must be readable. Make sure the type is Advanced and enable read/write and try again!", "Cancel"); 
		return;
	}			
}
//http://blog.csdn.net/shenmifangke
@MenuItem("Terrain/Replace Splatmap...")
static function Replace (){
    ScriptableWizard.DisplayWizard(
        "ReplaceSplatmap", ReplaceSplatmap, "Replace");
}


@MenuItem("Terrain/Export Texture")
    static function Apply()
{
    var texture : Texture2D = Selection.activeObject as Texture2D;
    if (texture == null)
    {
        EditorUtility.DisplayDialog("Select Texture", "You Must Select a Texture first!", "Ok");
        return;
    }

    var bytes = texture.EncodeToPNG();
    File.WriteAllBytes(Application.dataPath + "/exported_texture.png", bytes);
}
}
放在Editor目录下,就会发现多出来terrain菜单里面两项

第一个是替换splatalpha,第二个是把splatalpha贴图导出成png图片,会保存在工程目录assets里

这两个是极其有用的地形扩展脚本

下面具体来说说方式和我研究的过程


首先从第二个导出aplatalpha说起

导出png,这里导出的png不是一般的png,而是带有四个通道“完整”png,类似于存储了透明通道的32位tga之类的格式

我们通常会用图像处理软件比如ps等来处理图片,但是它有个问题,就是打开这个png的时候

会把alpha通道视为透明通道从而让颜色通道里的信息损失

比如下面一张图片,直接看会发现只有半个三角形(这张图是处理过的含有4个完整通道的png 地形导出png也会导出类似的png)


你可以保存下来在ps里打开,但是同样是这样,左侧半边的颜色信息缺失了,

但我可以告诉你实际上左侧三角形是有颜色信息的,只是ps里没有办法把png显示成4个通道,所以只能把最后一个非rgb通道识别成透明通道(什么,还有ps没法办到的事0 0,其实真有,不过这个可以用某些ps插件来解决)

这只是ps等常用软件无法分离四个通道的png而已,其他软件是可以的

比如unity本身,ae,nuke等等中,如下面就是用nuke处理分离颜色和透明通道


或者这里做了个确认性的测试,用的是openframeworks

#include "ofApp.h"
ofImage temp;
ofImage temp2;
//--------------------------------------------------------------
void ofApp::setup(){
temp.loadImage("a.png");
temp2.loadImage("a.png");
ofPixels pixels = temp.getPixelsRef();

ofPixels noAlpha;
noAlpha.allocate(temp.getWidth(),temp.getHeight(),OF_IMAGE_COLOR);
noAlpha.setChannel(0,pixels.getChannel(0));
noAlpha.setChannel(1,pixels.getChannel(1));
noAlpha.setChannel(2,pixels.getChannel(2));

temp.setFromPixels(noAlpha);
}

//--------------------------------------------------------------
void ofApp::update(){

}

void ofApp::draw(){
temp.draw(0,0);
temp2.draw(512,0);
}
void ofApp::keyPressed(int key){}
void ofApp::keyReleased(int key){}
void ofApp::mouseMoved(int x, int y ){}
void ofApp::mouseDragged(int x, int y, int button){}
void ofApp::mousePressed(int x, int y, int button){}
void ofApp::mouseReleased(int x, int y, int button){}
void ofApp::windowResized(int w, int h){}
void ofApp::gotMessage(ofMessage msg){}
void ofApp::dragEvent(ofDragInfo dragInfo){}


可以看到png中透明部分确实还有rgb信息


然后就是替换splatalpha

新的作为splatalpha的图片记得要在unity中设置如下,否则无法成功替换



用terrain菜单的中第一个替换图片后,然后会发现似乎是成功了(这里随意加了4种纹理)



然而随意画一笔就会发现好像有方块的效果,这不是我们想要的


其实这个问题是由你的png造成的,一般从unity里导出的png就不会有这个问题,

所以在此分析了下,发现splatalpha还有其他的限定条件

那就是所有通道每个像素白色亮度的加成必须是1,如果不是就会产生这种问题,

因为地形上你每画一笔贴图,那个层上的亮度(就是对应的rgba值)就会增加,但其他层会相应的减少,总和维持不变,所以我们必须想办法把所有通道的值值和不大于1(不足的会是黑色表示)超出的话即便是透明渐变笔刷,刷出来也会是方块效果

修正完后效果就会正常如下(无视黑色地方吧),就可以在unity中进一步加工了



当然外部处理的地形贴图最好还是以tga之类的格式存储,防止有人不知道这个

tga也要注意存成32位的还要勾选alpha通道才行






评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值