আমি কীভাবে পুরো পিক্সেল বিরতিতে ক্যামেরাটি স্থানান্তর করব?


13

মূলত আমি ক্যামেরাকে সাবপিক্সেলগুলিতে যেতে বাধা দিতে চাই, কারণ আমি মনে করি যে এটি স্প্রাইটসকে দৃশ্যমানভাবে তাদের মাত্রাগুলি পরিবর্তনের দিকে পরিচালিত করে যদি কিছুটা সামান্য থাকে। (এর জন্য আরও ভাল শব্দ আছে কি?) নোট করুন যে এটি একটি পিক্সেল-আর্ট গেম যেখানে আমি খাস্তা পিক্সেলিটেড গ্রাফিক্স পেতে চাই। সমস্যাটি দেখায় এমন একটি জিআইএফ এখানে:

এখানে চিত্র বর্ণনা লিখুন

এখন আমি যা চেষ্টা করেছি তা হ'ল: ক্যামেরাটি সরান, বর্তমান অবস্থানটি প্রজেক্ট করুন (সুতরাং এটি স্ক্রিনের স্থানাঙ্কী হয়) এবং তারপরে বৃত্তাকার বা কাস্টে কাস্ট করুন। এরপরে এটি আবার বিশ্বের স্থানাঙ্কে রূপান্তরিত করে এবং এটিকে নতুন ক্যামেরার অবস্থান হিসাবে ব্যবহার করুন। আমি যতদূর জানি, এর ক্যামেরাটি প্রকৃত স্ক্রিন স্থানাঙ্কে লক করা উচিত, এর ভগ্নাংশ নয়।

কিছু কারণে, তবে, yনতুন অবস্থানের মানটি কেবল বিস্ফোরিত হয়। কয়েক সেকেন্ডের মধ্যে এটির মতো বেড়ে যায় 334756315000

এখানে লিবিজিডিএক্স উইকিতে কোডের উপর ভিত্তি করে একটি এসএসসিসিই (বা একটি এমসিভিই) রয়েছে :

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.badlogic.gdx.utils.viewport.Viewport;


public class PixelMoveCameraTest implements ApplicationListener {

    static final int WORLD_WIDTH = 100;
    static final int WORLD_HEIGHT = 100;

    private OrthographicCamera cam;
    private SpriteBatch batch;

    private Sprite mapSprite;
    private float rotationSpeed;

    private Viewport viewport;
    private Sprite playerSprite;
    private Vector3 newCamPosition;

    @Override
    public void create() {
        rotationSpeed = 0.5f;

        playerSprite = new Sprite(new Texture("/path/to/dungeon_guy.png"));
        playerSprite.setSize(1f, 1f);

        mapSprite = new Sprite(new Texture("/path/to/sc_map.jpg"));
        mapSprite.setPosition(0, 0);
        mapSprite.setSize(WORLD_WIDTH, WORLD_HEIGHT);

        float w = Gdx.graphics.getWidth();
        float h = Gdx.graphics.getHeight();

        // Constructs a new OrthographicCamera, using the given viewport width and height
        // Height is multiplied by aspect ratio.
        cam = new OrthographicCamera();

        cam.position.set(0, 0, 0);
        cam.update();
        newCamPosition = cam.position.cpy();

        viewport = new ExtendViewport(32, 20, cam);
        batch = new SpriteBatch();
    }


    @Override
    public void render() {
        handleInput();
        cam.update();
        batch.setProjectionMatrix(cam.combined);

        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        batch.begin();
        mapSprite.draw(batch);
        playerSprite.draw(batch);
        batch.end();
    }

    private static float MOVEMENT_SPEED = 0.2f;

    private void handleInput() {
        if (Gdx.input.isKeyPressed(Input.Keys.A)) {
            cam.zoom += 0.02;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.Q)) {
            cam.zoom -= 0.02;
        }
        if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
            newCamPosition.add(-MOVEMENT_SPEED, 0, 0);
        }
        if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
            newCamPosition.add(MOVEMENT_SPEED, 0, 0);
        }
        if (Gdx.input.isKeyPressed(Input.Keys.DOWN)) {
            newCamPosition.add(0, -MOVEMENT_SPEED, 0);
        }
        if (Gdx.input.isKeyPressed(Input.Keys.UP)) {
            newCamPosition.add(0, MOVEMENT_SPEED, 0);
        }
        if (Gdx.input.isKeyPressed(Input.Keys.W)) {
            cam.rotate(-rotationSpeed, 0, 0, 1);
        }
        if (Gdx.input.isKeyPressed(Input.Keys.E)) {
            cam.rotate(rotationSpeed, 0, 0, 1);
        }

        cam.zoom = MathUtils.clamp(cam.zoom, 0.1f, 100 / cam.viewportWidth);

        float effectiveViewportWidth = cam.viewportWidth * cam.zoom;
        float effectiveViewportHeight = cam.viewportHeight * cam.zoom;

        cam.position.lerp(newCamPosition, 0.02f);
        cam.position.x = MathUtils.clamp(cam.position.x,
                effectiveViewportWidth / 2f, 100 - effectiveViewportWidth / 2f);
        cam.position.y = MathUtils.clamp(cam.position.y,
                effectiveViewportHeight / 2f, 100 - effectiveViewportHeight / 2f);


        // if this is false, the "bug" (y increasing a lot) doesn't appear
        if (true) {
            Vector3 v = viewport.project(cam.position.cpy());
            System.out.println(v);
            v = viewport.unproject(new Vector3((int) v.x, (int) v.y, v.z));
            cam.position.set(v);
        }
        playerSprite.setPosition(newCamPosition.x, newCamPosition.y);
    }

    @Override
    public void resize(int width, int height) {
        viewport.update(width, height);
    }

    @Override
    public void resume() {
    }

    @Override
    public void dispose() {
        mapSprite.getTexture().dispose();
        batch.dispose();
    }

    @Override
    public void pause() {
    }

    public static void main(String[] args) {
        new Lwjgl3Application(new PixelMoveCameraTest(), new Lwjgl3ApplicationConfiguration());
    }
}

এবং এখানে এবংsc_map.jpgdungeon_guy.png

আমি এই সমস্যাটি সমাধানের সহজ ও / বা আরও ভাল উপায় সম্পর্কে জানতে আগ্রহী।


"এর জন্য আরও ভাল শব্দ আছে কি?" Aliasing? সেক্ষেত্রে মাল্টিসম্পল অ্যান্টি-এলিয়জিং (এমএসএএ) বিকল্প বিকল্প হতে পারে?
ইউসুফ আমার

@ পারকনাইট দুঃখিত, আমি উল্লেখ করতে ভুলে গেছি যে আমি একটি পিক্সেলিটেড গেমের উপর কাজ করছি, যেখানে আমার খাস্তা গ্রাফিক্সের প্রয়োজন যাতে অ্যান্টি-এলিয়াসিং কাজ না করে (এএফআইএইসি)। আমি সেই প্রশ্নটি প্রশ্নের সাথে যুক্ত করেছি। ধন্যবাদ যদিও.
জোসচুয়া

উচ্চতর রেজোলিউশনে কাজ করার কোনও কারণ আছে, অন্যথায় 1 পিক্সেল রেজোলিউশনে কাজ করে চূড়ান্ত ফলাফল উপস্থাপনের জন্য?
ফেলসির

@ ফিলসির হ্যাঁ, আমি স্ক্রিন পিক্সেলগুলিতে চলেছি, যাতে খেলাটি যতটা সম্ভব সাবলীল মনে হয়। একটি সম্পূর্ণ টেক্সচার পিক্সেল সরানো খুব চিটচিটে দেখায়।
জোসচুয়া

উত্তর:


22

আপনার সমস্যা ক্যামেরাকে পুরো পিক্সেল ইনক্রিমেন্টে সরিয়ে নিচ্ছে না। এটি আপনার টেক্সেল থেকে পিক্সেল অনুপাতটি সামান্য অ-পূর্ণসংখ্যারআমি স্ট্যাকএক্সচেঞ্জ এ উত্তর দিয়েছি এমন একই প্রশ্ন থেকে কিছু উদাহরণ ধার করব

এখানে মারিওয়ের দুটি অনুলিপি - উভয়ই একই হারে পর্দা জুড়ে চলেছে (হয় স্প্রেটস দ্বারা ডানদিকে চলেছে পৃথিবীতে, বা ক্যামেরাটি বাম দিকে চলেছে - এটি সমাপ্ত সমাপ্ত হয়), তবে কেবল শীর্ষস্থানীয়ই এই লড়াকু শিল্পকর্মগুলি দেখায় এবং নীচে এক না:

দুটি মারিও স্প্রাইটস

কারণটি হ'ল আমি শীর্ষ মারিওকে ১.০১ এক্স এর 1 ফ্যাক্টর দ্বারা সামান্য পরিমাণে বাড়িয়েছি - অতিরিক্ত ক্ষুদ্র ভগ্নাংশের অর্থ তিনি আর পর্দার পিক্সেল গ্রিডের সাথে লাইন রাখেন না।

একটি ছোট ট্রান্সলেশনাল মিস্যালাইনমেন্ট কোনও সমস্যা নয় - "নিকটতম" টেক্সচার ফিল্টারিং আমাদের বিশেষ কিছু না করে যাইহোক নিকটবর্তী টেক্সলে স্ন্যাপ করবে।

তবে একটি স্কেল মেলেনি অর্থ হ'ল এই ছোটাছুটি সবসময় একই দিকে থাকে না। এক স্থানে নিকটতম টেক্সেলটি সন্ধানকারী একটি পিক্সেল একটি সামান্য ডানদিকে তুলবে, অন্য পিক্সেলটি কিছুটা বাম দিকে তুলবে - এবং এখন টেক্সটসের একটি কলামটি হয় বাদ দেওয়া হয়েছে বা মাঝখানে নকল করা হয়েছে, একটি লম্বা বা ঝিলিমিলি তৈরি করে যা স্ক্রিন জুড়ে ভ্রমণ করার সাথে সাথে স্প্রিটের উপরে চলে যায়।

এখানে একটি নিবিড় চেহারা। আমি একটি আড়াআড়ি মাশরুম স্প্রিট সহজেই চলন্ত অ্যানিমেটেড করেছি, যদিও আমরা এটি সীমাহীন সাব-পিক্সেল রেজোলিউশন সহ রেন্ডার করতে পারি। তারপরে আমি নিকটতম-প্রতিবেশী স্যাম্পলিং ব্যবহার করে একটি পিক্সেল গ্রিড ওভারলেড করেছি। স্যাম্পলিং পয়েন্ট (কেন্দ্রের বিন্দু) এর নীচে স্প্রাইটের অংশটির সাথে মেলে পুরো পিক্সেল রঙ পরিবর্তন করে।

1: 1 স্কেলিং

সঠিকভাবে স্কেল করা স্প্রাইট কোনও রিপল ছাড়াই চলমান

যদিও স্প্রাইটটি উপ-পিক্সেল স্থানাঙ্কগুলিতে মসৃণভাবে চলে আসে, তবুও এর রেন্ডার করা চিত্রটি প্রতিবার যখন একটি পূর্ণ পিক্সেল ভ্রমণ করে তখন সঠিকভাবে স্ন্যাপ করে। এই কাজটি করার জন্য আমাদের বিশেষ কিছু করার দরকার নেই।

1: 1.0625 স্কেলিং

16x16 স্প্রিটটি 17x17 অন স্ক্রিনে রেন্ডার করেছে, শৈলীগুলি প্রদর্শন করে

এই উদাহরণে, 16x16 টেক্সেল মাশরুম স্প্রিটটি 17x17 স্ক্রিন পিক্সেল পর্যন্ত মাপানো হয়েছে, এবং তাই চিত্রের এক অংশ থেকে অন্য অংশে স্ন্যাপিং পৃথকভাবে ঘটে, রিপল বা তরঙ্গ তৈরি করে যা প্রসারিত হওয়ার সাথে সাথে স্কোয়াশ করে।

সুতরাং, কৌশলটি হল আপনার ক্যামেরার আকার / দর্শন ক্ষেত্রটি সামঞ্জস্য করা যাতে আপনার সম্পদের উত্স টেক্সটগুলি একটি পূর্ণসংখ্যার স্ক্রিন পিক্সেলের সাথে মানচিত্র করে। এটি 1: 1 হতে হবে না - কোনও সম্পূর্ণ সংখ্যা দুর্দান্ত কাজ করে:

1: 3 স্কেলিং

ট্রিপল স্কেলে জুম বাড়ান

আপনার টার্গেট রেজোলিউশনের উপর নির্ভর করে আপনার এটি কিছুটা আলাদাভাবে করা দরকার - উইন্ডোটি ফিট করার জন্য কেবল স্কেলিং করা প্রায়শই সবসময় একটি ভগ্নাংশের স্কেল তৈরি করে। নির্দিষ্ট রেজোলিউশনের জন্য পর্দার প্রান্তে কিছু পরিমাণ প্যাডিংয়ের প্রয়োজন হতে পারে।


1
সবার আগে, অনেক অনেক ধন্যবাদ! এটি দুর্দান্ত দর্শন। একা এটির জন্য উত্সাহ দিন। দুঃখজনক হলেও, প্রদত্ত কোডটিতে আমি অ-পূর্ণসংখ্যার কিছু খুঁজে পাচ্ছি না। এর আকার mapSprite100x100, দ্য playerSprite1x1 আকারে সেট করা হয়েছে এবং ভিউপোর্টটি 32x20 আকারে সেট করা আছে। এমনকি 16 এর গুণকে সমস্ত কিছু পরিবর্তন করা সমস্যার সমাধান বলে মনে হচ্ছে না। কোন ধারনা?
জোসছুয়া

2
সর্বত্র পূর্ণসংখ্যা পাওয়া এবং এখনও একটি অ-পূর্ণসংখ্যার অনুপাত পাওয়া সম্পূর্ণভাবে সম্ভব। 17 টি স্ক্রিন পিক্সেলে প্রদর্শিত 16 টেক্সেল স্প্রাইটের উদাহরণটি ধরুন। উভয় মানই পূর্ণসংখ্যা, তবে তাদের অনুপাত হয় না। আমি লিবিজিডিএক্স সম্পর্কে খুব বেশি জানি না, তবে Unক্যে আমি বিশ্ব ইউনিট অনুসারে কয়টি টেক্সেল প্রদর্শন করছি তা লক্ষ্য করতাম (উদাহরণস্বরূপ, স্প্রাইটের বিশ্ব আকারের দ্বারা বিভক্ত স্প্রাইটের রেজোলিউশন), আমি যে কত বিশ্ব ইউনিট প্রদর্শন করছি তা আমার উইন্ডো (ক্যামেরার আকার ব্যবহার করে) এবং আমার উইন্ডোতে কত স্ক্রিন পিক্সেল রয়েছে। এই 3 টি মানকে শৃঙ্খলাবদ্ধ করে, আমরা প্রদত্ত উইন্ডো আকারের জন্য টেক্সেল থেকে পিক্সেল অনুপাত কাজ করতে পারি।
ডিএমগ্রিগরি

"এবং ভিউপোর্টটি 32x20" আকারে সেট করা আছে - যদি না আপনার উইন্ডোর "ক্লায়েন্টের আকার" (উপস্থাপনযোগ্য অঞ্চল) এর পূর্ণসংখ্যার একাধিক হয়, যা আমি অনুমান করি এটি না, আপনার ভিউপোর্টের 1 ইউনিট কিছু অ-পূর্ণসংখ্যার হবে পিক্সেল সংখ্যা।
মোলিংমোনকি

ধন্যবাদ। আমি আবার চেষ্টা করেছি। window size1000x1000 (পিক্সেল), WORLD_WIDTHx WORLD_HEIGHT100x100, FillViewport10x10, playerSprite1x1। দুঃখের বিষয়, সমস্যাটি এখনও রয়েছে।
জোসচুয়া

এই বিশদটি একটি মন্তব্য থ্রেডে বাছাই করার চেষ্টা করতে কিছুটা হতে চলেছে। আপনি কি কোনও গেম ডেভেলপমেন্ট চ্যাট রুম শুরু করতে চান , বা টুইটারে আমাকে সরাসরি বার্তা দিতে চান @ ডি_এম_ গ্রেগরি?
ডিএমগ্রিগরি

1

এখানে একটি ছোট চেকলিস্ট:

  1. "লক্ষ্য ক্যামেরা অবস্থান" সহ "বর্তমান ক্যামেরা অবস্থান" পৃথক করুন। (যেমন এনডেনরোদেভ উল্লেখ করেছেন) উদাহরণস্বরূপ যদি "বর্তমান ক্যামেরার অবস্থান" 1.1 হয় - "লক্ষ্য ক্যামেরার অবস্থান" তৈরি করুন 1.0

এবং কেবলমাত্র বর্তমান ক্যামেরার অবস্থান পরিবর্তন করুন যদি ক্যামেরাটি সরে যায়।
লক্ষ্য ক্যামেরার অবস্থানটি ট্রান্সফর্ম.পজিশনের পরিবর্তে অন্য কিছু হলে - সেট করুন ট্রান্সফর্ম.পজিশন (আপনার ক্যামেরার) "লক্ষ্য ক্যামেরার অবস্থান" এ সেট করুন।

aim_camera_position = Mathf.Round(current_camera_position)

if (transform.position != aim_camera_position)
{
  transform.position = aim_camera_position;
}

এটা আপনার সমস্যা সমাধান করবে. যদি না: আমাকে বলুন। তবে আপনারও এই জিনিসগুলি করা বিবেচনা করা উচিত:

  1. "ক্যামেরা প্রজেকশন "টিকে" অর্টোগ্রাফিক "এ সেট করুন (আপনার অস্বাভাবিকভাবে ওয়াই-সমস্যায় বাড়ার জন্য) (এখন থেকে আপনার কেবল" দেখার ক্ষেত্র "দিয়ে জুম করা উচিত)

  2. 90 ° - পদক্ষেপে ক্যামেরা ঘূর্ণন সেট করুন (0 ° বা 90 ° বা 180 °)

  3. আপনার উচিত কিনা তা যদি জানেন না তবে মিপম্যাপগুলি তৈরি করবেন না।

  4. আপনার স্প্রাইটের জন্য পর্যাপ্ত আকার ব্যবহার করুন এবং বিলিনিয়ার বা ট্রিলিনিয়ার ফিল্টার ব্যবহার করবেন না

  5. 5।

যদি 1 ইউনিট পিক্সেল-ইউনিট না হয় তবে এটির স্ক্রিন-রেজোলিউশন নির্ভর। আপনার কি দেখার ক্ষেত্রের অ্যাক্সেস আছে? আপনার দেখার ক্ষেত্রের উপর নির্ভর করে: 1 ইউনিট কত রেজোলিউশন তা সন্ধান করুন।

float tan2Fov = tan(radians( Field of view / 2)); 
float xScrWidth = _CamNear*tan2Fov*_CamAspect * 2; 
float xScrHeight = _CamNear*tan2Fov * 2; 
float onePixel(width) = xWidth / screenResolutionX 
float onePixel(height) = yHeight / screenResolutionY 

। এবং এখন যদি ওয়ানপিক্সেল (প্রস্থ) এবং ওয়ানপিক্সেল (উচ্চতা) 1.0000f না হয় তবে কেবলমাত্র আপনার ক্যামেরার সাহায্যে সেই ইউনিটগুলিতে বাম এবং ডানে চলে যান।


হে! আপনার উত্তরের জন্য ধন্যবাদ. 1) আমি ইতিমধ্যে প্রকৃত ক্যামেরা অবস্থান এবং বৃত্তাকারটি পৃথকভাবে সঞ্চয় করি। 2) আমি LibGDX এর ব্যবহার OrthographicCameraকরি যাতে আশা করি এটির মতো কাজ করা উচিত। (আপনি Unক্য ব্যবহার করছেন, তাই না?) 3-5) আমি ইতিমধ্যে আমার গেমগুলিতে এটি করি।
জোছুয়া 9

ঠিক আছে - তবে আপনাকে 1 ইউনিট 1 পিক্সেল কত ইউনিট তা খুঁজে বের করতে হবে। এটি স্ক্রিন রেজোলিউশন নির্ভর হতে পারে। আমি "5" সম্পাদনা করেছি আমার উত্তর পোস্টে। এটা চেষ্টা কর.
ওসি_রাইজডাব্লু

0

আমি libgdx এর সাথে পরিচিত নই তবে অন্য কোথাও এরকম অভিজ্ঞতা রয়েছে। আমি মনে করি যে সমস্যাটি লেটার এবং সম্ভাব্য ত্রুটিটি ভাসমান পয়েন্টের মানগুলিতে ব্যবহার করে যাচ্ছি in আমি মনে করি আপনার সমস্যার সম্ভাব্য সমাধান হ'ল নিজের ক্যামেরা লোকেশন অবজেক্ট তৈরি করা। আপনার চলাচলের কোডের জন্য এই অবজেক্টটি ব্যবহার করুন এবং সে অনুযায়ী এটি আপডেট করুন এবং তারপরে আপনার অবস্থানের অবজেক্টের নিকটতম আবশ্যক (পূর্ণসংখ্যা?) মানটিতে ক্যামেরার অবস্থানটি সেট করুন।


প্রথমত, আপনার অন্তর্দৃষ্টি জন্য ধন্যবাদ। ভাসমান পয়েন্ট ত্রুটিগুলির সাথে এটিতে আসলে কিছু করার থাকতে পারে। তবে সমস্যাটি ( yঅস্বাভাবিকভাবে বাড়ার) আমি ব্যবহার করার আগে উপস্থিত ছিল lerp। আমি আসলে এটি গতকালই যুক্ত করেছি যাতে লোকেরা অন্য সমস্যাটিও দেখতে পারে, যেখানে ক্যামেরাটি এগিয়ে আসার সময় স্প্রাইটের আকার স্থির থাকে না।
জোসচুয়া
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.