2012-10-22 3 views
3

Note that much of this code as changed as of edit 3 below.Three.js 맞춤 셰이더

그래서 저는 Brandon Jones (found here)의 블로그 게시물을 정말 좋아합니다. 코드를 Three.js로 변환하려고했지만 몇 가지 문제가 있습니다. 그의 전체 코드 here을 찾을 수 있습니다. 나는 여기 내 시도가 질문에 대한 몇 가지 의견과 함께, 지금까지입니다이 :이 함께 할 수있다 확신

TypeError: v1 is undefined 
    customAttribute.array[ offset_custom ] = v1.x; 

:

// Shader 
var tilemapVS = [ 
    "attribute vec2 pos;", 
    "attribute vec2 texture;", 

    "varying vec2 pixelCoord;", 
    "varying vec2 texCoord;", 

    "uniform vec2 viewOffset;", 
    "uniform vec2 viewportSize;", 
    "uniform vec2 inverseTileTextureSize;", 
    "uniform float inverseTileSize;", 

    "void main(void) {", 
    " pixelCoord = (texture * viewportSize) + viewOffset;", 
    " texCoord = pixelCoord * inverseTileTextureSize * inverseTileSize;", 
    " gl_Position = vec4(pos, 0.0, 1.0);", 
    "}" 
].join("\n"); 

var tilemapFS = [ 
    "precision highp float;", 

    "varying vec2 pixelCoord;", 
    "varying vec2 texCoord;", 

    "uniform sampler2D tiles;", 
    "uniform sampler2D sprites;", 

    "uniform vec2 inverseTileTextureSize;", 
    "uniform vec2 inverseSpriteTextureSize;", 
    "uniform float tileSize;", 
    "uniform int repeatTiles;", 

    "void main(void) {", 
    " if(repeatTiles == 0 && (texCoord.x < 0.0 || texCoord.x > 1.0 || texCoord.y < 0.0 || texCoord.y > 1.0)) { discard; }", 
    " vec4 tile = texture2D(tiles, texCoord);", 
    " if(tile.x == 1.0 && tile.y == 1.0) { discard; }", 
    " vec2 spriteOffset = floor(tile.xy * 256.0) * tileSize;", 
    " vec2 spriteCoord = mod(pixelCoord, tileSize);", 
    " gl_FragColor = texture2D(sprites, (spriteOffset + spriteCoord) * inverseSpriteTextureSize);", 
    //" gl_FragColor = tile;", 
    "}" 
].join("\n"); 

this.material = new THREE.ShaderMaterial({ 
    attributes: { 
     //not really sure what to use here, he uses some quadVertBuffer 
     //for these values, but not sure how to translate. 
     pos: { type: 'v2', value: new THREE.Vector2(0, 0) }, 
     texture: { type: 'v2', value: new THREE.Vector2(0, 0) } 
    }, 
    uniforms: { 
     viewportSize: { type: 'v2', value: new THREE.Vector2(viewport.width()/this.tileScale, viewport.height()/this.tileScale) }, 
     inverseSpriteTextureSize: { type: 'v2', value: new THREE.Vector2(1/tileset.image.width, 1/tileset.image.height) }, 
     tileSize: { type: 'f', value: this.tileSize }, 
     inverseTileSize: { type: 'f', value: 1/this.tileSize }, 

     tiles: { type: 't', value: tilemap }, 
     sprites: { type: 't', value: tileset }, 

     viewOffset: { type: 'v2', value: new THREE.Vector2(Math.floor(0), Math.floor(0)) }, 
     inverseTileTextureSize: { type: 'v2', value: new THREE.Vector2(1/tilemap.image.width, 1/tilemap.image.height) }, 
     //is 'i' the correct type for an int? 
     repeatTiles: { type: 'i', value: 1 } 
    }, 
    vertexShader: tilemapVS, 
    fragmentShader: tilemapFS, 
    transparent: false 
}); 

/*this.material = new THREE.MeshBasicMaterial({ 
    color: 0xCC0000 
})*/ 

this.plane = new THREE.PlaneGeometry(
    tilemap.image.width * this.tileSize * this.tileScale, //width 
    tilemap.image.height * this.tileSize * this.tileScale//, //height 
    //tilemap.image.width * this.tileScale, //width-segments 
    //tilemap.image.height * this.tileScale //height-segments 
); 

this.plane.dynamic = true; 

this.mesh = new THREE.Mesh(this.plane, this.material); 

나는 다음과 같은 오류가 페이지를로드하면 어떻게 특성을 설정했는지, 그러나 나는 그들이 무엇을해야하는지 잘 모르겠습니다. Three.js의 Custom Shaders에 대한 문서가 거의 없기 때문에 도움을 주시면 감사하겠습니다.

편집는 :

//in ctor 
var quadVerts = [ 
    //x y u v 
    -1, -1, 0, 1, 
    1, -1, 1, 1, 
    1, 1, 1, 0, 

    -1, -1, 0, 1, 
    1, 1, 1, 0, 
    -1, 1, 0, 0 
]; 

this.quadVertBuffer = gl.createBuffer(); 
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVertBuffer); 
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(quadVerts), gl.STATIC_DRAW); 

this.tilemapShader = GLUtil.createProgram(gl, tilemapVS, tilemapFS); 

//... 

//then on the draw method 
gl.bindBuffer(gl.ARRAY_BUFFER, this.quadVertBuffer); 

gl.enableVertexAttribArray(shader.attribute.position); 
gl.enableVertexAttribArray(shader.attribute.texture); 
gl.vertexAttribPointer(shader.attribute.position, 2, gl.FLOAT, false, 16, 0); 
gl.vertexAttribPointer(shader.attribute.texture, 2, gl.FLOAT, false, 16, 8); 

정말 완전히 정확히 이해하지 않습니다 다음은 버텍스 쉐이더의 두 속성을 채우기 위해 블로그 게시물에 사용되는 코드 (pos, 그리고 texture)입니다 여기에서 일어난다. 그러나 내가 정확하면 나는 그것이 각각 quadVertBuffer의 반 데이터와 함께 2 Float32Array를 채우고 있다고 생각한다. 이유가 확실하지 않을뿐만 아니라, 내가 맞는지 확실하지 않을뿐만 아니라 이것을 Three.js 메서드로 변환하는 방법을 알지 못합니다.


EDIT2 은 : 지금 나는 (2D) 배경을 표시하기 위해 비행기를 사용하고 내가 대신 스프라이트를 사용 하는가?


EDIT3 : 나는 Three.js를 위치/질감 등의 경우 동일하지 비슷한 것 같다 나를 위해 위치와 자외선 벡터를 (설정 것을 깨달았을 때

그래서 좀 더있어 위의 예에서). 또한 'v2' 유형 중 많은 수가 (uniform2f을 호출하는) 실제로 uniform2fv을 통해로드 되었기 때문에 일부 유형이 잘못되었을 수 있음을 알아 냈으므로 그 값을 'v2v'으로 변경하고 값을 업데이트했습니다. 이제 오류 메시지가 나타나지 않고 무언가 인을 타일링합니다. 내가 얻을

this._material = new THREE.ShaderMaterial({ 
    uniforms: { 
     viewportSize: { type: 'v2v', value: [new THREE.Vector2(viewport.width()/this.tileScale, viewport.height()/this.tileScale)] }, 
     inverseSpriteTextureSize: { type: 'v2v', value: [new THREE.Vector2(1/tileset.image.width, 1/tileset.image.height)] }, 
     tileSize: { type: 'f', value: this.tileSize }, 
     inverseTileSize: { type: 'f', value: 1/this.tileSize }, 

     tiles: { type: 't', value: tilemap }, 
     sprites: { type: 't', value: tileset }, 

     viewOffset: { type: 'v2', value: new THREE.Vector2(0, 0) }, 
     inverseTileTextureSize: { type: 'v2v', value: [new THREE.Vector2(1/tilemap.image.width, 1/tilemap.image.height)] }, 
     repeatTiles: { type: 'i', value: 1 } 
    }, 
    vertexShader: tilemapVS, 
    fragmentShader: tilemapFS, 
    transparent: false 
}); 

그리고 여기 결과입니다 :

enter image description here

어떤을

var tilemapVS = [ 
    "varying vec2 pixelCoord;", 
    "varying vec2 texCoord;", 

    "uniform vec2 viewOffset;", 
    "uniform vec2 viewportSize;", 
    "uniform vec2 inverseTileTextureSize;", 
    "uniform float inverseTileSize;", 

    "void main(void) {", 
    " pixelCoord = (uv * viewportSize) + viewOffset;", 
    " texCoord = pixelCoord * inverseTileTextureSize * inverseTileSize;", 
    " gl_Position = vec4(position.x, position.y, 0.0, 1.0);", 
    "}" 
].join("\n"); 

및 업데이트 된 쉐이더 재질 : 여기

업데이트 된 버텍스 쉐이더입니다 아이디어를 환영합니다!


EDIT 4 : 나는 내가 더 가까이 얻을 수 gl_Position 설정의 "Three.js를 방법"으로 발견 한 것을 사용하는 버텍스 셰이더를 변경할 수 있지만, 오프셋 경우

입니다 스프라이트 시트가 잘못되었습니다.나는 pixelCoord 변화가 틀렸다고 생각한다. (uvtexture과 약간 다른 값을 가지고 있기 때문에).

난에 버텍스 쉐이더의 주요 기능을 변경 :

void main(void) { 
    pixelCoord = (uv * viewportSize) + viewOffset; 
    texCoord = pixelCoord * inverseTileTextureSize * inverseTileSize; 
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 
} 

지금은 실제 타일 텍스처 시트를 형성 얻을하지만 선택 실제 타일은 잘못된 것입니다 : 점점

enter image description here

더 가까이서, 어떤 도움이 여전히 감사하겠습니다.


편집 5 :

는 내가 대답을 가지고 가까이 나처럼이 내 마지막 업데이트 될 것입니다 생각한다. tileset.flipY = false;을 설정 한 후, 타일셋은 실제 텍스처 타일이고 빨간색 맵은 아닙니다. 나는 적당한 장소에 착륙하는 모든 올바른 타일을 얻는다. 그들은 모두 뒤집어 져있다. 여기

는이 변경 후 모습입니다 :합니다 (타일 세트의 이미지를 편집하지 않고) Y 축에 대한 각 개별 텍스처를 반전 할 수있는 방법은

enter image description here

있습니까? 내 셰이더에 추가 할 수있는 간단한 벡터 수학이있는 것처럼 느껴진다.

나는 (tilemap.flipY = false;tileset.flipY = false;) 두 가지를 바꿔 쓰지 않으면 올바르게 맞춰진 올바른 질감의 텍스쳐를 얻을 수 있다는 점에 유의하십시오. 그러나 전체지도가 거꾸로되어 있습니다! 너무 가까이 ...

enter image description here

+0

* 전체 코드에 대한 링크를 공유 할 수있는 기회가 있으십니까? 오류를 디버그 할 수있는 작업 링크가 있으면 더 좋습니다. – mrdoob

+0

@mrdoob 물론, https://github.com/englercj/lttp-webgl이 코드입니다. 그냥 복제하여 index.html을 열 수 있습니다. "Load Resources"를 선택하고 "Launch Game"을 선택하십시오. 문제의 코드는 주로'js/game/lib/core/TileMap.js'에서 찾을 수 있습니다.이 코드는'js/game/lib/core/Engine.js'에서 인스턴스화되고 장면에 추가됩니다. 'resources' 객체의 모든 속성은'THREE.Texture'가'THREE.TextureLoader'로로드됩니다. 감사! – Chad

+0

나는 brandon의 코드도 참조 용으로 가지고 있지만, 사용되지는 않습니다 ('brandons_' 접두사가 붙습니다). – Chad

답변

1

나는이 나는 그것이 "고정"생각하지 않지만 "작업"수있었습니다.

나는 거꾸로 스프라이트 시트 (타일 세트)에 각 타일 을 그릴 (도지 그 다음 타일 맵을 만듭니다 쓴)를 tilemap (tilemap.flipY = true은)는 타일 세트 (tileset.flipY = false)를 unflipped 다음 mapmaker.html을 수정 튀 겼다.

나는 이와 같은 문제를 해결하기 위해 실제로 문제를 해결하는 다른 대답을 선호하지만, 지금은 이것이 내 해결책입니다.

다음은 관련 코드입니다.

셰이더 (tilemaptilesetTHREE.Texture S이다)

var tilemapVS = [ 
    "varying vec2 pixelCoord;", 
    "varying vec2 texCoord;", 

    "uniform vec2 viewOffset;", 
    "uniform vec2 viewportSize;", 
    "uniform vec2 inverseTileTextureSize;", 
    "uniform float inverseTileSize;", 

    "void main(void) {", 
    " pixelCoord = (uv * viewportSize) + viewOffset;", 
    " texCoord = pixelCoord * inverseTileTextureSize * inverseTileSize;", 
    " gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);", 
    "}" 
].join("\n"); 

var tilemapFS = [ 
    //"precision highp float;", 

    "varying vec2 pixelCoord;", 
    "varying vec2 texCoord;", 

    "uniform sampler2D tiles;", 
    "uniform sampler2D sprites;", 

    "uniform vec2 inverseTileTextureSize;", 
    "uniform vec2 inverseSpriteTextureSize;", 
    "uniform float tileSize;", 
    "uniform int repeatTiles;", 

    "void main(void) {", 
    " vec4 tile = texture2D(tiles, texCoord);", //load this pixel of the tilemap 
    " if(tile.x == 1.0 && tile.y == 1.0) { discard; }", //discard if R is 255 and G is 255 
    " vec2 spriteOffset = floor(tile.xy * 256.0) * tileSize;", //generate the offset in the tileset this pixel represents 
    " vec2 spriteCoord = mod(pixelCoord, tileSize);", 
    " vec4 texture = texture2D(sprites, (spriteOffset + spriteCoord) * inverseSpriteTextureSize);", 
    " gl_FragColor = texture;", 
    "}" 
].join("\n"); 

쉐이더 재질 :

//Setup Tilemap 
tilemap.magFilter = THREE.NearestFilter; 
tilemap.minFilter = THREE.NearestMipMapNearestFilter; 
if(this.repeat) { 
    tilemap.wrapS = tilemap.wrapT = THREE.RepeatWrapping; 
} else { 
    tilemap.wrapS = tilemap.wrapT = THREE.ClampToEdgeWrapping; 
} 

//Setup Tileset 
tileset.wrapS = tileset.wrapT = THREE.ClampToEdgeWrapping; 
tileset.flipY = false; 
if(this.filtered) { 
    tileset.magFilter = THREE.LinearFilter; 
    tileset.minFilter = THREE.LinearMipMapLinearFilter; 
} else { 
    tileset.magFilter = THREE.NearestFilter; 
    tileset.minFilter = THREE.NearestMipMapNearestFilter; 
} 

//setup shader uniforms 
this.offset = new THREE.Vector2(0, 0); 
this._uniforms = { 
    viewportSize: { type: 'v2', value: new THREE.Vector2(viewport.width/this.tileScale, viewport.height/this.tileScale) }, 
    inverseSpriteTextureSize: { type: 'v2', value: new THREE.Vector2(1/tileset.image.width, 1/tileset.image.height) }, 
    tileSize: { type: 'f', value: this.tileSize }, 
    inverseTileSize: { type: 'f', value: 1/this.tileSize }, 

    tiles: { type: 't', value: tilemap }, 
    sprites: { type: 't', value: tileset }, 

    viewOffset: { type: 'v2', value: this.offset }, 
    inverseTileTextureSize: { type: 'v2', value: new THREE.Vector2(1/tilemap.image.width, 1/tilemap.image.height) }, 
    repeatTiles: { type: 'i', value: this.repeat ? 1 : 0 } 
}; 

//create the shader material 
this._material = new THREE.ShaderMaterial({ 
    uniforms: this._uniforms, 
    vertexShader: tilemapVS, 
    fragmentShader: tilemapFS, 
    transparent: false 
}); 

this._plane = new THREE.PlaneGeometry(viewport.width, viewport.height, this.tileSize, this.tileSize); 

this._mesh = new THREE.Mesh(this._plane, this._material); 

수정 맵 메이커 부 :

MapMaker.prototype.processTile = function(x, y) { 
    //rotate upside down, and draw 
    this.tileCtx.save(); 
    this.tileCtx.translate(0, this.tileSize); 
    this.tileCtx.scale(1, -1); 
    this.tileCtx.drawImage(this.srcImage, 
     x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize, 
     0, 0, this.tileSize, this.tileSize); 

    var sprite = this.cacheSprite(); 

    this.tileCtx.restore(); 

    this.mapCtx.fillStyle="rgb(" + sprite.x + "," + sprite.y + ", 0)"; 
    this.mapCtx.fillRect(x,y,1,1); 

    /* Why was this thing drawing 2 times? 
    this.tileCtx.drawImage(this.srcImage, 
     x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize, 
     0, 0, this.tileSize, this.tileSize);*/ 
}; 

누구나 다른 답이 있으면

, 게시를 부끄러워하지 마십시오.